gogcli-mcp-drive 4.2.5 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +869 -139
- package/manifest.json +9 -2
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/tools/drive-extra.ts +39 -36
- package/tests/tools/drive-extra.test.ts +84 -46
- package/vitest.config.ts +5 -0
package/dist/index.js
CHANGED
|
@@ -37,6 +37,33 @@ var storage2 = new AsyncLocalStorage2();
|
|
|
37
37
|
function withCallerCapabilities(capabilities, fn) {
|
|
38
38
|
return capabilities ? storage2.run(capabilities, fn) : fn();
|
|
39
39
|
}
|
|
40
|
+
function currentCallerCapabilities() {
|
|
41
|
+
return storage2.getStore();
|
|
42
|
+
}
|
|
43
|
+
var ENVELOPE_CAPABILITIES_KEY = "io.modelcontextprotocol/clientCapabilities";
|
|
44
|
+
var ELICITATION_MODES = ["form", "url"];
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
function callerCapabilities(ctx) {
|
|
49
|
+
const envelope = isRecord(ctx) && isRecord(ctx.mcpReq) ? ctx.mcpReq.envelope : void 0;
|
|
50
|
+
if (isRecord(envelope)) {
|
|
51
|
+
const declared = envelope[ENVELOPE_CAPABILITIES_KEY];
|
|
52
|
+
if (isRecord(declared))
|
|
53
|
+
return declared;
|
|
54
|
+
}
|
|
55
|
+
return currentCallerCapabilities();
|
|
56
|
+
}
|
|
57
|
+
function callerAcceptsFormElicitation(ctx) {
|
|
58
|
+
const capabilities = callerCapabilities(ctx);
|
|
59
|
+
if (!capabilities)
|
|
60
|
+
return void 0;
|
|
61
|
+
const elicitation = capabilities.elicitation;
|
|
62
|
+
if (!isRecord(elicitation))
|
|
63
|
+
return false;
|
|
64
|
+
const namedModes = ELICITATION_MODES.filter((mode) => mode in elicitation);
|
|
65
|
+
return namedModes.length === 0 || namedModes.includes("form");
|
|
66
|
+
}
|
|
40
67
|
|
|
41
68
|
// ../../node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
|
|
42
69
|
var __create = Object.create;
|
|
@@ -2092,8 +2119,8 @@ function emoji() {
|
|
|
2092
2119
|
}
|
|
2093
2120
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
2094
2121
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
2095
|
-
var mac = (
|
|
2096
|
-
const escapedDelim = escapeRegex(
|
|
2122
|
+
var mac = (delimiter3) => {
|
|
2123
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
2097
2124
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
2098
2125
|
};
|
|
2099
2126
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -5121,7 +5148,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5121
5148
|
var NONE = 0;
|
|
5122
5149
|
var ASSUMED = 1;
|
|
5123
5150
|
var PROVEN = 2;
|
|
5124
|
-
function isRecursive(inst, stack,
|
|
5151
|
+
function isRecursive(inst, stack, resolve4) {
|
|
5125
5152
|
const cached2 = recursive.get(inst);
|
|
5126
5153
|
if (cached2 !== void 0)
|
|
5127
5154
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5131,7 +5158,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5131
5158
|
let result = NONE;
|
|
5132
5159
|
const check2 = (child) => {
|
|
5133
5160
|
if (result !== PROVEN && child?._zod) {
|
|
5134
|
-
const answer = isRecursive(child, stack,
|
|
5161
|
+
const answer = isRecursive(child, stack, resolve4);
|
|
5135
5162
|
if (answer > result)
|
|
5136
5163
|
result = answer;
|
|
5137
5164
|
}
|
|
@@ -5142,7 +5169,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5142
5169
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5143
5170
|
if (spread && !desc.enumerable)
|
|
5144
5171
|
continue;
|
|
5145
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5172
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve4) : NONE;
|
|
5146
5173
|
if (child > answer)
|
|
5147
5174
|
answer = child;
|
|
5148
5175
|
}
|
|
@@ -5206,7 +5233,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5206
5233
|
break;
|
|
5207
5234
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5208
5235
|
case "lazy": {
|
|
5209
|
-
const inner = def._cachedInner ?? (
|
|
5236
|
+
const inner = def._cachedInner ?? (resolve4 ? inst._zod.innerType : void 0);
|
|
5210
5237
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5211
5238
|
break;
|
|
5212
5239
|
}
|
|
@@ -24101,19 +24128,50 @@ var inputRequired = Object.assign(buildInputRequired, {
|
|
|
24101
24128
|
return { method: "roots/list" };
|
|
24102
24129
|
}
|
|
24103
24130
|
});
|
|
24131
|
+
function acceptedContent(responses, key, schema) {
|
|
24132
|
+
const view = inputResponse(responses, key);
|
|
24133
|
+
if (view.kind !== "elicit" || view.action !== "accept" || view.content === void 0) return void 0;
|
|
24134
|
+
if (schema === void 0) return view.content;
|
|
24135
|
+
const outcome = schema["~standard"].validate(view.content);
|
|
24136
|
+
if (outcome instanceof Promise) throw new TypeError("acceptedContent(responses, key, schema) requires a synchronously-validating schema");
|
|
24137
|
+
return outcome.issues === void 0 ? outcome.value : void 0;
|
|
24138
|
+
}
|
|
24139
|
+
function inputResponse(responses, key) {
|
|
24140
|
+
if (responses === void 0 || typeof responses !== "object" || responses === null) return { kind: "missing" };
|
|
24141
|
+
const entry = responses[key];
|
|
24142
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return { kind: "missing" };
|
|
24143
|
+
const candidate = entry;
|
|
24144
|
+
if (candidate["action"] === "accept" || candidate["action"] === "decline" || candidate["action"] === "cancel") {
|
|
24145
|
+
const content = candidate["content"];
|
|
24146
|
+
return {
|
|
24147
|
+
kind: "elicit",
|
|
24148
|
+
action: candidate["action"],
|
|
24149
|
+
...content !== null && typeof content === "object" && !Array.isArray(content) && { content }
|
|
24150
|
+
};
|
|
24151
|
+
}
|
|
24152
|
+
if (Array.isArray(candidate["roots"])) return {
|
|
24153
|
+
kind: "roots",
|
|
24154
|
+
roots: candidate["roots"]
|
|
24155
|
+
};
|
|
24156
|
+
if (typeof candidate["role"] === "string" && candidate["content"] !== void 0) return {
|
|
24157
|
+
kind: "sampling",
|
|
24158
|
+
result: candidate
|
|
24159
|
+
};
|
|
24160
|
+
return { kind: "missing" };
|
|
24161
|
+
}
|
|
24104
24162
|
var REQUEST_STATE_ONLY_LEG_PACING_MS = 250;
|
|
24105
24163
|
function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
24106
24164
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
24107
24165
|
}
|
|
24108
24166
|
function sleep(ms, signal) {
|
|
24109
|
-
return new Promise((
|
|
24167
|
+
return new Promise((resolve4, reject) => {
|
|
24110
24168
|
if (signal?.aborted) {
|
|
24111
24169
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
24112
24170
|
return;
|
|
24113
24171
|
}
|
|
24114
24172
|
const timer = setTimeout(() => {
|
|
24115
24173
|
signal?.removeEventListener("abort", onAbort);
|
|
24116
|
-
|
|
24174
|
+
resolve4();
|
|
24117
24175
|
}, ms);
|
|
24118
24176
|
const onAbort = () => {
|
|
24119
24177
|
clearTimeout(timer);
|
|
@@ -24907,7 +24965,7 @@ var Protocol = class {
|
|
|
24907
24965
|
const flowStartedAt = Date.now();
|
|
24908
24966
|
let onAbort;
|
|
24909
24967
|
let cleanupMessageId;
|
|
24910
|
-
return new Promise((
|
|
24968
|
+
return new Promise((resolve4, reject) => {
|
|
24911
24969
|
const earlyReject = (error62) => {
|
|
24912
24970
|
reject(error62);
|
|
24913
24971
|
};
|
|
@@ -24975,7 +25033,7 @@ var Protocol = class {
|
|
|
24975
25033
|
}
|
|
24976
25034
|
if (decoded.kind === "invalid") return reject(decoded.error);
|
|
24977
25035
|
if (decoded.kind === "input_required") {
|
|
24978
|
-
if (options?.allowInputRequired === true) return
|
|
25036
|
+
if (options?.allowInputRequired === true) return resolve4(manualInputRequiredValue(decoded));
|
|
24979
25037
|
const flow = {
|
|
24980
25038
|
codec: codec2,
|
|
24981
25039
|
request,
|
|
@@ -24987,11 +25045,11 @@ var Protocol = class {
|
|
|
24987
25045
|
params
|
|
24988
25046
|
}, resultSchema, legOptions)
|
|
24989
25047
|
};
|
|
24990
|
-
return
|
|
25048
|
+
return resolve4(this._resolveNonCompleteResult(decoded, flow));
|
|
24991
25049
|
}
|
|
24992
25050
|
const result = decoded.result;
|
|
24993
25051
|
validateStandardSchema(resultSchema, result).then((parseResult) => {
|
|
24994
|
-
if (parseResult.success)
|
|
25052
|
+
if (parseResult.success) resolve4(parseResult.data);
|
|
24995
25053
|
else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
24996
25054
|
}, reject);
|
|
24997
25055
|
});
|
|
@@ -27903,7 +27961,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27903
27961
|
ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
|
|
27904
27962
|
const schOrFunc = root.refs[ref];
|
|
27905
27963
|
if (schOrFunc) return schOrFunc;
|
|
27906
|
-
let _sch =
|
|
27964
|
+
let _sch = resolve4.call(this, root, ref);
|
|
27907
27965
|
if (_sch === void 0) {
|
|
27908
27966
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
27909
27967
|
const { schemaId } = this.opts;
|
|
@@ -27929,7 +27987,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27929
27987
|
function sameSchemaEnv(s1, s2) {
|
|
27930
27988
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
27931
27989
|
}
|
|
27932
|
-
function
|
|
27990
|
+
function resolve4(root, ref) {
|
|
27933
27991
|
let sch;
|
|
27934
27992
|
while (typeof (sch = this.refs[ref]) == "string") ref = sch;
|
|
27935
27993
|
return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
|
@@ -28379,47 +28437,47 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28379
28437
|
else if (typeof uri === "object") uri = parse3(serialize(uri, options), options);
|
|
28380
28438
|
return uri;
|
|
28381
28439
|
}
|
|
28382
|
-
function
|
|
28440
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
28383
28441
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
28384
28442
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
28385
28443
|
schemelessOptions.skipEscape = true;
|
|
28386
28444
|
return serialize(resolved, schemelessOptions);
|
|
28387
28445
|
}
|
|
28388
|
-
function resolveComponent(base,
|
|
28446
|
+
function resolveComponent(base, relative3, options, skipNormalization) {
|
|
28389
28447
|
const target = {};
|
|
28390
28448
|
if (!skipNormalization) {
|
|
28391
28449
|
base = parse3(serialize(base, options), options);
|
|
28392
|
-
|
|
28450
|
+
relative3 = parse3(serialize(relative3, options), options);
|
|
28393
28451
|
}
|
|
28394
28452
|
options = options || {};
|
|
28395
|
-
if (!options.tolerant &&
|
|
28396
|
-
target.scheme =
|
|
28397
|
-
target.userinfo =
|
|
28398
|
-
target.host =
|
|
28399
|
-
target.port =
|
|
28400
|
-
target.path = removeDotSegments(
|
|
28401
|
-
target.query =
|
|
28453
|
+
if (!options.tolerant && relative3.scheme) {
|
|
28454
|
+
target.scheme = relative3.scheme;
|
|
28455
|
+
target.userinfo = relative3.userinfo;
|
|
28456
|
+
target.host = relative3.host;
|
|
28457
|
+
target.port = relative3.port;
|
|
28458
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
28459
|
+
target.query = relative3.query;
|
|
28402
28460
|
} else {
|
|
28403
|
-
if (
|
|
28404
|
-
target.userinfo =
|
|
28405
|
-
target.host =
|
|
28406
|
-
target.port =
|
|
28407
|
-
target.path = removeDotSegments(
|
|
28408
|
-
target.query =
|
|
28461
|
+
if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
|
|
28462
|
+
target.userinfo = relative3.userinfo;
|
|
28463
|
+
target.host = relative3.host;
|
|
28464
|
+
target.port = relative3.port;
|
|
28465
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
28466
|
+
target.query = relative3.query;
|
|
28409
28467
|
} else {
|
|
28410
|
-
if (!
|
|
28468
|
+
if (!relative3.path) {
|
|
28411
28469
|
target.path = base.path;
|
|
28412
|
-
if (
|
|
28470
|
+
if (relative3.query !== void 0) target.query = relative3.query;
|
|
28413
28471
|
else target.query = base.query;
|
|
28414
28472
|
} else {
|
|
28415
|
-
if (
|
|
28473
|
+
if (relative3.path[0] === "/") target.path = removeDotSegments(relative3.path);
|
|
28416
28474
|
else {
|
|
28417
|
-
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" +
|
|
28418
|
-
else if (!base.path) target.path =
|
|
28419
|
-
else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
28475
|
+
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" + relative3.path;
|
|
28476
|
+
else if (!base.path) target.path = relative3.path;
|
|
28477
|
+
else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
|
|
28420
28478
|
target.path = removeDotSegments(target.path);
|
|
28421
28479
|
}
|
|
28422
|
-
target.query =
|
|
28480
|
+
target.query = relative3.query;
|
|
28423
28481
|
}
|
|
28424
28482
|
target.userinfo = base.userinfo;
|
|
28425
28483
|
target.host = base.host;
|
|
@@ -28427,7 +28485,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28427
28485
|
}
|
|
28428
28486
|
target.scheme = base.scheme;
|
|
28429
28487
|
}
|
|
28430
|
-
target.fragment =
|
|
28488
|
+
target.fragment = relative3.fragment;
|
|
28431
28489
|
return target;
|
|
28432
28490
|
}
|
|
28433
28491
|
function equal(uriA, uriB, options) {
|
|
@@ -28553,7 +28611,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28553
28611
|
const fastUri = {
|
|
28554
28612
|
SCHEMES,
|
|
28555
28613
|
normalize,
|
|
28556
|
-
resolve,
|
|
28614
|
+
resolve: resolve4,
|
|
28557
28615
|
resolveComponent,
|
|
28558
28616
|
equal,
|
|
28559
28617
|
serialize,
|
|
@@ -29335,14 +29393,14 @@ var require_ucs2length = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
29335
29393
|
function ucs2length(str) {
|
|
29336
29394
|
const len = str.length;
|
|
29337
29395
|
let length = 0;
|
|
29338
|
-
let
|
|
29396
|
+
let pos2 = 0;
|
|
29339
29397
|
let value;
|
|
29340
|
-
while (
|
|
29398
|
+
while (pos2 < len) {
|
|
29341
29399
|
length++;
|
|
29342
|
-
value = str.charCodeAt(
|
|
29343
|
-
if (value >= 55296 && value <= 56319 &&
|
|
29344
|
-
value = str.charCodeAt(
|
|
29345
|
-
if ((value & 64512) === 56320)
|
|
29400
|
+
value = str.charCodeAt(pos2++);
|
|
29401
|
+
if (value >= 55296 && value <= 56319 && pos2 < len) {
|
|
29402
|
+
value = str.charCodeAt(pos2);
|
|
29403
|
+
if ((value & 64512) === 56320) pos2++;
|
|
29346
29404
|
}
|
|
29347
29405
|
}
|
|
29348
29406
|
return length;
|
|
@@ -33926,7 +33984,7 @@ var StdioServerTransport = class {
|
|
|
33926
33984
|
}
|
|
33927
33985
|
send(message) {
|
|
33928
33986
|
if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
33929
|
-
return new Promise((
|
|
33987
|
+
return new Promise((resolve4, reject) => {
|
|
33930
33988
|
const json2 = serializeMessage(message);
|
|
33931
33989
|
let settled = false;
|
|
33932
33990
|
const onError = (error62) => {
|
|
@@ -33941,14 +33999,14 @@ var StdioServerTransport = class {
|
|
|
33941
33999
|
settled = true;
|
|
33942
34000
|
this._stdout.off("error", onError);
|
|
33943
34001
|
this._stdout.off("drain", onDrain);
|
|
33944
|
-
|
|
34002
|
+
resolve4();
|
|
33945
34003
|
};
|
|
33946
34004
|
this._stdout.once("error", onError);
|
|
33947
34005
|
if (this._stdout.write(json2)) {
|
|
33948
34006
|
if (settled) return;
|
|
33949
34007
|
settled = true;
|
|
33950
34008
|
this._stdout.off("error", onError);
|
|
33951
|
-
|
|
34009
|
+
resolve4();
|
|
33952
34010
|
} else if (!settled) this._stdout.once("drain", onDrain);
|
|
33953
34011
|
});
|
|
33954
34012
|
}
|
|
@@ -34002,14 +34060,14 @@ var StdioConnectionChannel = class {
|
|
|
34002
34060
|
*/
|
|
34003
34061
|
async whenRequestsAnswered(timeoutMs) {
|
|
34004
34062
|
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
34005
|
-
return await new Promise((
|
|
34063
|
+
return await new Promise((resolve4) => {
|
|
34006
34064
|
const waiter = () => {
|
|
34007
34065
|
clearTimeout(timer);
|
|
34008
|
-
|
|
34066
|
+
resolve4(true);
|
|
34009
34067
|
};
|
|
34010
34068
|
const timer = setTimeout(() => {
|
|
34011
34069
|
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
34012
|
-
|
|
34070
|
+
resolve4(false);
|
|
34013
34071
|
}, timeoutMs);
|
|
34014
34072
|
this._drainWaiters.push(waiter);
|
|
34015
34073
|
});
|
|
@@ -34148,14 +34206,14 @@ function serveStdio(factory, options = {}) {
|
|
|
34148
34206
|
return false;
|
|
34149
34207
|
};
|
|
34150
34208
|
const answerLegacyRejection = (request, reason, requestedVersion) => {
|
|
34151
|
-
const
|
|
34209
|
+
const rejection3 = modernOnlyStrictRejection({
|
|
34152
34210
|
kind: "legacy",
|
|
34153
34211
|
reason,
|
|
34154
34212
|
...requestedVersion !== void 0 && { requestedVersion }
|
|
34155
34213
|
}, SUPPORTED_MODERN_PROTOCOL_VERSIONS);
|
|
34156
|
-
if (
|
|
34157
|
-
reportError(/* @__PURE__ */ new Error(`Rejected 2025-era request on a modern-only stdio connection (${
|
|
34158
|
-
return writeErrorResponse(request.id,
|
|
34214
|
+
if (rejection3 === void 0) return Promise.resolve();
|
|
34215
|
+
reportError(/* @__PURE__ */ new Error(`Rejected 2025-era request on a modern-only stdio connection (${rejection3.cell}): ${rejection3.message}`));
|
|
34216
|
+
return writeErrorResponse(request.id, rejection3.code, rejection3.message, rejection3.data);
|
|
34159
34217
|
};
|
|
34160
34218
|
const onInstanceClosed = (channel) => {
|
|
34161
34219
|
if (closing || channel === discarding) return;
|
|
@@ -34379,13 +34437,28 @@ var API_KEY_RE = new RegExp([
|
|
|
34379
34437
|
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
34380
34438
|
// webhook signing secret (Stripe-style)
|
|
34381
34439
|
].map((p) => `\\b${p}`).join("|"), "g");
|
|
34382
|
-
var QUERY_SECRET_RE = /([?&](?:
|
|
34440
|
+
var QUERY_SECRET_RE = /([?&](?:(?:access|refresh|id|auth|session|csrf|xsrf)[_-]?token|client[_-]?secret|api[_-]?secret|api[_-]?key|password|passwd|signature|token|key|sig)=)[^&#\s"'<>`]+/gi;
|
|
34441
|
+
var OAUTH_CODE_RE = /([?&]code=)(?=[^&#\s"'<>`]{16,})[^&#\s"'<>`]+/gi;
|
|
34442
|
+
var FORM_PASSWORD_RE = /((?:^|[\s,;:"'(\[{])(?:password|passwd)=)[^&#\s"'<>`]+/gim;
|
|
34443
|
+
var HEADER_SECRET_RE = /(\b(?:x[-_][a-z0-9_-]*?(?:api[-_]?key|token|secret|auth)[a-z0-9_-]*|api[-_]?key)\s*:\s*)[^\s,;"'<>`]+/gi;
|
|
34383
34444
|
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
34384
|
-
var JSON_SECRET_KEYS =
|
|
34385
|
-
|
|
34386
|
-
|
|
34445
|
+
var JSON_SECRET_KEYS = [
|
|
34446
|
+
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf)[_-]?token",
|
|
34447
|
+
"client[_-]?secret",
|
|
34448
|
+
"api[_-]?secret",
|
|
34449
|
+
"(?:x[_-])?api[_-]?key",
|
|
34450
|
+
"private[_-]?key",
|
|
34451
|
+
"x[_-][a-z0-9_-]*?(?:api[_-]?key|token|secret|auth)[a-z0-9_-]*",
|
|
34452
|
+
"(?:proxy-)?authorization",
|
|
34453
|
+
"password",
|
|
34454
|
+
"passwd",
|
|
34455
|
+
"secret",
|
|
34456
|
+
"token"
|
|
34457
|
+
].join("|");
|
|
34458
|
+
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")(?:[^"\\\\]|\\\\.)*(")`, "gi");
|
|
34459
|
+
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')(?:[^'\\\\]|\\\\.)*(')`, "gi");
|
|
34387
34460
|
function redactSecrets(text) {
|
|
34388
|
-
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
34461
|
+
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(HEADER_SECRET_RE, "$1[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(OAUTH_CODE_RE, "$1[REDACTED]").replace(FORM_PASSWORD_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
34389
34462
|
}
|
|
34390
34463
|
|
|
34391
34464
|
// ../../node_modules/@chrischall/mcp-utils/dist/response/view.js
|
|
@@ -34464,6 +34537,11 @@ function walk(value, keep, drop) {
|
|
|
34464
34537
|
}
|
|
34465
34538
|
|
|
34466
34539
|
// ../../node_modules/@chrischall/mcp-utils/dist/response/index.js
|
|
34540
|
+
function textResult(data) {
|
|
34541
|
+
return {
|
|
34542
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
34543
|
+
};
|
|
34544
|
+
}
|
|
34467
34545
|
function rawTextResult(text) {
|
|
34468
34546
|
return { content: [{ type: "text", text }] };
|
|
34469
34547
|
}
|
|
@@ -34474,6 +34552,154 @@ function errorResult(message) {
|
|
|
34474
34552
|
};
|
|
34475
34553
|
}
|
|
34476
34554
|
|
|
34555
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/server/confirmation.js
|
|
34556
|
+
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
34557
|
+
var DEFAULT_REQUEST_KEY = "confirmation";
|
|
34558
|
+
var DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
|
|
34559
|
+
var UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
|
|
34560
|
+
var STATE_PREFIX = "mcpu.confirm.v1.";
|
|
34561
|
+
function canonicalJson(value) {
|
|
34562
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
34563
|
+
return JSON.stringify(value);
|
|
34564
|
+
if (value === void 0)
|
|
34565
|
+
return "null";
|
|
34566
|
+
if (typeof value === "number")
|
|
34567
|
+
return Number.isFinite(value) ? JSON.stringify(value) : `{"$num":"${String(value)}"}`;
|
|
34568
|
+
if (typeof value === "bigint")
|
|
34569
|
+
return `{"$bigint":"${value.toString()}"}`;
|
|
34570
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
34571
|
+
throw new TypeError(`requireConfirmation: cannot bind a ${typeof value} argument value.`);
|
|
34572
|
+
}
|
|
34573
|
+
if (Array.isArray(value))
|
|
34574
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
34575
|
+
if (value instanceof Date) {
|
|
34576
|
+
return `{"$date":${JSON.stringify(Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString())}}`;
|
|
34577
|
+
}
|
|
34578
|
+
if (ArrayBuffer.isView(value)) {
|
|
34579
|
+
const bytes = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
34580
|
+
return `{"$bytes":${JSON.stringify(bytes.toString("base64"))}}`;
|
|
34581
|
+
}
|
|
34582
|
+
if (value instanceof ArrayBuffer)
|
|
34583
|
+
return `{"$bytes":${JSON.stringify(Buffer.from(value).toString("base64"))}}`;
|
|
34584
|
+
if (value instanceof Map) {
|
|
34585
|
+
const entries2 = [...value.entries()].map(([k, v]) => `[${canonicalJson(k)},${canonicalJson(v)}]`).sort();
|
|
34586
|
+
return `{"$map":[${entries2.join(",")}]}`;
|
|
34587
|
+
}
|
|
34588
|
+
if (value instanceof Set) {
|
|
34589
|
+
return `{"$set":[${[...value].map(canonicalJson).sort().join(",")}]}`;
|
|
34590
|
+
}
|
|
34591
|
+
const proto = Object.getPrototypeOf(value);
|
|
34592
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
34593
|
+
throw new TypeError("requireConfirmation: cannot bind a non-plain object argument value (class instance).");
|
|
34594
|
+
}
|
|
34595
|
+
const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
34596
|
+
return `{${entries.map(([k, v]) => `${JSON.stringify(escapeKey(k))}:${canonicalJson(v)}`).join(",")}}`;
|
|
34597
|
+
}
|
|
34598
|
+
function escapeKey(key) {
|
|
34599
|
+
return key.startsWith("$") ? `$${key}` : key;
|
|
34600
|
+
}
|
|
34601
|
+
function bindingKey(binding) {
|
|
34602
|
+
if (binding.ttlSeconds !== void 0 && !(Number.isFinite(binding.ttlSeconds) && binding.ttlSeconds > 0)) {
|
|
34603
|
+
throw new RangeError("requireConfirmation: binding.ttlSeconds must be a finite number greater than 0.");
|
|
34604
|
+
}
|
|
34605
|
+
const key = typeof binding.key === "string" ? Buffer.from(binding.key, "utf8") : Buffer.from(binding.key);
|
|
34606
|
+
if (key.length < 32) {
|
|
34607
|
+
throw new RangeError("requireConfirmation: binding.key must be at least 32 bytes.");
|
|
34608
|
+
}
|
|
34609
|
+
return key;
|
|
34610
|
+
}
|
|
34611
|
+
function commitment(action, args) {
|
|
34612
|
+
return createHash("sha256").update(`${action}\0${canonicalJson(args)}`).digest("base64url");
|
|
34613
|
+
}
|
|
34614
|
+
function mintState(key, action, binding) {
|
|
34615
|
+
const exp = Math.floor(Date.now() / 1e3) + (binding.ttlSeconds ?? 600);
|
|
34616
|
+
const body = Buffer.from(JSON.stringify({ c: commitment(action, binding.args), exp })).toString("base64url");
|
|
34617
|
+
const mac3 = createHmac("sha256", key).update(`${STATE_PREFIX}${body}`).digest("base64url");
|
|
34618
|
+
return `${STATE_PREFIX}${body}.${mac3}`;
|
|
34619
|
+
}
|
|
34620
|
+
function verifyState(key, action, binding, state) {
|
|
34621
|
+
if (typeof state !== "string" || !state.startsWith(STATE_PREFIX))
|
|
34622
|
+
return false;
|
|
34623
|
+
const rest = state.slice(STATE_PREFIX.length);
|
|
34624
|
+
const dot = rest.indexOf(".");
|
|
34625
|
+
if (dot < 0)
|
|
34626
|
+
return false;
|
|
34627
|
+
const body = rest.slice(0, dot);
|
|
34628
|
+
const mac3 = Buffer.from(rest.slice(dot + 1), "base64url");
|
|
34629
|
+
const expected = createHmac("sha256", key).update(`${STATE_PREFIX}${body}`).digest();
|
|
34630
|
+
if (mac3.length !== expected.length || !timingSafeEqual(mac3, expected))
|
|
34631
|
+
return false;
|
|
34632
|
+
let payload;
|
|
34633
|
+
try {
|
|
34634
|
+
payload = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
|
|
34635
|
+
} catch {
|
|
34636
|
+
return false;
|
|
34637
|
+
}
|
|
34638
|
+
if (typeof payload.exp !== "number" || payload.exp * 1e3 <= Date.now())
|
|
34639
|
+
return false;
|
|
34640
|
+
const want = Buffer.from(commitment(action, binding.args));
|
|
34641
|
+
const got = Buffer.from(typeof payload.c === "string" ? payload.c : "");
|
|
34642
|
+
return got.length === want.length && timingSafeEqual(got, want);
|
|
34643
|
+
}
|
|
34644
|
+
function echoedState(ctx) {
|
|
34645
|
+
const accessor = ctx.mcpReq.requestState;
|
|
34646
|
+
return typeof accessor === "function" ? accessor() : void 0;
|
|
34647
|
+
}
|
|
34648
|
+
function requireConfirmation(ctx, options) {
|
|
34649
|
+
const requestKey = options.requestKey ?? DEFAULT_REQUEST_KEY;
|
|
34650
|
+
const key = options.binding ? bindingKey(options.binding) : void 0;
|
|
34651
|
+
const confirmationSchema = external_exports.object({
|
|
34652
|
+
confirmed: external_exports.boolean().describe(options.confirmationLabel ?? DEFAULT_CONFIRMATION_LABEL)
|
|
34653
|
+
});
|
|
34654
|
+
const ask = () => {
|
|
34655
|
+
const preview = {
|
|
34656
|
+
action: options.action,
|
|
34657
|
+
...options.details === void 0 ? {} : { details: options.details }
|
|
34658
|
+
};
|
|
34659
|
+
return inputRequired({
|
|
34660
|
+
inputRequests: {
|
|
34661
|
+
[requestKey]: inputRequired.elicit({
|
|
34662
|
+
message: `${options.message}
|
|
34663
|
+
${JSON.stringify(preview, null, 2)}`,
|
|
34664
|
+
requestedSchema: confirmationSchema
|
|
34665
|
+
})
|
|
34666
|
+
},
|
|
34667
|
+
...key && options.binding ? { requestState: mintState(key, options.action, options.binding) } : {}
|
|
34668
|
+
});
|
|
34669
|
+
};
|
|
34670
|
+
const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
|
|
34671
|
+
const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
|
|
34672
|
+
if (response.kind === "missing") {
|
|
34673
|
+
if (callerAcceptsFormElicitation(ctx) === false) {
|
|
34674
|
+
return textResult({
|
|
34675
|
+
confirmed: false,
|
|
34676
|
+
dispatched: false,
|
|
34677
|
+
action: options.action,
|
|
34678
|
+
reason: "confirmation-unsupported",
|
|
34679
|
+
note: options.unsupportedNote ? `${UNSUPPORTED_NOTE}. ${options.unsupportedNote}` : `${UNSUPPORTED_NOTE}.`
|
|
34680
|
+
});
|
|
34681
|
+
}
|
|
34682
|
+
return ask();
|
|
34683
|
+
}
|
|
34684
|
+
if (response.kind === "elicit" && response.action === "accept" && accepted?.confirmed === true) {
|
|
34685
|
+
if (key && options.binding) {
|
|
34686
|
+
const state = echoedState(ctx);
|
|
34687
|
+
if (state === void 0 || state === null) {
|
|
34688
|
+
return errorResult(`Confirmation for ${options.action} was accepted, but the retry carried no requestState, so it cannot be checked against the prompt that was shown. Nothing was done. The likely cause is that the MCP client or host does not round-trip requestState (it must echo the requestState from the input_required result back on the retry); asking again would loop.`);
|
|
34689
|
+
}
|
|
34690
|
+
if (!verifyState(key, options.action, options.binding, state))
|
|
34691
|
+
return ask();
|
|
34692
|
+
}
|
|
34693
|
+
return void 0;
|
|
34694
|
+
}
|
|
34695
|
+
return textResult({
|
|
34696
|
+
confirmed: false,
|
|
34697
|
+
cancelled: true,
|
|
34698
|
+
action: options.action,
|
|
34699
|
+
note: "Nothing was changed because the confirmation was declined, cancelled, or left unchecked."
|
|
34700
|
+
});
|
|
34701
|
+
}
|
|
34702
|
+
|
|
34477
34703
|
// ../../node_modules/@chrischall/mcp-utils/dist/server/index.js
|
|
34478
34704
|
var SERVER_PROTOCOL_VERSIONS = Object.freeze([
|
|
34479
34705
|
"2026-07-28",
|
|
@@ -34568,13 +34794,47 @@ async function createMcpServer(opts) {
|
|
|
34568
34794
|
}
|
|
34569
34795
|
return server;
|
|
34570
34796
|
}
|
|
34797
|
+
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
34798
|
+
var DEFAULT_REPEAT_SIGNAL_GRACE_MS = 500;
|
|
34571
34799
|
function withGracefulShutdown(target, opts = {}) {
|
|
34572
34800
|
const shouldExit = opts.exit ?? true;
|
|
34801
|
+
if (opts.timeoutMs !== void 0 && !(Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0)) {
|
|
34802
|
+
throw new RangeError("withGracefulShutdown: timeoutMs must be a finite number greater than 0.");
|
|
34803
|
+
}
|
|
34804
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
34805
|
+
if (opts.repeatSignalGraceMs !== void 0 && !(Number.isFinite(opts.repeatSignalGraceMs) && opts.repeatSignalGraceMs >= 0)) {
|
|
34806
|
+
throw new RangeError("withGracefulShutdown: repeatSignalGraceMs must be a finite number >= 0.");
|
|
34807
|
+
}
|
|
34808
|
+
const repeatGraceMs = opts.repeatSignalGraceMs ?? DEFAULT_REPEAT_SIGNAL_GRACE_MS;
|
|
34573
34809
|
let shuttingDown = false;
|
|
34810
|
+
let firstSignalAt = 0;
|
|
34811
|
+
let exited = false;
|
|
34812
|
+
const exitOnce = () => {
|
|
34813
|
+
if (exited)
|
|
34814
|
+
return;
|
|
34815
|
+
exited = true;
|
|
34816
|
+
process.exit(0);
|
|
34817
|
+
};
|
|
34574
34818
|
const handler = (signal) => {
|
|
34575
|
-
if (shuttingDown)
|
|
34819
|
+
if (shuttingDown) {
|
|
34820
|
+
if (Date.now() - firstSignalAt < repeatGraceMs)
|
|
34821
|
+
return;
|
|
34822
|
+
if (shouldExit) {
|
|
34823
|
+
console.error(`[mcp-utils] second ${signal} during shutdown \u2014 exiting now`);
|
|
34824
|
+
exitOnce();
|
|
34825
|
+
}
|
|
34576
34826
|
return;
|
|
34827
|
+
}
|
|
34577
34828
|
shuttingDown = true;
|
|
34829
|
+
firstSignalAt = Date.now();
|
|
34830
|
+
let timer;
|
|
34831
|
+
if (shouldExit) {
|
|
34832
|
+
timer = setTimeout(() => {
|
|
34833
|
+
console.error(`[mcp-utils] graceful shutdown on ${signal} did not finish in ${timeoutMs}ms \u2014 exiting`);
|
|
34834
|
+
exitOnce();
|
|
34835
|
+
}, timeoutMs);
|
|
34836
|
+
timer.unref?.();
|
|
34837
|
+
}
|
|
34578
34838
|
void (async () => {
|
|
34579
34839
|
try {
|
|
34580
34840
|
if (opts.onSignal)
|
|
@@ -34583,8 +34843,10 @@ function withGracefulShutdown(target, opts = {}) {
|
|
|
34583
34843
|
} catch (err) {
|
|
34584
34844
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
34585
34845
|
} finally {
|
|
34846
|
+
if (timer !== void 0)
|
|
34847
|
+
clearTimeout(timer);
|
|
34586
34848
|
if (shouldExit)
|
|
34587
|
-
|
|
34849
|
+
exitOnce();
|
|
34588
34850
|
}
|
|
34589
34851
|
})();
|
|
34590
34852
|
};
|
|
@@ -34614,6 +34876,8 @@ function runMcp(opts) {
|
|
|
34614
34876
|
}
|
|
34615
34877
|
|
|
34616
34878
|
// ../../node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
34879
|
+
import { homedir } from "node:os";
|
|
34880
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
34617
34881
|
var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
|
|
34618
34882
|
function readEnvVar(key, opts = {}) {
|
|
34619
34883
|
const env = opts.env ?? process.env;
|
|
@@ -34640,6 +34904,50 @@ function parseBoolEnv(key, opts = {}) {
|
|
|
34640
34904
|
return false;
|
|
34641
34905
|
return fallback;
|
|
34642
34906
|
}
|
|
34907
|
+
function expandPath(p) {
|
|
34908
|
+
let expanded = p;
|
|
34909
|
+
if (p === "~") {
|
|
34910
|
+
expanded = homedir();
|
|
34911
|
+
} else if (p.startsWith("~/")) {
|
|
34912
|
+
expanded = join(homedir(), p.slice(2));
|
|
34913
|
+
}
|
|
34914
|
+
return isAbsolute(expanded) ? expanded : resolve(expanded);
|
|
34915
|
+
}
|
|
34916
|
+
|
|
34917
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/fs/confine.js
|
|
34918
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
34919
|
+
import { dirname, isAbsolute as isAbsolute2, relative, resolve as resolve2, sep } from "node:path";
|
|
34920
|
+
function isInside(root, target) {
|
|
34921
|
+
const rel = relative(root, target);
|
|
34922
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute2(rel);
|
|
34923
|
+
}
|
|
34924
|
+
function realPathAllowingMissing(p) {
|
|
34925
|
+
const abs = resolve2(p);
|
|
34926
|
+
let existing = abs;
|
|
34927
|
+
const tail = [];
|
|
34928
|
+
while (!existsSync(existing)) {
|
|
34929
|
+
const parent = dirname(existing);
|
|
34930
|
+
if (parent === existing)
|
|
34931
|
+
break;
|
|
34932
|
+
tail.unshift(existing.slice(parent.length).replace(/^[/\\]+/, ""));
|
|
34933
|
+
existing = parent;
|
|
34934
|
+
}
|
|
34935
|
+
let real;
|
|
34936
|
+
try {
|
|
34937
|
+
real = realpathSync(existing);
|
|
34938
|
+
} catch {
|
|
34939
|
+
real = existing;
|
|
34940
|
+
}
|
|
34941
|
+
return tail.length > 0 ? resolve2(real, ...tail) : real;
|
|
34942
|
+
}
|
|
34943
|
+
function assertPathWithinRoots(path, roots) {
|
|
34944
|
+
const target = realPathAllowingMissing(expandPath(path));
|
|
34945
|
+
for (const root of roots) {
|
|
34946
|
+
if (isInside(realPathAllowingMissing(expandPath(root)), target))
|
|
34947
|
+
return target;
|
|
34948
|
+
}
|
|
34949
|
+
throw new Error(`Path is outside the allowed directories: ${path}`);
|
|
34950
|
+
}
|
|
34643
34951
|
|
|
34644
34952
|
// ../../node_modules/@chrischall/mcp-utils/dist/zod/index.js
|
|
34645
34953
|
var PositiveInt = external_exports.number().int().positive();
|
|
@@ -34661,7 +34969,7 @@ var pageSchema = {
|
|
|
34661
34969
|
};
|
|
34662
34970
|
|
|
34663
34971
|
// ../gogcli-mcp/src/runner.ts
|
|
34664
|
-
import { delimiter, join } from "node:path";
|
|
34972
|
+
import { delimiter, join as join2 } from "node:path";
|
|
34665
34973
|
|
|
34666
34974
|
// ../gogcli-mcp/src/timestamps.ts
|
|
34667
34975
|
var DEFAULT_DISPLAY_TZ = "America/New_York";
|
|
@@ -34687,9 +34995,9 @@ function offsetAt(instant, tz) {
|
|
|
34687
34995
|
const w = wallPartsIn(instant, tz);
|
|
34688
34996
|
const asUTC = Date.UTC(w.year, w.month - 1, w.day, w.hour, w.minute, w.second, instant.getUTCMilliseconds());
|
|
34689
34997
|
const minutes = Math.round((asUTC - instant.getTime()) / 6e4);
|
|
34690
|
-
const
|
|
34998
|
+
const sign2 = minutes < 0 ? "-" : "+";
|
|
34691
34999
|
const abs = Math.abs(minutes);
|
|
34692
|
-
return `${
|
|
35000
|
+
return `${sign2}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;
|
|
34693
35001
|
}
|
|
34694
35002
|
function wallPartsIn(instant, tz) {
|
|
34695
35003
|
const parts = new Intl.DateTimeFormat("en-US", {
|
|
@@ -34862,9 +35170,48 @@ function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSource
|
|
|
34862
35170
|
return JSON.stringify(parsed, null, detectIndent(text));
|
|
34863
35171
|
}
|
|
34864
35172
|
|
|
35173
|
+
// ../gogcli-mcp/src/arg-guard.ts
|
|
35174
|
+
var FORBIDDEN_LONG_FLAG = /^--(readonly|enable-commands|enable-commands-exact|disable-commands|access-token|home|account|acct|client|gmail-no-send|no-input|non-interactive|noninteractive)(=|$)/i;
|
|
35175
|
+
var SHORT_ACCOUNT_CLUSTER = /^-(?!-)[A-Za-z]*a/;
|
|
35176
|
+
function forbiddenArgReason(arg) {
|
|
35177
|
+
if (arg === "--") {
|
|
35178
|
+
return 'The argument "--" is not allowed: it ends flag parsing and would disable safety flags appended after it.';
|
|
35179
|
+
}
|
|
35180
|
+
const match = FORBIDDEN_LONG_FLAG.exec(arg);
|
|
35181
|
+
if (match) {
|
|
35182
|
+
return `The flag ${arg} is not allowed here: --${match[1].toLowerCase()} is a safety/credential control set by the server operator, not a per-call option.`;
|
|
35183
|
+
}
|
|
35184
|
+
if (SHORT_ACCOUNT_CLUSTER.test(arg)) {
|
|
35185
|
+
return `The flag ${arg} is not allowed here: -a selects the account. Use the tool's account parameter instead.`;
|
|
35186
|
+
}
|
|
35187
|
+
return void 0;
|
|
35188
|
+
}
|
|
35189
|
+
function assertSafeForwardedArgs(args) {
|
|
35190
|
+
for (const arg of args) {
|
|
35191
|
+
const reason = forbiddenArgReason(arg);
|
|
35192
|
+
if (reason) throw new Error(reason);
|
|
35193
|
+
}
|
|
35194
|
+
}
|
|
35195
|
+
var SUBCOMMAND_SHAPE = /^[a-z][a-z0-9-]*$/;
|
|
35196
|
+
function assertSafeSubcommand(subcommand) {
|
|
35197
|
+
if (!SUBCOMMAND_SHAPE.test(subcommand)) {
|
|
35198
|
+
throw new Error(
|
|
35199
|
+
`Invalid subcommand ${JSON.stringify(subcommand)}: pass a single gog subcommand name such as "list" or "mark-read", and put its arguments in args.`
|
|
35200
|
+
);
|
|
35201
|
+
}
|
|
35202
|
+
}
|
|
35203
|
+
|
|
35204
|
+
// ../gogcli-mcp/src/argv.ts
|
|
35205
|
+
function pos(value) {
|
|
35206
|
+
return { kind: "positional", value };
|
|
35207
|
+
}
|
|
35208
|
+
function isGogPositional(arg) {
|
|
35209
|
+
return typeof arg === "object" && arg !== null && arg.kind === "positional";
|
|
35210
|
+
}
|
|
35211
|
+
|
|
34865
35212
|
// ../gogcli-mcp/src/runner.ts
|
|
34866
35213
|
function isGogFileArg(arg) {
|
|
34867
|
-
return typeof arg !== "string";
|
|
35214
|
+
return typeof arg !== "string" && arg.kind === "file";
|
|
34868
35215
|
}
|
|
34869
35216
|
var TIMEOUT_MS = 3e4;
|
|
34870
35217
|
function readonlyEnvEnabled() {
|
|
@@ -34948,8 +35295,8 @@ function formatTimeout(ms) {
|
|
|
34948
35295
|
}
|
|
34949
35296
|
async function spawnWithTempFiles(args, opts) {
|
|
34950
35297
|
const { mkdtemp, mkdir, writeFile, rm } = await import("node:fs/promises");
|
|
34951
|
-
const { tmpdir } = await import("node:os");
|
|
34952
|
-
const dir = await mkdtemp(
|
|
35298
|
+
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
35299
|
+
const dir = await mkdtemp(join2(tmpdir2(), "gogcli-mcp-"));
|
|
34953
35300
|
try {
|
|
34954
35301
|
const argv = [];
|
|
34955
35302
|
let seq = 0;
|
|
@@ -34958,10 +35305,10 @@ async function spawnWithTempFiles(args, opts) {
|
|
|
34958
35305
|
argv.push(arg);
|
|
34959
35306
|
continue;
|
|
34960
35307
|
}
|
|
34961
|
-
const sub =
|
|
35308
|
+
const sub = join2(dir, String(seq));
|
|
34962
35309
|
seq += 1;
|
|
34963
35310
|
await mkdir(sub, { recursive: true, mode: 448 });
|
|
34964
|
-
const path =
|
|
35311
|
+
const path = join2(sub, arg.filename ?? `${arg.flag}.${arg.ext ?? "txt"}`);
|
|
34965
35312
|
const data = arg.encoding === "base64" ? Buffer.from(arg.contents, "base64") : Buffer.from(arg.contents, "utf8");
|
|
34966
35313
|
await writeFile(path, data, { mode: 384 });
|
|
34967
35314
|
argv.push(arg.positional ? path : `--${arg.flag}=${path}`);
|
|
@@ -34979,10 +35326,10 @@ function spawnExecutor(args, opts) {
|
|
|
34979
35326
|
return spawnGog(args, opts);
|
|
34980
35327
|
}
|
|
34981
35328
|
async function spawnGog(fullArgs, opts) {
|
|
34982
|
-
const { timeout, interactive = false, spawner, binary = false } = opts;
|
|
35329
|
+
const { timeout, interactive = false, spawner, binary = false, maxOutputBytes } = opts;
|
|
34983
35330
|
const spawn = spawner ?? (await import("node:child_process")).spawn;
|
|
34984
35331
|
const effectiveTimeout = timeout ?? TIMEOUT_MS;
|
|
34985
|
-
return new Promise((
|
|
35332
|
+
return new Promise((resolve4, reject) => {
|
|
34986
35333
|
const childEnv = { ...sanitizedEnv(), GOG_TIMEZONE: naiveSourceTimeZone(), PATH: augmentedPath() };
|
|
34987
35334
|
const child = spawn(readEnvVar("GOG_PATH") ?? "gog", fullArgs, { env: childEnv });
|
|
34988
35335
|
const stdoutChunks = [];
|
|
@@ -35000,7 +35347,17 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35000
35347
|
child.kill();
|
|
35001
35348
|
reject(new Error(`gog timed out after ${formatTimeout(effectiveTimeout)}`));
|
|
35002
35349
|
}, effectiveTimeout);
|
|
35350
|
+
let stdoutBytes = 0;
|
|
35003
35351
|
child.stdout.on("data", (chunk) => {
|
|
35352
|
+
if (settled) return;
|
|
35353
|
+
stdoutBytes += chunk.length;
|
|
35354
|
+
if (maxOutputBytes !== void 0 && stdoutBytes > maxOutputBytes) {
|
|
35355
|
+
settled = true;
|
|
35356
|
+
stopWatching();
|
|
35357
|
+
child.kill();
|
|
35358
|
+
reject(new Error(`gog output exceeded the limit: more than ${maxOutputBytes} bytes`));
|
|
35359
|
+
return;
|
|
35360
|
+
}
|
|
35004
35361
|
stdoutChunks.push(chunk);
|
|
35005
35362
|
});
|
|
35006
35363
|
child.stderr.on("data", (chunk) => {
|
|
@@ -35017,14 +35374,14 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35017
35374
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
35018
35375
|
if (code === 0) {
|
|
35019
35376
|
if (binary) {
|
|
35020
|
-
|
|
35377
|
+
resolve4(Buffer.concat(stdoutChunks).toString("base64"));
|
|
35021
35378
|
return;
|
|
35022
35379
|
}
|
|
35023
35380
|
const stdout = Buffer.concat(stdoutChunks).toString();
|
|
35024
35381
|
if (interactive && stderr) {
|
|
35025
|
-
|
|
35382
|
+
resolve4(stdout + "\n" + stderr);
|
|
35026
35383
|
} else {
|
|
35027
|
-
|
|
35384
|
+
resolve4(stdout);
|
|
35028
35385
|
}
|
|
35029
35386
|
} else {
|
|
35030
35387
|
reject(new Error(stderr || `gog exited with code ${code}`));
|
|
@@ -35044,7 +35401,33 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35044
35401
|
});
|
|
35045
35402
|
});
|
|
35046
35403
|
}
|
|
35404
|
+
function placePositionals(args) {
|
|
35405
|
+
const flags = [];
|
|
35406
|
+
const positionals = [];
|
|
35407
|
+
let afterSeparator = false;
|
|
35408
|
+
for (const arg of args) {
|
|
35409
|
+
if (arg === "--") {
|
|
35410
|
+
afterSeparator = true;
|
|
35411
|
+
} else if (isGogPositional(arg)) {
|
|
35412
|
+
positionals.push(arg.value);
|
|
35413
|
+
} else if (afterSeparator || isGogFileArg(arg) && arg.positional) {
|
|
35414
|
+
positionals.push(arg);
|
|
35415
|
+
} else {
|
|
35416
|
+
flags.push(arg);
|
|
35417
|
+
}
|
|
35418
|
+
}
|
|
35419
|
+
return { flags, positionals };
|
|
35420
|
+
}
|
|
35421
|
+
function assertNoSafetyOverrides(flags) {
|
|
35422
|
+
for (const arg of flags) {
|
|
35423
|
+
if (typeof arg !== "string") continue;
|
|
35424
|
+
const reason = forbiddenArgReason(arg);
|
|
35425
|
+
if (reason) throw new Error(reason);
|
|
35426
|
+
}
|
|
35427
|
+
}
|
|
35047
35428
|
function assembleArgs(args, opts) {
|
|
35429
|
+
const { flags, positionals } = placePositionals(args);
|
|
35430
|
+
assertNoSafetyOverrides(flags);
|
|
35048
35431
|
const effectiveAccount = opts.account ?? readEnvVar("GOG_ACCOUNT");
|
|
35049
35432
|
const fullArgs = ["--json", "--color=never"];
|
|
35050
35433
|
if (!opts.interactive) {
|
|
@@ -35053,17 +35436,21 @@ function assembleArgs(args, opts) {
|
|
|
35053
35436
|
if (opts.readonly || readonlyEnvEnabled()) {
|
|
35054
35437
|
fullArgs.push("--readonly");
|
|
35055
35438
|
}
|
|
35439
|
+
if (opts.gmailNoSend) {
|
|
35440
|
+
fullArgs.push("--gmail-no-send");
|
|
35441
|
+
}
|
|
35056
35442
|
if (effectiveAccount) {
|
|
35057
35443
|
fullArgs.push("--account", effectiveAccount);
|
|
35058
35444
|
}
|
|
35059
|
-
fullArgs.push(...
|
|
35445
|
+
fullArgs.push(...flags);
|
|
35446
|
+
if (positionals.length > 0) fullArgs.push("--", ...positionals);
|
|
35060
35447
|
return fullArgs;
|
|
35061
35448
|
}
|
|
35062
35449
|
async function run(args, options = {}) {
|
|
35063
|
-
const { account, spawner, interactive = false, timeout, readonly: readonly2 = false, redactMode = "full", opaqueFields } = options;
|
|
35450
|
+
const { account, spawner, interactive = false, timeout, readonly: readonly2 = false, redactMode = "full", opaqueFields, gmailNoSend = false } = options;
|
|
35064
35451
|
const base = redactMode === "tokens" ? redactGoogleTokens : redactSecrets2;
|
|
35065
35452
|
const redact = opaqueFields?.length ? (text) => redactPreservingOpaqueFields(text, opaqueFields, base) : base;
|
|
35066
|
-
const fullArgs = assembleArgs(args, { account, interactive, readonly: readonly2 });
|
|
35453
|
+
const fullArgs = assembleArgs(args, { account, interactive, readonly: readonly2, gmailNoSend });
|
|
35067
35454
|
try {
|
|
35068
35455
|
return redact(await spawnExecutor(fullArgs, { timeout, interactive, spawner }));
|
|
35069
35456
|
} catch (err) {
|
|
@@ -35071,9 +35458,9 @@ async function run(args, options = {}) {
|
|
|
35071
35458
|
}
|
|
35072
35459
|
}
|
|
35073
35460
|
async function runBinary(args, options = {}) {
|
|
35074
|
-
const { account, spawner, timeout, readonly: readonly2 = false } = options;
|
|
35075
|
-
const fullArgs = assembleArgs(args, { account, interactive: false, readonly: readonly2 });
|
|
35076
|
-
return spawnExecutor(fullArgs, { timeout, interactive: false, spawner, binary: true });
|
|
35461
|
+
const { account, spawner, timeout, readonly: readonly2 = false, gmailNoSend = false, maxOutputBytes } = options;
|
|
35462
|
+
const fullArgs = assembleArgs(args, { account, interactive: false, readonly: readonly2, gmailNoSend });
|
|
35463
|
+
return spawnExecutor(fullArgs, { timeout, interactive: false, spawner, binary: true, maxOutputBytes });
|
|
35077
35464
|
}
|
|
35078
35465
|
|
|
35079
35466
|
// ../gogcli-mcp/src/pagination.ts
|
|
@@ -35096,6 +35483,107 @@ function stripConsumedPageToken(text) {
|
|
|
35096
35483
|
return JSON.stringify(obj, null, detectIndent2(text));
|
|
35097
35484
|
}
|
|
35098
35485
|
|
|
35486
|
+
// ../gogcli-mcp/src/file-roots.ts
|
|
35487
|
+
import { homedir as homedir2 } from "node:os";
|
|
35488
|
+
import { delimiter as delimiter2, join as join4 } from "node:path";
|
|
35489
|
+
|
|
35490
|
+
// ../gogcli-mcp/src/attachment-root.ts
|
|
35491
|
+
import { tmpdir, userInfo } from "node:os";
|
|
35492
|
+
import { dirname as dirname2, join as join3, relative as relative2, resolve as resolve3, isAbsolute as isAbsolute3, sep as sep2 } from "node:path";
|
|
35493
|
+
var ATTACHMENT_DOWNLOAD_ROOT = join3(tmpdir(), `gogcli-mcp-attachments-${userInfo().uid}`);
|
|
35494
|
+
var ATTACHMENT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
35495
|
+
|
|
35496
|
+
// ../gogcli-mcp/src/file-roots.ts
|
|
35497
|
+
var FILE_ROOTS_ENV = "GOG_FILE_ROOTS";
|
|
35498
|
+
function defaultFileRoot() {
|
|
35499
|
+
return join4(homedir2(), "gogcli-mcp-files");
|
|
35500
|
+
}
|
|
35501
|
+
function fileRoots() {
|
|
35502
|
+
const raw = readEnvVar(FILE_ROOTS_ENV);
|
|
35503
|
+
const roots = (raw ?? "").split(delimiter2).map((r) => r.trim()).filter(Boolean);
|
|
35504
|
+
return roots.length > 0 ? roots : [defaultFileRoot()];
|
|
35505
|
+
}
|
|
35506
|
+
function confinePath(path, param, opts = {}) {
|
|
35507
|
+
if (opts.allowDash && path === "-") return path;
|
|
35508
|
+
const roots = [...fileRoots(), ATTACHMENT_DOWNLOAD_ROOT];
|
|
35509
|
+
try {
|
|
35510
|
+
assertPathWithinRoots(path, roots);
|
|
35511
|
+
} catch {
|
|
35512
|
+
throw new Error(
|
|
35513
|
+
`${param} ${JSON.stringify(path)} is outside the directories this server may read or write (${roots.join(", ")}). Put the file in one of them, or ask the server operator to widen ${FILE_ROOTS_ENV}.`
|
|
35514
|
+
);
|
|
35515
|
+
}
|
|
35516
|
+
return path;
|
|
35517
|
+
}
|
|
35518
|
+
|
|
35519
|
+
// ../gogcli-mcp/src/run-path-guard.ts
|
|
35520
|
+
var POSITIONAL_PATH_SUBCOMMANDS = {
|
|
35521
|
+
appscript: { pull: "gog_appscript_pull" },
|
|
35522
|
+
drive: { upload: "gog_drive_upload", sync: "gog_drive_sync_push" },
|
|
35523
|
+
gmail: { import: "gog_gmail_import" },
|
|
35524
|
+
slides: {
|
|
35525
|
+
"add-slide": "gog_slides_add_slide",
|
|
35526
|
+
"insert-image": "gog_slides_insert_image",
|
|
35527
|
+
"replace-slide": "gog_slides_replace_slide"
|
|
35528
|
+
}
|
|
35529
|
+
};
|
|
35530
|
+
var PATH_FLAGS = /* @__PURE__ */ new Set(["out", "output", "out-dir", "output-dir", "dir", "worker-dir", "attach", "file", "key", "cert", "replacements"]);
|
|
35531
|
+
var ID_FLAGS = {
|
|
35532
|
+
drive: /* @__PURE__ */ new Set(["file", "filter-file"])
|
|
35533
|
+
};
|
|
35534
|
+
var EXEC_FLAGS = /* @__PURE__ */ new Set(["on-change", "on-new", "mmdc"]);
|
|
35535
|
+
var SHORT_PATH_CLUSTER = /^-(?!-)[A-Za-z]*[of]/;
|
|
35536
|
+
var LONG_FLAG = /^--([A-Za-z0-9][A-Za-z0-9-]*)(?:=([\s\S]*))?$/;
|
|
35537
|
+
function isPathFlag(service, name) {
|
|
35538
|
+
if (ID_FLAGS[service]?.has(name)) return false;
|
|
35539
|
+
return PATH_FLAGS.has(name) || name.endsWith("-file");
|
|
35540
|
+
}
|
|
35541
|
+
function confineFlagValue(flag, value) {
|
|
35542
|
+
if (value === "-") return;
|
|
35543
|
+
confinePath(value, flag);
|
|
35544
|
+
for (const part of value.split(",")) {
|
|
35545
|
+
if (part !== "" && part !== "-") confinePath(part, flag);
|
|
35546
|
+
}
|
|
35547
|
+
}
|
|
35548
|
+
function positionalPathTool(service, subcommand) {
|
|
35549
|
+
return POSITIONAL_PATH_SUBCOMMANDS[service]?.[subcommand];
|
|
35550
|
+
}
|
|
35551
|
+
function assertRunPathsConfined(service, subcommand, args) {
|
|
35552
|
+
const dedicated = positionalPathTool(service, subcommand);
|
|
35553
|
+
if (dedicated) {
|
|
35554
|
+
throw new Error(
|
|
35555
|
+
`gog ${service} ${subcommand} reads or writes a local path given as a positional argument, so it is not available through gog_${service}_run. Use ${dedicated}, which confines the path to GOG_FILE_ROOTS.`
|
|
35556
|
+
);
|
|
35557
|
+
}
|
|
35558
|
+
for (let i = 0; i < args.length; i++) {
|
|
35559
|
+
const arg = args[i];
|
|
35560
|
+
if (SHORT_PATH_CLUSTER.test(arg)) {
|
|
35561
|
+
throw new Error(
|
|
35562
|
+
`The flag ${arg} is not allowed here: spell a path flag out as --out or --file (e.g. --out=<path>) so its path can be checked against GOG_FILE_ROOTS.`
|
|
35563
|
+
);
|
|
35564
|
+
}
|
|
35565
|
+
const match = LONG_FLAG.exec(arg);
|
|
35566
|
+
if (!match) continue;
|
|
35567
|
+
const name = match[1].toLowerCase();
|
|
35568
|
+
if (EXEC_FLAGS.has(name)) {
|
|
35569
|
+
throw new Error(`The flag --${name} is not allowed here: it runs a local program chosen by the caller.`);
|
|
35570
|
+
}
|
|
35571
|
+
const isJson = name.endsWith("-json");
|
|
35572
|
+
if (!isJson && !isPathFlag(service, name)) continue;
|
|
35573
|
+
let value = match[2];
|
|
35574
|
+
if (value === void 0) {
|
|
35575
|
+
value = args[i + 1];
|
|
35576
|
+
if (value === void 0) continue;
|
|
35577
|
+
i++;
|
|
35578
|
+
}
|
|
35579
|
+
if (isJson) {
|
|
35580
|
+
if (value.startsWith("@")) confineFlagValue(`--${name}`, value.slice(1));
|
|
35581
|
+
continue;
|
|
35582
|
+
}
|
|
35583
|
+
confineFlagValue(`--${name}`, value);
|
|
35584
|
+
}
|
|
35585
|
+
}
|
|
35586
|
+
|
|
35099
35587
|
// ../gogcli-mcp/src/tools/utils.ts
|
|
35100
35588
|
var accountParam = external_exports.string().optional().describe(
|
|
35101
35589
|
"Google account email to use, e.g. you@gmail.com \u2014 must be the full address, not a bare username. Overrides the GOG_ACCOUNT env var. Omit to use the single configured account."
|
|
@@ -35146,9 +35634,17 @@ function pushPaginationFlags(args, p) {
|
|
|
35146
35634
|
if (p.all) args.push("--all");
|
|
35147
35635
|
}
|
|
35148
35636
|
function registerRunTool(server, options) {
|
|
35149
|
-
const { service, examples, omitAccount = false, note } = options;
|
|
35637
|
+
const { service, examples, omitAccount = false, note, allowedSubcommands, vet, gmailNoSend = false } = options;
|
|
35638
|
+
for (const [, example] of examples.matchAll(/"([^"]+)"/g)) {
|
|
35639
|
+
const refused = allowedSubcommands && !allowedSubcommands.includes(example) || vet?.(example, []) || positionalPathTool(service, example);
|
|
35640
|
+
if (refused) {
|
|
35641
|
+
throw new Error(`gog_${service}_run example "${example}" is refused by the tool itself; list a subcommand it runs.`);
|
|
35642
|
+
}
|
|
35643
|
+
}
|
|
35150
35644
|
const baseDescription = `Run any gog ${service} subcommand not covered by the other tools. Run \`gog ${service} --help\` for the full list of subcommands, or \`gog ${service} <subcommand> --help\` for flags on a specific subcommand.`;
|
|
35151
|
-
const
|
|
35645
|
+
const restriction = allowedSubcommands ? ` Only these subcommands are available: ${allowedSubcommands.join(", ")}.` : "";
|
|
35646
|
+
const safety = ' Flags that override server safety controls (--readonly, --enable-commands, --disable-commands, --account, --access-token, --home, --client, --gmail-no-send, --no-input) and a bare "--" are refused. Local file paths (--out, --out-dir, --attach, --file, --*-file, @file JSON) must be inside GOG_FILE_ROOTS; subcommands that take a local path positionally (e.g. drive upload) are refused in favour of their dedicated tools.';
|
|
35647
|
+
const description = `${baseDescription}${restriction}${safety}${note ? ` ${note}` : ""}`;
|
|
35152
35648
|
const inputSchema = {
|
|
35153
35649
|
subcommand: external_exports.string().describe(`The gog ${service} subcommand to run, e.g. ${examples}`),
|
|
35154
35650
|
args: external_exports.array(external_exports.string()).describe("Additional positional args and flags")
|
|
@@ -35162,7 +35658,21 @@ function registerRunTool(server, options) {
|
|
|
35162
35658
|
inputSchema: external_exports.object(inputSchema)
|
|
35163
35659
|
}, async (rawArgs) => {
|
|
35164
35660
|
const { subcommand, args, account } = rawArgs;
|
|
35165
|
-
|
|
35661
|
+
try {
|
|
35662
|
+
assertSafeSubcommand(subcommand);
|
|
35663
|
+
assertSafeForwardedArgs(args);
|
|
35664
|
+
if (allowedSubcommands && !allowedSubcommands.includes(subcommand)) {
|
|
35665
|
+
throw new Error(
|
|
35666
|
+
`gog ${service} ${subcommand} is not available through gog_${service}_run. Allowed: ${allowedSubcommands.join(", ")}.`
|
|
35667
|
+
);
|
|
35668
|
+
}
|
|
35669
|
+
const refusal = vet?.(subcommand, args);
|
|
35670
|
+
if (refusal) throw new Error(refusal);
|
|
35671
|
+
assertRunPathsConfined(service, subcommand, args);
|
|
35672
|
+
} catch (err) {
|
|
35673
|
+
return errorResult(errorText(err));
|
|
35674
|
+
}
|
|
35675
|
+
return runOrDiagnose([service, subcommand, ...args], gmailNoSend ? { account, gmailNoSend } : { account });
|
|
35166
35676
|
});
|
|
35167
35677
|
}
|
|
35168
35678
|
function errorText(err) {
|
|
@@ -35283,7 +35793,176 @@ function formatAuthHealth(raw, now) {
|
|
|
35283
35793
|
return accounts.map((a) => formatOneAccountHealth(a, now)).join("\n\n");
|
|
35284
35794
|
}
|
|
35285
35795
|
|
|
35796
|
+
// ../gogcli-mcp/src/send-confirm-token.ts
|
|
35797
|
+
import { createHash as createHash2, createHmac as createHmac2, randomBytes, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
35798
|
+
var CONFIRM_TOKEN_TTL_DEFAULT_SECONDS = 600;
|
|
35799
|
+
var PREFIX = "gct1";
|
|
35800
|
+
var secret;
|
|
35801
|
+
var spent = /* @__PURE__ */ new Map();
|
|
35802
|
+
function sendConfirmFallbackEnabled() {
|
|
35803
|
+
return readEnvVar("GOG_SEND_CONFIRM_FALLBACK")?.trim().toLowerCase() === "token";
|
|
35804
|
+
}
|
|
35805
|
+
function confirmTokenTtlSeconds() {
|
|
35806
|
+
const raw = readEnvVar("GOG_CONFIRM_TTL_SECONDS")?.trim();
|
|
35807
|
+
if (raw && /^\d+$/.test(raw)) {
|
|
35808
|
+
const n = Number(raw);
|
|
35809
|
+
if (n > 0) return n;
|
|
35810
|
+
}
|
|
35811
|
+
return CONFIRM_TOKEN_TTL_DEFAULT_SECONDS;
|
|
35812
|
+
}
|
|
35813
|
+
function hmacKey() {
|
|
35814
|
+
if (!secret) {
|
|
35815
|
+
const configured = readEnvVar("GOG_CONFIRM_SECRET");
|
|
35816
|
+
secret = configured ? Buffer.from(configured, "utf8") : randomBytes(32);
|
|
35817
|
+
}
|
|
35818
|
+
return secret;
|
|
35819
|
+
}
|
|
35820
|
+
function canonicalize(value) {
|
|
35821
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
35822
|
+
if (value && typeof value === "object") {
|
|
35823
|
+
const out = {};
|
|
35824
|
+
for (const key of Object.keys(value).sort()) {
|
|
35825
|
+
const v = value[key];
|
|
35826
|
+
if (v !== void 0) out[key] = canonicalize(v);
|
|
35827
|
+
}
|
|
35828
|
+
return out;
|
|
35829
|
+
}
|
|
35830
|
+
return value;
|
|
35831
|
+
}
|
|
35832
|
+
function hashSendPayload(payload) {
|
|
35833
|
+
return createHash2("sha256").update(JSON.stringify(canonicalize(payload))).digest("hex");
|
|
35834
|
+
}
|
|
35835
|
+
function sign(body) {
|
|
35836
|
+
return createHmac2("sha256", hmacKey()).update(`${PREFIX}.${body}`).digest("base64url");
|
|
35837
|
+
}
|
|
35838
|
+
function issueConfirmToken(binding, now = Date.now()) {
|
|
35839
|
+
const exp = now + confirmTokenTtlSeconds() * 1e3;
|
|
35840
|
+
const claims = {
|
|
35841
|
+
t: binding.tool,
|
|
35842
|
+
a: binding.account,
|
|
35843
|
+
g: binding.target,
|
|
35844
|
+
...binding.revision === void 0 ? {} : { r: binding.revision },
|
|
35845
|
+
h: binding.payloadHash,
|
|
35846
|
+
iat: now,
|
|
35847
|
+
exp,
|
|
35848
|
+
n: randomBytes(16).toString("base64url")
|
|
35849
|
+
};
|
|
35850
|
+
const body = Buffer.from(JSON.stringify(claims), "utf8").toString("base64url");
|
|
35851
|
+
return { token: `${PREFIX}.${body}.${sign(body)}`, expiresAt: new Date(exp).toISOString() };
|
|
35852
|
+
}
|
|
35853
|
+
function signatureMatches(body, sig) {
|
|
35854
|
+
const expected = Buffer.from(sign(body), "utf8");
|
|
35855
|
+
const actual = Buffer.from(sig, "utf8");
|
|
35856
|
+
return expected.length === actual.length && timingSafeEqual2(expected, actual);
|
|
35857
|
+
}
|
|
35858
|
+
function parseClaims(body) {
|
|
35859
|
+
try {
|
|
35860
|
+
return JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
|
|
35861
|
+
} catch {
|
|
35862
|
+
return void 0;
|
|
35863
|
+
}
|
|
35864
|
+
}
|
|
35865
|
+
function verifyConfirmToken(token, binding, now = Date.now()) {
|
|
35866
|
+
for (const [nonce, exp] of spent) if (exp < now) spent.delete(nonce);
|
|
35867
|
+
const parts = token.split(".");
|
|
35868
|
+
if (parts.length !== 3 || parts[0] !== PREFIX || !parts[1] || !parts[2]) return { ok: false, error: "TOKEN_INVALID" };
|
|
35869
|
+
const [, body, sig] = parts;
|
|
35870
|
+
if (!signatureMatches(body, sig)) return { ok: false, error: "TOKEN_INVALID" };
|
|
35871
|
+
const claims = parseClaims(body);
|
|
35872
|
+
if (!claims) return { ok: false, error: "TOKEN_INVALID" };
|
|
35873
|
+
if (claims.t !== binding.tool || claims.a !== binding.account || claims.g !== binding.target) {
|
|
35874
|
+
return { ok: false, error: "TOKEN_INVALID" };
|
|
35875
|
+
}
|
|
35876
|
+
if (spent.has(claims.n)) return { ok: false, error: "TOKEN_REUSED" };
|
|
35877
|
+
if (now > claims.exp) return { ok: false, error: "TOKEN_EXPIRED" };
|
|
35878
|
+
if (claims.r !== binding.revision) return { ok: false, error: "DRAFT_CHANGED", reason: "message-id-rotated" };
|
|
35879
|
+
if (claims.h !== binding.payloadHash) return { ok: false, error: "DRAFT_CHANGED", reason: "payload-changed" };
|
|
35880
|
+
spent.set(claims.n, claims.exp);
|
|
35881
|
+
return { ok: true };
|
|
35882
|
+
}
|
|
35883
|
+
|
|
35884
|
+
// ../gogcli-mcp/src/dispatch-confirmation.ts
|
|
35885
|
+
var CONFIRM_ACTION_INSTRUCTION = "Show this preview to the user verbatim and proceed only after they explicitly approve in chat. Then call again with confirmToken.";
|
|
35886
|
+
var FALLBACK_HINT = "Or set GOG_SEND_CONFIRM_FALLBACK=token to enable two-step confirmation.";
|
|
35887
|
+
var CONFIRM_FALLBACK_DESCRIPTION = ' If the client cannot show that prompt (no MCP elicitation, e.g. claude.ai) and the server sets GOG_SEND_CONFIRM_FALLBACK=token, a two-step flow applies instead: call WITHOUT confirmToken and nothing is sent or changed \u2014 the result has status "confirmation-required", the full preview and a confirmToken. Show that preview to the user verbatim; only after they explicitly approve it in chat, call again with the SAME arguments plus confirmToken. The tool re-reads what it would act on and refuses (DRAFT_CHANGED, with a fresh preview and token) if it changed; TOKEN_EXPIRED / TOKEN_REUSED / TOKEN_INVALID also do nothing.';
|
|
35888
|
+
var confirmTokenParam = external_exports.string().optional().describe(
|
|
35889
|
+
`ONLY for the two-step fallback (client without MCP elicitation, server with GOG_SEND_CONFIRM_FALLBACK=token). The confirmToken from this same tool's phase-1 "confirmation-required" response, passed back ONLY after the user has seen that preview and explicitly approved it in chat \u2014 never on the first call, never invented, never reused. Call again with the same arguments. Ignored when the client supports elicitation.`
|
|
35890
|
+
);
|
|
35891
|
+
var TOKEN_ERROR_NOTE = {
|
|
35892
|
+
TOKEN_EXPIRED: "Nothing was sent or changed: the confirmToken expired. Call again WITHOUT confirmToken for a fresh preview, and ask the user to approve it again.",
|
|
35893
|
+
TOKEN_REUSED: "Nothing was sent or changed by this call: this confirmToken was already used, and one approval acts once. If doing it again is really intended, call again WITHOUT confirmToken and get a new approval.",
|
|
35894
|
+
TOKEN_INVALID: "Nothing was sent or changed: this confirmToken was not issued by this server for this tool, account and target (or the server has restarted since). Call again WITHOUT confirmToken for a fresh preview and approval."
|
|
35895
|
+
};
|
|
35896
|
+
var DRAFT_CHANGED_NOTE = {
|
|
35897
|
+
"message-id-rotated": "Nothing was sent or changed: the target was edited since the user approved it (a draft's messageId or an event's version rotated), so what would happen is not what they saw.",
|
|
35898
|
+
"payload-changed": "Nothing was sent or changed: what would happen no longer matches what the user approved."
|
|
35899
|
+
};
|
|
35900
|
+
function isToolResult(value) {
|
|
35901
|
+
return Array.isArray(value.content);
|
|
35902
|
+
}
|
|
35903
|
+
function rejection2(data) {
|
|
35904
|
+
return { ...textResult({ status: "confirmation-rejected", confirmed: false, dispatched: false, ...data }), isError: true };
|
|
35905
|
+
}
|
|
35906
|
+
async function tokenConfirmation(op, fallback) {
|
|
35907
|
+
const subject = await fallback.subject();
|
|
35908
|
+
if (isToolResult(subject)) return subject;
|
|
35909
|
+
const binding = {
|
|
35910
|
+
tool: fallback.tool,
|
|
35911
|
+
account: fallback.account ?? readEnvVar("GOG_ACCOUNT") ?? "",
|
|
35912
|
+
target: subject.target,
|
|
35913
|
+
...subject.revision === void 0 ? {} : { revision: subject.revision },
|
|
35914
|
+
payloadHash: hashSendPayload(subject.payload)
|
|
35915
|
+
};
|
|
35916
|
+
const phaseOne = () => {
|
|
35917
|
+
const { token, expiresAt } = issueConfirmToken(binding);
|
|
35918
|
+
return {
|
|
35919
|
+
action: op,
|
|
35920
|
+
preview: subject.preview,
|
|
35921
|
+
confirmToken: token,
|
|
35922
|
+
expiresAt,
|
|
35923
|
+
ttlSeconds: confirmTokenTtlSeconds(),
|
|
35924
|
+
instruction: fallback.instruction ?? CONFIRM_ACTION_INSTRUCTION
|
|
35925
|
+
};
|
|
35926
|
+
};
|
|
35927
|
+
if (!fallback.confirmToken) {
|
|
35928
|
+
return textResult({ status: "confirmation-required", confirmed: false, dispatched: false, ...phaseOne() });
|
|
35929
|
+
}
|
|
35930
|
+
const verdict = verifyConfirmToken(fallback.confirmToken, binding);
|
|
35931
|
+
if (verdict.ok) return void 0;
|
|
35932
|
+
if (verdict.error === "DRAFT_CHANGED") {
|
|
35933
|
+
return rejection2({
|
|
35934
|
+
error: "DRAFT_CHANGED",
|
|
35935
|
+
reason: verdict.reason,
|
|
35936
|
+
note: `${DRAFT_CHANGED_NOTE[verdict.reason]} The current preview and a fresh confirmToken are below.`,
|
|
35937
|
+
...phaseOne()
|
|
35938
|
+
});
|
|
35939
|
+
}
|
|
35940
|
+
return rejection2({ error: verdict.error, action: op, note: TOKEN_ERROR_NOTE[verdict.error] });
|
|
35941
|
+
}
|
|
35942
|
+
function gatedElsewhere(what, via, does, tool) {
|
|
35943
|
+
return `${what} ${does} and is not available through ${via}. Use ${tool}, which asks the user to confirm.`;
|
|
35944
|
+
}
|
|
35945
|
+
async function requireDispatchConfirmation(ctx, options) {
|
|
35946
|
+
const { action, fallback } = options;
|
|
35947
|
+
if (fallback && callerAcceptsFormElicitation(ctx) === false && sendConfirmFallbackEnabled()) {
|
|
35948
|
+
return tokenConfirmation(action, fallback);
|
|
35949
|
+
}
|
|
35950
|
+
const note = fallback ? [options.unsupportedNote, FALLBACK_HINT].filter(Boolean).join(" ") : options.unsupportedNote;
|
|
35951
|
+
return requireConfirmation(ctx, {
|
|
35952
|
+
action,
|
|
35953
|
+
message: options.message,
|
|
35954
|
+
details: options.details,
|
|
35955
|
+
confirmationLabel: options.confirmationLabel,
|
|
35956
|
+
...note ? { unsupportedNote: note } : {}
|
|
35957
|
+
});
|
|
35958
|
+
}
|
|
35959
|
+
function resultText(result) {
|
|
35960
|
+
const first = result.content[0];
|
|
35961
|
+
return first && first.type === "text" && typeof first.text === "string" ? first.text : "{}";
|
|
35962
|
+
}
|
|
35963
|
+
|
|
35286
35964
|
// ../gogcli-mcp/src/tools/auth.ts
|
|
35965
|
+
var AUTH_RUN_SUBCOMMANDS = ["list", "status", "services", "remove", "alias"];
|
|
35287
35966
|
function registerAuthToolsWith(server, defaultServices) {
|
|
35288
35967
|
const servicesDescribe = `Services to authorize: "all" or comma-separated list (e.g. "sheets,gmail,calendar"). Default: "${defaultServices}". Prefer the narrowest set you need \u2014 requesting a service whose Google API is not enabled on the OAuth client's project makes Google reject the WHOLE request with invalid_scope.`;
|
|
35289
35968
|
const extraScopesDescribe = "Additional raw OAuth scope URIs to request, comma-separated, on top of the ones `services` implies. Use for scopes no service covers \u2014 e.g. https://www.googleapis.com/auth/bigquery.readonly, required before gog_sheets_datasource_* can read BigQuery-backed Connected Sheets. Leave unset otherwise: an extra scope whose API is not enabled on the OAuth client project makes Google reject the WHOLE authorization with invalid_scope.";
|
|
@@ -35341,7 +36020,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35341
36020
|
})
|
|
35342
36021
|
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
35343
36022
|
try {
|
|
35344
|
-
const args = ["auth", "add", email3, "--services", services];
|
|
36023
|
+
const args = ["auth", "add", pos(email3), "--services", services];
|
|
35345
36024
|
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`, "--force-consent");
|
|
35346
36025
|
return rawTextResult(await run(args, {
|
|
35347
36026
|
interactive: true,
|
|
@@ -35361,7 +36040,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35361
36040
|
})
|
|
35362
36041
|
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
35363
36042
|
try {
|
|
35364
|
-
const args = ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"];
|
|
36043
|
+
const args = ["auth", "add", pos(email3), "--remote", "--step", "1", "--services", services, "--force-consent"];
|
|
35365
36044
|
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
|
|
35366
36045
|
return rawTextResult(await run(args, { redactMode: "tokens" }));
|
|
35367
36046
|
} catch (err) {
|
|
@@ -35388,7 +36067,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35388
36067
|
const args = [
|
|
35389
36068
|
"auth",
|
|
35390
36069
|
"add",
|
|
35391
|
-
email3,
|
|
36070
|
+
pos(email3),
|
|
35392
36071
|
"--remote",
|
|
35393
36072
|
"--step",
|
|
35394
36073
|
"2",
|
|
@@ -35408,6 +36087,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35408
36087
|
service: "auth",
|
|
35409
36088
|
examples: '"remove", "alias", "list"',
|
|
35410
36089
|
omitAccount: true,
|
|
36090
|
+
allowedSubcommands: AUTH_RUN_SUBCOMMANDS,
|
|
35411
36091
|
note: "For browser-based authorization, use gog_auth_add instead."
|
|
35412
36092
|
});
|
|
35413
36093
|
}
|
|
@@ -35481,12 +36161,25 @@ function inlineFileArg(flag, attachment, opts = {}) {
|
|
|
35481
36161
|
}
|
|
35482
36162
|
|
|
35483
36163
|
// ../gogcli-mcp/src/tools/drive.ts
|
|
36164
|
+
function vetDriveRun(subcommand, _args) {
|
|
36165
|
+
return subcommand.toLowerCase() === "share" ? gatedElsewhere("gog drive share", "gog_drive_run", "grants access to a file", "gog_drive_share") : void 0;
|
|
36166
|
+
}
|
|
35484
36167
|
var GOOGLE_DOC_MIME = "application/vnd.google-apps.document";
|
|
36168
|
+
function shareTargetMeta(raw) {
|
|
36169
|
+
try {
|
|
36170
|
+
const { name, mimeType } = fileMeta(raw);
|
|
36171
|
+
return { name, mimeType };
|
|
36172
|
+
} catch {
|
|
36173
|
+
return {};
|
|
36174
|
+
}
|
|
36175
|
+
}
|
|
35485
36176
|
function fileMeta(raw) {
|
|
35486
36177
|
const parsed = JSON.parse(raw);
|
|
35487
36178
|
const f = parsed.file ?? parsed;
|
|
35488
|
-
|
|
36179
|
+
const size = f.size === void 0 ? void 0 : Number(f.size);
|
|
36180
|
+
return { name: f.name, mimeType: f.mimeType, size: Number.isFinite(size) ? size : void 0 };
|
|
35489
36181
|
}
|
|
36182
|
+
var MAX_DRIVE_READ_BYTES = MAX_INLINE_ATTACHMENT_BYTES;
|
|
35490
36183
|
var DRIVE_LS_COMPACT_FIELDS = "nextPageToken,files(id,name,mimeType,modifiedTime,size,webViewLink)";
|
|
35491
36184
|
function registerDriveTools(server) {
|
|
35492
36185
|
server.registerTool("gog_drive_ls", {
|
|
@@ -35530,7 +36223,7 @@ function registerDriveTools(server) {
|
|
|
35530
36223
|
account: accountParam
|
|
35531
36224
|
})
|
|
35532
36225
|
}, async ({ query, view, account }) => {
|
|
35533
|
-
return runOrDiagnose(["drive", "search", query], {
|
|
36226
|
+
return runOrDiagnose(["drive", "search", pos(query)], {
|
|
35534
36227
|
account,
|
|
35535
36228
|
stripMedia: resolveView(view, ["compact", "full"]) === "compact"
|
|
35536
36229
|
});
|
|
@@ -35550,7 +36243,7 @@ function registerDriveTools(server) {
|
|
|
35550
36243
|
account: accountParam
|
|
35551
36244
|
})
|
|
35552
36245
|
}, async ({ fileId, view, account }) => {
|
|
35553
|
-
return runOrDiagnose(["drive", "get", fileId], {
|
|
36246
|
+
return runOrDiagnose(["drive", "get", pos(fileId)], {
|
|
35554
36247
|
account,
|
|
35555
36248
|
stripMedia: resolveView(view, ["compact", "full"]) === "compact"
|
|
35556
36249
|
});
|
|
@@ -35563,7 +36256,7 @@ function registerDriveTools(server) {
|
|
|
35563
36256
|
account: accountParam
|
|
35564
36257
|
})
|
|
35565
36258
|
}, async ({ name, account }) => {
|
|
35566
|
-
return runOrDiagnose(["drive", "mkdir", name], { account });
|
|
36259
|
+
return runOrDiagnose(["drive", "mkdir", pos(name)], { account });
|
|
35567
36260
|
});
|
|
35568
36261
|
server.registerTool("gog_drive_rename", {
|
|
35569
36262
|
description: "Rename a file or folder in Google Drive.",
|
|
@@ -35574,7 +36267,7 @@ function registerDriveTools(server) {
|
|
|
35574
36267
|
account: accountParam
|
|
35575
36268
|
})
|
|
35576
36269
|
}, async ({ fileId, newName, account }) => {
|
|
35577
|
-
return runOrDiagnose(["drive", "rename", fileId, newName], { account });
|
|
36270
|
+
return runOrDiagnose(["drive", "rename", pos(fileId), pos(newName)], { account });
|
|
35578
36271
|
});
|
|
35579
36272
|
server.registerTool("gog_drive_move", {
|
|
35580
36273
|
description: "Move a file to a different folder in Google Drive.",
|
|
@@ -35585,7 +36278,7 @@ function registerDriveTools(server) {
|
|
|
35585
36278
|
account: accountParam
|
|
35586
36279
|
})
|
|
35587
36280
|
}, async ({ fileId, parentId, account }) => {
|
|
35588
|
-
return runOrDiagnose(["drive", "move", fileId, `--parent=${parentId}`], { account });
|
|
36281
|
+
return runOrDiagnose(["drive", "move", pos(fileId), `--parent=${parentId}`], { account });
|
|
35589
36282
|
});
|
|
35590
36283
|
server.registerTool("gog_drive_delete", {
|
|
35591
36284
|
description: "Move a Google Drive file to trash, or permanently delete it with permanent=true (irreversible).",
|
|
@@ -35596,13 +36289,13 @@ function registerDriveTools(server) {
|
|
|
35596
36289
|
account: accountParam
|
|
35597
36290
|
})
|
|
35598
36291
|
}, async ({ fileId, permanent, account }) => {
|
|
35599
|
-
const args = ["drive", "delete", fileId];
|
|
36292
|
+
const args = ["drive", "delete", pos(fileId)];
|
|
35600
36293
|
if (permanent) args.push("--permanent");
|
|
35601
36294
|
args.push("--force");
|
|
35602
36295
|
return runOrDiagnose(args, { account });
|
|
35603
36296
|
});
|
|
35604
36297
|
server.registerTool("gog_drive_share", {
|
|
35605
|
-
description: "Share a Google Drive file or folder.",
|
|
36298
|
+
description: "Share a Google Drive file or folder. Granting access is the risk even though no email is sent (gog does not notify by default), so this reads the file and asks the MCP host to show the user a confirmation prompt naming it, who gets access and with what role; nothing is shared unless they accept." + CONFIRM_FALLBACK_DESCRIPTION,
|
|
35606
36299
|
annotations: { destructiveHint: true },
|
|
35607
36300
|
inputSchema: external_exports.object({
|
|
35608
36301
|
fileId: external_exports.string().describe("File or folder ID"),
|
|
@@ -35610,10 +36303,36 @@ function registerDriveTools(server) {
|
|
|
35610
36303
|
email: external_exports.string().optional().describe("User email (required when to=user)"),
|
|
35611
36304
|
domain: external_exports.string().optional().describe("Domain (required when to=domain)"),
|
|
35612
36305
|
role: external_exports.enum(["reader", "writer"]).optional().describe("Permission role (default: reader)"),
|
|
35613
|
-
account: accountParam
|
|
36306
|
+
account: accountParam,
|
|
36307
|
+
confirmToken: confirmTokenParam
|
|
35614
36308
|
})
|
|
35615
|
-
}, async ({ fileId, to, email: email3, domain: domain2, role, account }) => {
|
|
35616
|
-
const
|
|
36309
|
+
}, async ({ fileId, to, email: email3, domain: domain2, role, account, confirmToken }, ctx) => {
|
|
36310
|
+
const got = await runOrDiagnose(["drive", "get", pos(fileId)], { account });
|
|
36311
|
+
if (got.isError) return got;
|
|
36312
|
+
const file2 = { id: fileId, ...shareTargetMeta(resultText(got)) };
|
|
36313
|
+
const grant = {
|
|
36314
|
+
file: file2,
|
|
36315
|
+
to,
|
|
36316
|
+
...email3 ? { email: email3 } : {},
|
|
36317
|
+
...domain2 ? { domain: domain2 } : {},
|
|
36318
|
+
role: role ?? "reader",
|
|
36319
|
+
publicLink: to === "anyone"
|
|
36320
|
+
};
|
|
36321
|
+
const confirmation = await requireDispatchConfirmation(ctx, {
|
|
36322
|
+
action: "drive.share",
|
|
36323
|
+
message: to === "anyone" ? "Review and confirm making this file available to ANYONE with the link:" : "Review and confirm this Drive share:",
|
|
36324
|
+
confirmationLabel: "Confirm that this access should be granted now.",
|
|
36325
|
+
details: grant,
|
|
36326
|
+
unsupportedNote: "Ask the user to share it themselves from Google Drive.",
|
|
36327
|
+
fallback: {
|
|
36328
|
+
tool: "gog_drive_share",
|
|
36329
|
+
account,
|
|
36330
|
+
confirmToken,
|
|
36331
|
+
subject: () => ({ target: fileId, payload: grant, preview: grant })
|
|
36332
|
+
}
|
|
36333
|
+
});
|
|
36334
|
+
if (confirmation) return confirmation;
|
|
36335
|
+
const args = ["drive", "share", pos(fileId), `--to=${to}`];
|
|
35617
36336
|
if (email3) args.push(`--email=${email3}`);
|
|
35618
36337
|
if (domain2) args.push(`--domain=${domain2}`);
|
|
35619
36338
|
if (role) args.push(`--role=${role}`);
|
|
@@ -35636,7 +36355,7 @@ function registerDriveTools(server) {
|
|
|
35636
36355
|
}, async ({ fileId, ocrLanguage, offset = 0, maxChars, account }) => {
|
|
35637
36356
|
let tempDocId;
|
|
35638
36357
|
try {
|
|
35639
|
-
const { name, mimeType } = fileMeta(await run(["drive", "get", fileId], { account }));
|
|
36358
|
+
const { name, mimeType } = fileMeta(await run(["drive", "get", pos(fileId)], { account }));
|
|
35640
36359
|
let sourceId = fileId;
|
|
35641
36360
|
if (mimeType !== GOOGLE_DOC_MIME) {
|
|
35642
36361
|
const params = JSON.stringify({ fileId, ...ocrLanguage ? { ocrLanguage } : {} });
|
|
@@ -35681,13 +36400,13 @@ function registerDriveTools(server) {
|
|
|
35681
36400
|
return diagnose(err);
|
|
35682
36401
|
} finally {
|
|
35683
36402
|
if (tempDocId) {
|
|
35684
|
-
await run(["drive", "delete", tempDocId, "--permanent", "--force"], { account }).catch(() => {
|
|
36403
|
+
await run(["drive", "delete", pos(tempDocId), "--permanent", "--force"], { account }).catch(() => {
|
|
35685
36404
|
});
|
|
35686
36405
|
}
|
|
35687
36406
|
}
|
|
35688
36407
|
});
|
|
35689
36408
|
server.registerTool("gog_drive_read_bytes", {
|
|
35690
|
-
description: "Fetch a Drive file's raw bytes and return them base64-encoded as an embedded resource \u2014 the generic fallback for callers that want the file itself (to parse locally) rather than extracted text. For readable text from a PDF, prefer gog_drive_extract_text.",
|
|
36409
|
+
description: "Fetch a Drive file's raw bytes and return them base64-encoded as an embedded resource \u2014 the generic fallback for callers that want the file itself (to parse locally) rather than extracted text. Files over 8 MiB are refused (checked before downloading). For readable text from a PDF, prefer gog_drive_extract_text.",
|
|
35691
36410
|
annotations: { readOnlyHint: true },
|
|
35692
36411
|
inputSchema: external_exports.object({
|
|
35693
36412
|
fileId: external_exports.string().describe("Drive file ID"),
|
|
@@ -35695,9 +36414,17 @@ function registerDriveTools(server) {
|
|
|
35695
36414
|
})
|
|
35696
36415
|
}, async ({ fileId, account }) => {
|
|
35697
36416
|
try {
|
|
35698
|
-
const { name, mimeType } = fileMeta(await run(["drive", "get", fileId], { account }));
|
|
36417
|
+
const { name, mimeType, size } = fileMeta(await run(["drive", "get", pos(fileId)], { account }));
|
|
36418
|
+
if (size !== void 0 && size > MAX_DRIVE_READ_BYTES) {
|
|
36419
|
+
return errorResult(
|
|
36420
|
+
`${name ?? fileId} is ${size} bytes, over the 8 MiB this tool returns inline. Use gog_drive_extract_text for its text, or share its webViewLink (gog_drive_get) instead.`
|
|
36421
|
+
);
|
|
36422
|
+
}
|
|
35699
36423
|
const params = JSON.stringify({ fileId, alt: "media" });
|
|
35700
|
-
const blob = await runBinary(
|
|
36424
|
+
const blob = await runBinary(
|
|
36425
|
+
["api", "call", "drive", "v3", "files.get", `--params=${params}`],
|
|
36426
|
+
{ account, maxOutputBytes: MAX_DRIVE_READ_BYTES }
|
|
36427
|
+
);
|
|
35701
36428
|
const type = mimeType ?? "application/octet-stream";
|
|
35702
36429
|
const unrenderableHint = type.startsWith("image/") ? "" : ` If your client does not render a ${type} resource, gog_drive_extract_text returns the same file as text (PDFs included, via OCR).`;
|
|
35703
36430
|
return {
|
|
@@ -35717,7 +36444,7 @@ function registerDriveTools(server) {
|
|
|
35717
36444
|
return diagnose(err);
|
|
35718
36445
|
}
|
|
35719
36446
|
});
|
|
35720
|
-
registerRunTool(server, { service: "drive", examples: '"copy", "
|
|
36447
|
+
registerRunTool(server, { service: "drive", examples: '"copy", "download", "permissions"', vet: vetDriveRun });
|
|
35721
36448
|
}
|
|
35722
36449
|
|
|
35723
36450
|
// ../gogcli-mcp/src/tools/gmail.ts
|
|
@@ -35732,7 +36459,7 @@ var replySchema = {
|
|
|
35732
36459
|
remove: external_exports.array(external_exports.string()).optional().describe("Remove these recipients from all fields (repeatable) \u2014 e.g. to drop someone from a reply-all."),
|
|
35733
36460
|
subject: external_exports.string().optional().describe('Override reply subject (default: "Re: <original>"). A changed subject starts a NEW Gmail thread.'),
|
|
35734
36461
|
noQuote: external_exports.boolean().optional().describe("Do not include the original message quoted below the reply (default: the original is quoted)"),
|
|
35735
|
-
attach: external_exports.array(external_exports.string()).optional().describe(`File paths to attach (repeatable), resolved ON THE GOG SERVER's filesystem \u2014 NOT this client's. Only usable when gog runs on the same machine you do (local stdio); on a hosted deployment (e.g. mcp-host) these paths do not exist and the call fails with "no such file or directory" \u2014 use attachInline there. Read on the server, base64-encoded with a MIME type inferred from the extension.`),
|
|
36462
|
+
attach: external_exports.array(external_exports.string()).optional().describe(`File paths to attach (repeatable), resolved ON THE GOG SERVER's filesystem \u2014 NOT this client's. Only usable when gog runs on the same machine you do (local stdio); on a hosted deployment (e.g. mcp-host) these paths do not exist and the call fails with "no such file or directory" \u2014 use attachInline there. Read on the server, base64-encoded with a MIME type inferred from the extension. Must be inside the server's GOG_FILE_ROOTS directories (default ~/gogcli-mcp-files).`),
|
|
35736
36463
|
attachInline: attachInlineParam,
|
|
35737
36464
|
from: external_exports.string().optional().describe("Send from this email address (must be a verified send-as alias)"),
|
|
35738
36465
|
autoFromAddressedAlias: external_exports.boolean().optional().describe("When from is omitted, send from the verified send-as alias the original message was addressed TO, instead of the account's primary address \u2014 so a reply to mail sent to an alias goes back out from that alias. Ignored when from is set."),
|
|
@@ -35741,7 +36468,7 @@ var replySchema = {
|
|
|
35741
36468
|
signatureFile: external_exports.string().optional().describe("Append a local signature file (plain text or HTML), read on the gog server"),
|
|
35742
36469
|
account: accountParam
|
|
35743
36470
|
};
|
|
35744
|
-
var sendReplySchema = external_exports.object(replySchema);
|
|
36471
|
+
var sendReplySchema = external_exports.object({ ...replySchema, confirmToken: confirmTokenParam });
|
|
35745
36472
|
|
|
35746
36473
|
// ../gogcli-mcp/src/tools/sheets.ts
|
|
35747
36474
|
var cellValueParam = external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean(), external_exports.null()]);
|
|
@@ -35753,10 +36480,10 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
|
|
|
35753
36480
|
);
|
|
35754
36481
|
|
|
35755
36482
|
// ../gogcli-mcp/src/server.ts
|
|
35756
|
-
var VERSION = true ? "4.
|
|
36483
|
+
var VERSION = true ? "4.4.0" : "0.0.0";
|
|
35757
36484
|
|
|
35758
36485
|
// ../gogcli-mcp/src/bootstrap-auth.ts
|
|
35759
|
-
import { join as
|
|
36486
|
+
import { join as join5 } from "node:path";
|
|
35760
36487
|
var AUTH_BOOTSTRAP_MARKER = "auth-bootstrap.sha256";
|
|
35761
36488
|
var VARS = ["GOG_CLIENT_ID", "GOG_CLIENT_SECRET", "GOG_REFRESH_TOKEN", "GOG_ACCOUNT"];
|
|
35762
36489
|
var log = (line) => {
|
|
@@ -35790,12 +36517,12 @@ async function bootstrapGogAuth(env = process.env, options = {}) {
|
|
|
35790
36517
|
const [clientId, clientSecret, refreshToken, account] = values;
|
|
35791
36518
|
const { spawner } = options;
|
|
35792
36519
|
try {
|
|
35793
|
-
const { createHash } = await import("node:crypto");
|
|
36520
|
+
const { createHash: createHash3 } = await import("node:crypto");
|
|
35794
36521
|
const { mkdir, readFile, writeFile, chmod } = await import("node:fs/promises");
|
|
35795
36522
|
const home = options.home ?? (await import("node:os")).homedir();
|
|
35796
|
-
const dir =
|
|
35797
|
-
const marker =
|
|
35798
|
-
const fingerprint =
|
|
36523
|
+
const dir = join5(home, ".gogcli-mcp");
|
|
36524
|
+
const marker = join5(dir, AUTH_BOOTSTRAP_MARKER);
|
|
36525
|
+
const fingerprint = createHash3("sha256").update(values.join("\0")).digest("hex");
|
|
35799
36526
|
const previous = await readFile(marker, "utf8").catch(() => void 0);
|
|
35800
36527
|
if (previous === fingerprint && await accountListed(account, spawner)) return "present";
|
|
35801
36528
|
await run(
|
|
@@ -35831,7 +36558,8 @@ var MAX_BLOB_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
|
35831
36558
|
function registerExtraDriveTools(server) {
|
|
35832
36559
|
server.registerTool("gog_drive_download", {
|
|
35833
36560
|
description: "Download a Drive file to the local filesystem. For Google Docs formats, specify an export format (pdf, csv, xlsx, pptx, txt, png, docx, md).",
|
|
35834
|
-
|
|
36561
|
+
// Writes a file on the gog host and can overwrite one: not read-only (audit SEC-4).
|
|
36562
|
+
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
35835
36563
|
inputSchema: external_exports.object({
|
|
35836
36564
|
fileId: external_exports.string().describe("File ID to download"),
|
|
35837
36565
|
out: external_exports.string().optional().describe("Output file path (default: gogcli config dir)"),
|
|
@@ -35840,7 +36568,8 @@ function registerExtraDriveTools(server) {
|
|
|
35840
36568
|
account: accountParam
|
|
35841
36569
|
})
|
|
35842
36570
|
}, async ({ fileId, out, format, overwrite, account }) => {
|
|
35843
|
-
|
|
36571
|
+
if (out) confinePath(out, "out");
|
|
36572
|
+
const args = ["drive", "download", pos(fileId)];
|
|
35844
36573
|
if (out) args.push(`--out=${out}`);
|
|
35845
36574
|
if (format) args.push(`--format=${format}`);
|
|
35846
36575
|
if (overwrite) args.push("--overwrite");
|
|
@@ -35850,7 +36579,7 @@ function registerExtraDriveTools(server) {
|
|
|
35850
36579
|
description: `Upload a file to Drive. Supply it EITHER as localPath (a path on the gog server's own filesystem \u2014 local stdio deployments only) OR as content (the bytes, base64-encoded, carried with the request), which is what works when this server runs remotely from you and no path you can name exists on it. Use replace to replace the content of an existing file (preserves link/permissions), or convert to auto-convert to a Google format. Pair replace with ifVersion to make the overwrite conditional: gog sends an atomic If-Match precondition and reports a conflict \u2014 applying nothing \u2014 if the file changed since you read it, instead of silently clobbering a concurrent edit. No read tool surfaces the version number: fetch it immediately before uploading with gog_drive_run { subcommand: "raw", args: ["<fileId>", "--fields=version"] } \u2014 it comes back as a JSON string, so pass it on as a number. Conditional replacement refuses Google Workspace files (Docs/Sheets/Slides), which have no replaceable binary content.`,
|
|
35851
36580
|
annotations: { destructiveHint: false },
|
|
35852
36581
|
inputSchema: external_exports.object({
|
|
35853
|
-
localPath: external_exports.string().optional().describe(`Path to the file to upload, resolved ON THE GOG SERVER's filesystem \u2014 NOT this client's. Only usable when gog runs on the same machine you do (local stdio); on a hosted deployment (e.g. mcp-host) this path does not exist and the call fails with "no such file or directory" \u2014 use content there. Exactly one of localPath / content is required.`),
|
|
36582
|
+
localPath: external_exports.string().optional().describe(`Path to the file to upload, resolved ON THE GOG SERVER's filesystem \u2014 NOT this client's. Only usable when gog runs on the same machine you do (local stdio); on a hosted deployment (e.g. mcp-host) this path does not exist and the call fails with "no such file or directory" \u2014 use content there. Exactly one of localPath / content is required. Must be inside the server's GOG_FILE_ROOTS directories (default ~/gogcli-mcp-files).`),
|
|
35854
36583
|
content: external_exports.string().optional().describe("The file's bytes, base64-encoded (standard alphabet, with padding) \u2014 upload a file you hold without it existing anywhere on the gog server. This is the only route that works when the caller and gog share no filesystem. Requires name (there is no path to take a filename from). Max 8 MiB; for anything larger use localPath from a local deployment. Exactly one of localPath / content is required \u2014 supplying both is an error, not a precedence rule."),
|
|
35855
36584
|
name: external_exports.string().optional().describe("Override filename (create) or rename target (replace)"),
|
|
35856
36585
|
parent: external_exports.string().optional().describe("Destination folder ID (create only)"),
|
|
@@ -35875,7 +36604,7 @@ function registerExtraDriveTools(server) {
|
|
|
35875
36604
|
}
|
|
35876
36605
|
let pathArg;
|
|
35877
36606
|
if (localPath !== void 0) {
|
|
35878
|
-
pathArg = localPath;
|
|
36607
|
+
pathArg = confinePath(localPath, "localPath");
|
|
35879
36608
|
} else {
|
|
35880
36609
|
if (!name) {
|
|
35881
36610
|
throw new Error("content requires name: there is no path to derive the Drive filename from.");
|
|
@@ -35886,7 +36615,7 @@ function registerExtraDriveTools(server) {
|
|
|
35886
36615
|
{ positional: true, where: "content" }
|
|
35887
36616
|
).arg;
|
|
35888
36617
|
}
|
|
35889
|
-
const args = ["drive", "upload", pathArg];
|
|
36618
|
+
const args = ["drive", "upload", typeof pathArg === "string" ? pos(pathArg) : pathArg];
|
|
35890
36619
|
if (name) args.push(`--name=${name}`);
|
|
35891
36620
|
if (parent) args.push(`--parent=${parent}`);
|
|
35892
36621
|
if (replace) args.push(`--replace=${replace}`);
|
|
@@ -35901,14 +36630,15 @@ function registerExtraDriveTools(server) {
|
|
|
35901
36630
|
description: "Recursively push a local directory's contents into an existing Drive folder \u2014 uploads new files, updates changed ones (matched by name + MD5), and creates missing subfolders. One-way and additive: it never deletes anything on Drive. Use dryRun to preview the planned actions first.",
|
|
35902
36631
|
annotations: { destructiveHint: true },
|
|
35903
36632
|
inputSchema: external_exports.object({
|
|
35904
|
-
localPath: external_exports.string().describe("Local directory to push (its contents are mirrored into the parent folder)"),
|
|
36633
|
+
localPath: external_exports.string().describe("Local directory to push (its contents are mirrored into the parent folder). Must be inside the server's GOG_FILE_ROOTS directories (default ~/gogcli-mcp-files)."),
|
|
35905
36634
|
parent: external_exports.string().describe("Existing destination Drive folder ID"),
|
|
35906
36635
|
dryRun: external_exports.boolean().optional().describe("Preview the planned actions without making any changes"),
|
|
35907
36636
|
allDrives: external_exports.boolean().optional().describe("Include shared drives (default: true; set false for My Drive only)"),
|
|
35908
36637
|
account: accountParam
|
|
35909
36638
|
})
|
|
35910
36639
|
}, async ({ localPath, parent, dryRun, allDrives, account }) => {
|
|
35911
|
-
|
|
36640
|
+
confinePath(localPath, "localPath");
|
|
36641
|
+
const args = ["drive", "sync", "push", pos(localPath), `--parent=${parent}`];
|
|
35912
36642
|
if (dryRun) args.push("--dry-run");
|
|
35913
36643
|
if (allDrives === false) args.push("--no-all-drives");
|
|
35914
36644
|
return runOrDiagnose(args, { account });
|
|
@@ -35923,7 +36653,7 @@ function registerExtraDriveTools(server) {
|
|
|
35923
36653
|
account: accountParam
|
|
35924
36654
|
})
|
|
35925
36655
|
}, async ({ fileId, name, parent, account }) => {
|
|
35926
|
-
const args = ["drive", "copy", fileId, name];
|
|
36656
|
+
const args = ["drive", "copy", pos(fileId), pos(name)];
|
|
35927
36657
|
if (parent) args.push(`--parent=${parent}`);
|
|
35928
36658
|
return runOrDiagnose(args, { account });
|
|
35929
36659
|
});
|
|
@@ -35935,7 +36665,7 @@ function registerExtraDriveTools(server) {
|
|
|
35935
36665
|
account: accountParam
|
|
35936
36666
|
})
|
|
35937
36667
|
}, async ({ fileIds, account }) => {
|
|
35938
|
-
return runOrDiagnose(["drive", "url", ...fileIds], { account });
|
|
36668
|
+
return runOrDiagnose(["drive", "url", ...fileIds.map(pos)], { account });
|
|
35939
36669
|
});
|
|
35940
36670
|
server.registerTool("gog_drive_permissions", {
|
|
35941
36671
|
description: "List permissions on a Drive file.",
|
|
@@ -35948,7 +36678,7 @@ function registerExtraDriveTools(server) {
|
|
|
35948
36678
|
account: accountParam
|
|
35949
36679
|
})
|
|
35950
36680
|
}, async ({ fileId, max, pageToken, page, account }) => {
|
|
35951
|
-
const args = ["drive", "permissions", fileId];
|
|
36681
|
+
const args = ["drive", "permissions", pos(fileId)];
|
|
35952
36682
|
if (max !== void 0) args.push(`--max=${max}`);
|
|
35953
36683
|
const token = resolvePageToken({ pageToken, page });
|
|
35954
36684
|
if (token) args.push(`--page=${token}`);
|
|
@@ -35963,7 +36693,7 @@ function registerExtraDriveTools(server) {
|
|
|
35963
36693
|
account: accountParam
|
|
35964
36694
|
})
|
|
35965
36695
|
}, async ({ fileId, permissionId, account }) => {
|
|
35966
|
-
return runOrDiagnose(["drive", "unshare", fileId, permissionId, "--force"], { account });
|
|
36696
|
+
return runOrDiagnose(["drive", "unshare", pos(fileId), pos(permissionId), "--force"], { account });
|
|
35967
36697
|
});
|
|
35968
36698
|
server.registerTool("gog_drive_drives_list", {
|
|
35969
36699
|
description: "List shared drives (Team Drives) accessible to the account.",
|
|
@@ -35996,7 +36726,7 @@ function registerExtraDriveTools(server) {
|
|
|
35996
36726
|
account: accountParam
|
|
35997
36727
|
})
|
|
35998
36728
|
}, async ({ fileId, since, includeQuoted, max, page, all, account }) => {
|
|
35999
|
-
const args = ["drive", "comments", "list", fileId];
|
|
36729
|
+
const args = ["drive", "comments", "list", pos(fileId)];
|
|
36000
36730
|
if (since) args.push(`--since=${since}`);
|
|
36001
36731
|
if (includeQuoted) args.push("--include-quoted");
|
|
36002
36732
|
pushPaginationFlags(args, { max, page, all });
|
|
@@ -36011,7 +36741,7 @@ function registerExtraDriveTools(server) {
|
|
|
36011
36741
|
account: accountParam
|
|
36012
36742
|
})
|
|
36013
36743
|
}, async ({ fileId, commentId, account }) => {
|
|
36014
|
-
return runOrDiagnose(["drive", "comments", "get", fileId, commentId], { account });
|
|
36744
|
+
return runOrDiagnose(["drive", "comments", "get", pos(fileId), pos(commentId)], { account });
|
|
36015
36745
|
});
|
|
36016
36746
|
server.registerTool("gog_drive_comments_add", {
|
|
36017
36747
|
description: "Add a new comment to a Drive file.",
|
|
@@ -36022,7 +36752,7 @@ function registerExtraDriveTools(server) {
|
|
|
36022
36752
|
account: accountParam
|
|
36023
36753
|
})
|
|
36024
36754
|
}, async ({ fileId, content, account }) => {
|
|
36025
|
-
return runOrDiagnose(["drive", "comments", "create", fileId, content], { account });
|
|
36755
|
+
return runOrDiagnose(["drive", "comments", "create", pos(fileId), pos(content)], { account });
|
|
36026
36756
|
});
|
|
36027
36757
|
server.registerTool("gog_drive_comments_update", {
|
|
36028
36758
|
description: "Update the text of an existing comment.",
|
|
@@ -36034,7 +36764,7 @@ function registerExtraDriveTools(server) {
|
|
|
36034
36764
|
account: accountParam
|
|
36035
36765
|
})
|
|
36036
36766
|
}, async ({ fileId, commentId, content, account }) => {
|
|
36037
|
-
return runOrDiagnose(["drive", "comments", "update", fileId, commentId, content], { account });
|
|
36767
|
+
return runOrDiagnose(["drive", "comments", "update", pos(fileId), pos(commentId), pos(content)], { account });
|
|
36038
36768
|
});
|
|
36039
36769
|
server.registerTool("gog_drive_comments_delete", {
|
|
36040
36770
|
description: "Delete a comment from a Drive file.",
|
|
@@ -36045,7 +36775,7 @@ function registerExtraDriveTools(server) {
|
|
|
36045
36775
|
account: accountParam
|
|
36046
36776
|
})
|
|
36047
36777
|
}, async ({ fileId, commentId, account }) => {
|
|
36048
|
-
return runOrDiagnose(["drive", "comments", "delete", fileId, commentId, "--force"], { account });
|
|
36778
|
+
return runOrDiagnose(["drive", "comments", "delete", pos(fileId), pos(commentId), "--force"], { account });
|
|
36049
36779
|
});
|
|
36050
36780
|
server.registerTool("gog_drive_comments_reply", {
|
|
36051
36781
|
description: 'Reply to an existing comment on a Drive file. Pass `action: "resolve"` or `"reopen"` to atomically flip the parent comment\'s resolved state via the Drive API\'s Reply.action field \u2014 avoids the older workaround of deleting the comment (which destroys review-thread context).',
|
|
@@ -36058,7 +36788,7 @@ function registerExtraDriveTools(server) {
|
|
|
36058
36788
|
account: accountParam
|
|
36059
36789
|
})
|
|
36060
36790
|
}, async ({ fileId, commentId, content, action, account }) => {
|
|
36061
|
-
const args = ["drive", "comments", "reply", fileId, commentId, content];
|
|
36791
|
+
const args = ["drive", "comments", "reply", pos(fileId), pos(commentId), pos(content)];
|
|
36062
36792
|
if (action) args.push(`--action=${action}`);
|
|
36063
36793
|
return runOrDiagnose(args, { account });
|
|
36064
36794
|
});
|
|
@@ -36071,7 +36801,7 @@ function registerExtraDriveTools(server) {
|
|
|
36071
36801
|
account: accountParam
|
|
36072
36802
|
})
|
|
36073
36803
|
}, async ({ fileId, commentId, account }) => {
|
|
36074
|
-
return runOrDiagnose(["drive", "comments", "resolve", fileId, commentId], { account });
|
|
36804
|
+
return runOrDiagnose(["drive", "comments", "resolve", pos(fileId), pos(commentId)], { account });
|
|
36075
36805
|
});
|
|
36076
36806
|
server.registerTool("gog_drive_comments_reopen", {
|
|
36077
36807
|
description: 'Reopen a previously resolved comment on a Drive file. To reopen while replying, use gog_drive_comments_reply with action: "reopen".',
|
|
@@ -36082,7 +36812,7 @@ function registerExtraDriveTools(server) {
|
|
|
36082
36812
|
account: accountParam
|
|
36083
36813
|
})
|
|
36084
36814
|
}, async ({ fileId, commentId, account }) => {
|
|
36085
|
-
return runOrDiagnose(["drive", "comments", "reopen", fileId, commentId], { account });
|
|
36815
|
+
return runOrDiagnose(["drive", "comments", "reopen", pos(fileId), pos(commentId)], { account });
|
|
36086
36816
|
});
|
|
36087
36817
|
server.registerTool("gog_drive_du", {
|
|
36088
36818
|
description: "Summarize Drive folder sizes (disk-usage style) starting from a folder.",
|
|
@@ -36168,7 +36898,7 @@ function registerExtraDriveTools(server) {
|
|
|
36168
36898
|
account: accountParam
|
|
36169
36899
|
})
|
|
36170
36900
|
}, async ({ fileId, max, page, all, account }) => {
|
|
36171
|
-
const args = ["drive", "revisions", "list", fileId];
|
|
36901
|
+
const args = ["drive", "revisions", "list", pos(fileId)];
|
|
36172
36902
|
pushPaginationFlags(args, { max, page, all });
|
|
36173
36903
|
return runOrDiagnose(args, { account });
|
|
36174
36904
|
});
|
|
@@ -36181,7 +36911,7 @@ function registerExtraDriveTools(server) {
|
|
|
36181
36911
|
account: accountParam
|
|
36182
36912
|
})
|
|
36183
36913
|
}, async ({ fileId, revisionId, account }) => {
|
|
36184
|
-
return runOrDiagnose(["drive", "revisions", "get", fileId, revisionId], { account });
|
|
36914
|
+
return runOrDiagnose(["drive", "revisions", "get", pos(fileId), pos(revisionId)], { account });
|
|
36185
36915
|
});
|
|
36186
36916
|
server.registerTool("gog_drive_shortcut_create", {
|
|
36187
36917
|
description: "Create a Drive shortcut to a file or folder inside a destination folder. Shortcuts are classified distinctly in listing/tree output and are never followed by tree scans.",
|
|
@@ -36193,7 +36923,7 @@ function registerExtraDriveTools(server) {
|
|
|
36193
36923
|
account: accountParam
|
|
36194
36924
|
})
|
|
36195
36925
|
}, async ({ targetId, parent, name, account }) => {
|
|
36196
|
-
const args = ["drive", "shortcut", "create", targetId, `--parent=${parent}`];
|
|
36926
|
+
const args = ["drive", "shortcut", "create", pos(targetId), `--parent=${parent}`];
|
|
36197
36927
|
if (name) args.push(`--name=${name}`);
|
|
36198
36928
|
return runOrDiagnose(args, { account });
|
|
36199
36929
|
});
|
|
@@ -36234,7 +36964,7 @@ function registerExtraDriveTools(server) {
|
|
|
36234
36964
|
account: accountParam
|
|
36235
36965
|
})
|
|
36236
36966
|
}, async ({ name, language, view, adminAccess, account }) => {
|
|
36237
|
-
const args = ["drive", "labels", "get", name];
|
|
36967
|
+
const args = ["drive", "labels", "get", pos(name)];
|
|
36238
36968
|
if (language) args.push(`--language=${language}`);
|
|
36239
36969
|
if (view) args.push(`--view=${view}`);
|
|
36240
36970
|
if (adminAccess) args.push("--admin-access");
|
|
@@ -36251,7 +36981,7 @@ function registerExtraDriveTools(server) {
|
|
|
36251
36981
|
account: accountParam
|
|
36252
36982
|
})
|
|
36253
36983
|
}, async ({ fileId, max, pageToken, page, account }) => {
|
|
36254
|
-
const args = ["drive", "labels", "file", "list", fileId];
|
|
36984
|
+
const args = ["drive", "labels", "file", "list", pos(fileId)];
|
|
36255
36985
|
if (max !== void 0) args.push(`--max=${max}`);
|
|
36256
36986
|
const token = resolvePageToken({ pageToken, page });
|
|
36257
36987
|
if (token) args.push(`--page=${token}`);
|
|
@@ -36273,7 +37003,7 @@ function registerExtraDriveTools(server) {
|
|
|
36273
37003
|
account: accountParam
|
|
36274
37004
|
})
|
|
36275
37005
|
}, async ({ fileId, labelId, text, selection, integer: integer2, date: date5, user, unset, fieldsJson, account }) => {
|
|
36276
|
-
const args = ["drive", "labels", "file", "apply", fileId, labelId];
|
|
37006
|
+
const args = ["drive", "labels", "file", "apply", pos(fileId), pos(labelId)];
|
|
36277
37007
|
if (text) for (const t of text) args.push(`--text=${t}`);
|
|
36278
37008
|
if (selection) for (const s of selection) args.push(`--selection=${s}`);
|
|
36279
37009
|
if (integer2) for (const i of integer2) args.push(`--integer=${i}`);
|
|
@@ -36292,7 +37022,7 @@ function registerExtraDriveTools(server) {
|
|
|
36292
37022
|
account: accountParam
|
|
36293
37023
|
})
|
|
36294
37024
|
}, async ({ fileId, labelId, account }) => {
|
|
36295
|
-
return runOrDiagnose(["drive", "labels", "file", "remove", fileId, labelId, "--force"], { account });
|
|
37025
|
+
return runOrDiagnose(["drive", "labels", "file", "remove", pos(fileId), pos(labelId), "--force"], { account });
|
|
36296
37026
|
});
|
|
36297
37027
|
server.registerTool("gog_drive_activity", {
|
|
36298
37028
|
description: "Query the Drive Activity API for audit events (edits, creates, deletes, moves, shares, etc.) scoped to a file or folder and/or time range.",
|
|
@@ -36365,7 +37095,7 @@ function registerExtraDriveTools(server) {
|
|
|
36365
37095
|
account: accountParam
|
|
36366
37096
|
})
|
|
36367
37097
|
}, async ({ user, file: file2, parent, depth, max, noAllDrives, account }) => {
|
|
36368
|
-
const args = ["drive", "audit", "user", user];
|
|
37098
|
+
const args = ["drive", "audit", "user", pos(user)];
|
|
36369
37099
|
if (file2) args.push(`--file=${file2}`);
|
|
36370
37100
|
if (parent) args.push(`--parent=${parent}`);
|
|
36371
37101
|
if (depth !== void 0) args.push(`--depth=${depth}`);
|