gogcli-mcp-drive 4.2.5 → 4.3.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 +441 -127
- 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
|
@@ -2092,8 +2092,8 @@ function emoji() {
|
|
|
2092
2092
|
}
|
|
2093
2093
|
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
2094
|
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(
|
|
2095
|
+
var mac = (delimiter3) => {
|
|
2096
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
2097
2097
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
2098
2098
|
};
|
|
2099
2099
|
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 +5121,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5121
5121
|
var NONE = 0;
|
|
5122
5122
|
var ASSUMED = 1;
|
|
5123
5123
|
var PROVEN = 2;
|
|
5124
|
-
function isRecursive(inst, stack,
|
|
5124
|
+
function isRecursive(inst, stack, resolve4) {
|
|
5125
5125
|
const cached2 = recursive.get(inst);
|
|
5126
5126
|
if (cached2 !== void 0)
|
|
5127
5127
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5131,7 +5131,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5131
5131
|
let result = NONE;
|
|
5132
5132
|
const check2 = (child) => {
|
|
5133
5133
|
if (result !== PROVEN && child?._zod) {
|
|
5134
|
-
const answer = isRecursive(child, stack,
|
|
5134
|
+
const answer = isRecursive(child, stack, resolve4);
|
|
5135
5135
|
if (answer > result)
|
|
5136
5136
|
result = answer;
|
|
5137
5137
|
}
|
|
@@ -5142,7 +5142,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5142
5142
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5143
5143
|
if (spread && !desc.enumerable)
|
|
5144
5144
|
continue;
|
|
5145
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5145
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve4) : NONE;
|
|
5146
5146
|
if (child > answer)
|
|
5147
5147
|
answer = child;
|
|
5148
5148
|
}
|
|
@@ -5206,7 +5206,7 @@ function isRecursive(inst, stack, resolve) {
|
|
|
5206
5206
|
break;
|
|
5207
5207
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5208
5208
|
case "lazy": {
|
|
5209
|
-
const inner = def._cachedInner ?? (
|
|
5209
|
+
const inner = def._cachedInner ?? (resolve4 ? inst._zod.innerType : void 0);
|
|
5210
5210
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5211
5211
|
break;
|
|
5212
5212
|
}
|
|
@@ -24106,14 +24106,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
|
24106
24106
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
24107
24107
|
}
|
|
24108
24108
|
function sleep(ms, signal) {
|
|
24109
|
-
return new Promise((
|
|
24109
|
+
return new Promise((resolve4, reject) => {
|
|
24110
24110
|
if (signal?.aborted) {
|
|
24111
24111
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
24112
24112
|
return;
|
|
24113
24113
|
}
|
|
24114
24114
|
const timer = setTimeout(() => {
|
|
24115
24115
|
signal?.removeEventListener("abort", onAbort);
|
|
24116
|
-
|
|
24116
|
+
resolve4();
|
|
24117
24117
|
}, ms);
|
|
24118
24118
|
const onAbort = () => {
|
|
24119
24119
|
clearTimeout(timer);
|
|
@@ -24907,7 +24907,7 @@ var Protocol = class {
|
|
|
24907
24907
|
const flowStartedAt = Date.now();
|
|
24908
24908
|
let onAbort;
|
|
24909
24909
|
let cleanupMessageId;
|
|
24910
|
-
return new Promise((
|
|
24910
|
+
return new Promise((resolve4, reject) => {
|
|
24911
24911
|
const earlyReject = (error62) => {
|
|
24912
24912
|
reject(error62);
|
|
24913
24913
|
};
|
|
@@ -24975,7 +24975,7 @@ var Protocol = class {
|
|
|
24975
24975
|
}
|
|
24976
24976
|
if (decoded.kind === "invalid") return reject(decoded.error);
|
|
24977
24977
|
if (decoded.kind === "input_required") {
|
|
24978
|
-
if (options?.allowInputRequired === true) return
|
|
24978
|
+
if (options?.allowInputRequired === true) return resolve4(manualInputRequiredValue(decoded));
|
|
24979
24979
|
const flow = {
|
|
24980
24980
|
codec: codec2,
|
|
24981
24981
|
request,
|
|
@@ -24987,11 +24987,11 @@ var Protocol = class {
|
|
|
24987
24987
|
params
|
|
24988
24988
|
}, resultSchema, legOptions)
|
|
24989
24989
|
};
|
|
24990
|
-
return
|
|
24990
|
+
return resolve4(this._resolveNonCompleteResult(decoded, flow));
|
|
24991
24991
|
}
|
|
24992
24992
|
const result = decoded.result;
|
|
24993
24993
|
validateStandardSchema(resultSchema, result).then((parseResult) => {
|
|
24994
|
-
if (parseResult.success)
|
|
24994
|
+
if (parseResult.success) resolve4(parseResult.data);
|
|
24995
24995
|
else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
24996
24996
|
}, reject);
|
|
24997
24997
|
});
|
|
@@ -27903,7 +27903,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27903
27903
|
ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
|
|
27904
27904
|
const schOrFunc = root.refs[ref];
|
|
27905
27905
|
if (schOrFunc) return schOrFunc;
|
|
27906
|
-
let _sch =
|
|
27906
|
+
let _sch = resolve4.call(this, root, ref);
|
|
27907
27907
|
if (_sch === void 0) {
|
|
27908
27908
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
27909
27909
|
const { schemaId } = this.opts;
|
|
@@ -27929,7 +27929,7 @@ var require_compile = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
27929
27929
|
function sameSchemaEnv(s1, s2) {
|
|
27930
27930
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
27931
27931
|
}
|
|
27932
|
-
function
|
|
27932
|
+
function resolve4(root, ref) {
|
|
27933
27933
|
let sch;
|
|
27934
27934
|
while (typeof (sch = this.refs[ref]) == "string") ref = sch;
|
|
27935
27935
|
return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
|
@@ -28379,47 +28379,47 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28379
28379
|
else if (typeof uri === "object") uri = parse3(serialize(uri, options), options);
|
|
28380
28380
|
return uri;
|
|
28381
28381
|
}
|
|
28382
|
-
function
|
|
28382
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
28383
28383
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
28384
28384
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
28385
28385
|
schemelessOptions.skipEscape = true;
|
|
28386
28386
|
return serialize(resolved, schemelessOptions);
|
|
28387
28387
|
}
|
|
28388
|
-
function resolveComponent(base,
|
|
28388
|
+
function resolveComponent(base, relative3, options, skipNormalization) {
|
|
28389
28389
|
const target = {};
|
|
28390
28390
|
if (!skipNormalization) {
|
|
28391
28391
|
base = parse3(serialize(base, options), options);
|
|
28392
|
-
|
|
28392
|
+
relative3 = parse3(serialize(relative3, options), options);
|
|
28393
28393
|
}
|
|
28394
28394
|
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 =
|
|
28395
|
+
if (!options.tolerant && relative3.scheme) {
|
|
28396
|
+
target.scheme = relative3.scheme;
|
|
28397
|
+
target.userinfo = relative3.userinfo;
|
|
28398
|
+
target.host = relative3.host;
|
|
28399
|
+
target.port = relative3.port;
|
|
28400
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
28401
|
+
target.query = relative3.query;
|
|
28402
28402
|
} else {
|
|
28403
|
-
if (
|
|
28404
|
-
target.userinfo =
|
|
28405
|
-
target.host =
|
|
28406
|
-
target.port =
|
|
28407
|
-
target.path = removeDotSegments(
|
|
28408
|
-
target.query =
|
|
28403
|
+
if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
|
|
28404
|
+
target.userinfo = relative3.userinfo;
|
|
28405
|
+
target.host = relative3.host;
|
|
28406
|
+
target.port = relative3.port;
|
|
28407
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
28408
|
+
target.query = relative3.query;
|
|
28409
28409
|
} else {
|
|
28410
|
-
if (!
|
|
28410
|
+
if (!relative3.path) {
|
|
28411
28411
|
target.path = base.path;
|
|
28412
|
-
if (
|
|
28412
|
+
if (relative3.query !== void 0) target.query = relative3.query;
|
|
28413
28413
|
else target.query = base.query;
|
|
28414
28414
|
} else {
|
|
28415
|
-
if (
|
|
28415
|
+
if (relative3.path[0] === "/") target.path = removeDotSegments(relative3.path);
|
|
28416
28416
|
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) +
|
|
28417
|
+
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) target.path = "/" + relative3.path;
|
|
28418
|
+
else if (!base.path) target.path = relative3.path;
|
|
28419
|
+
else target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
|
|
28420
28420
|
target.path = removeDotSegments(target.path);
|
|
28421
28421
|
}
|
|
28422
|
-
target.query =
|
|
28422
|
+
target.query = relative3.query;
|
|
28423
28423
|
}
|
|
28424
28424
|
target.userinfo = base.userinfo;
|
|
28425
28425
|
target.host = base.host;
|
|
@@ -28427,7 +28427,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28427
28427
|
}
|
|
28428
28428
|
target.scheme = base.scheme;
|
|
28429
28429
|
}
|
|
28430
|
-
target.fragment =
|
|
28430
|
+
target.fragment = relative3.fragment;
|
|
28431
28431
|
return target;
|
|
28432
28432
|
}
|
|
28433
28433
|
function equal(uriA, uriB, options) {
|
|
@@ -28553,7 +28553,7 @@ var require_fast_uri = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
28553
28553
|
const fastUri = {
|
|
28554
28554
|
SCHEMES,
|
|
28555
28555
|
normalize,
|
|
28556
|
-
resolve,
|
|
28556
|
+
resolve: resolve4,
|
|
28557
28557
|
resolveComponent,
|
|
28558
28558
|
equal,
|
|
28559
28559
|
serialize,
|
|
@@ -29335,14 +29335,14 @@ var require_ucs2length = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
29335
29335
|
function ucs2length(str) {
|
|
29336
29336
|
const len = str.length;
|
|
29337
29337
|
let length = 0;
|
|
29338
|
-
let
|
|
29338
|
+
let pos2 = 0;
|
|
29339
29339
|
let value;
|
|
29340
|
-
while (
|
|
29340
|
+
while (pos2 < len) {
|
|
29341
29341
|
length++;
|
|
29342
|
-
value = str.charCodeAt(
|
|
29343
|
-
if (value >= 55296 && value <= 56319 &&
|
|
29344
|
-
value = str.charCodeAt(
|
|
29345
|
-
if ((value & 64512) === 56320)
|
|
29342
|
+
value = str.charCodeAt(pos2++);
|
|
29343
|
+
if (value >= 55296 && value <= 56319 && pos2 < len) {
|
|
29344
|
+
value = str.charCodeAt(pos2);
|
|
29345
|
+
if ((value & 64512) === 56320) pos2++;
|
|
29346
29346
|
}
|
|
29347
29347
|
}
|
|
29348
29348
|
return length;
|
|
@@ -33926,7 +33926,7 @@ var StdioServerTransport = class {
|
|
|
33926
33926
|
}
|
|
33927
33927
|
send(message) {
|
|
33928
33928
|
if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
33929
|
-
return new Promise((
|
|
33929
|
+
return new Promise((resolve4, reject) => {
|
|
33930
33930
|
const json2 = serializeMessage(message);
|
|
33931
33931
|
let settled = false;
|
|
33932
33932
|
const onError = (error62) => {
|
|
@@ -33941,14 +33941,14 @@ var StdioServerTransport = class {
|
|
|
33941
33941
|
settled = true;
|
|
33942
33942
|
this._stdout.off("error", onError);
|
|
33943
33943
|
this._stdout.off("drain", onDrain);
|
|
33944
|
-
|
|
33944
|
+
resolve4();
|
|
33945
33945
|
};
|
|
33946
33946
|
this._stdout.once("error", onError);
|
|
33947
33947
|
if (this._stdout.write(json2)) {
|
|
33948
33948
|
if (settled) return;
|
|
33949
33949
|
settled = true;
|
|
33950
33950
|
this._stdout.off("error", onError);
|
|
33951
|
-
|
|
33951
|
+
resolve4();
|
|
33952
33952
|
} else if (!settled) this._stdout.once("drain", onDrain);
|
|
33953
33953
|
});
|
|
33954
33954
|
}
|
|
@@ -34002,14 +34002,14 @@ var StdioConnectionChannel = class {
|
|
|
34002
34002
|
*/
|
|
34003
34003
|
async whenRequestsAnswered(timeoutMs) {
|
|
34004
34004
|
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
34005
|
-
return await new Promise((
|
|
34005
|
+
return await new Promise((resolve4) => {
|
|
34006
34006
|
const waiter = () => {
|
|
34007
34007
|
clearTimeout(timer);
|
|
34008
|
-
|
|
34008
|
+
resolve4(true);
|
|
34009
34009
|
};
|
|
34010
34010
|
const timer = setTimeout(() => {
|
|
34011
34011
|
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
34012
|
-
|
|
34012
|
+
resolve4(false);
|
|
34013
34013
|
}, timeoutMs);
|
|
34014
34014
|
this._drainWaiters.push(waiter);
|
|
34015
34015
|
});
|
|
@@ -34379,13 +34379,28 @@ var API_KEY_RE = new RegExp([
|
|
|
34379
34379
|
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
34380
34380
|
// webhook signing secret (Stripe-style)
|
|
34381
34381
|
].map((p) => `\\b${p}`).join("|"), "g");
|
|
34382
|
-
var QUERY_SECRET_RE = /([?&](?:
|
|
34382
|
+
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;
|
|
34383
|
+
var OAUTH_CODE_RE = /([?&]code=)(?=[^&#\s"'<>`]{16,})[^&#\s"'<>`]+/gi;
|
|
34384
|
+
var FORM_PASSWORD_RE = /((?:^|[\s,;:"'(\[{])(?:password|passwd)=)[^&#\s"'<>`]+/gim;
|
|
34385
|
+
var HEADER_SECRET_RE = /(\b(?:x[-_][a-z0-9_-]*?(?:api[-_]?key|token|secret|auth)[a-z0-9_-]*|api[-_]?key)\s*:\s*)[^\s,;"'<>`]+/gi;
|
|
34383
34386
|
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
34384
|
-
var JSON_SECRET_KEYS =
|
|
34385
|
-
|
|
34386
|
-
|
|
34387
|
+
var JSON_SECRET_KEYS = [
|
|
34388
|
+
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf)[_-]?token",
|
|
34389
|
+
"client[_-]?secret",
|
|
34390
|
+
"api[_-]?secret",
|
|
34391
|
+
"(?:x[_-])?api[_-]?key",
|
|
34392
|
+
"private[_-]?key",
|
|
34393
|
+
"x[_-][a-z0-9_-]*?(?:api[_-]?key|token|secret|auth)[a-z0-9_-]*",
|
|
34394
|
+
"(?:proxy-)?authorization",
|
|
34395
|
+
"password",
|
|
34396
|
+
"passwd",
|
|
34397
|
+
"secret",
|
|
34398
|
+
"token"
|
|
34399
|
+
].join("|");
|
|
34400
|
+
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")(?:[^"\\\\]|\\\\.)*(")`, "gi");
|
|
34401
|
+
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')(?:[^'\\\\]|\\\\.)*(')`, "gi");
|
|
34387
34402
|
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]");
|
|
34403
|
+
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
34404
|
}
|
|
34390
34405
|
|
|
34391
34406
|
// ../../node_modules/@chrischall/mcp-utils/dist/response/view.js
|
|
@@ -34568,13 +34583,47 @@ async function createMcpServer(opts) {
|
|
|
34568
34583
|
}
|
|
34569
34584
|
return server;
|
|
34570
34585
|
}
|
|
34586
|
+
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
34587
|
+
var DEFAULT_REPEAT_SIGNAL_GRACE_MS = 500;
|
|
34571
34588
|
function withGracefulShutdown(target, opts = {}) {
|
|
34572
34589
|
const shouldExit = opts.exit ?? true;
|
|
34590
|
+
if (opts.timeoutMs !== void 0 && !(Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0)) {
|
|
34591
|
+
throw new RangeError("withGracefulShutdown: timeoutMs must be a finite number greater than 0.");
|
|
34592
|
+
}
|
|
34593
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
34594
|
+
if (opts.repeatSignalGraceMs !== void 0 && !(Number.isFinite(opts.repeatSignalGraceMs) && opts.repeatSignalGraceMs >= 0)) {
|
|
34595
|
+
throw new RangeError("withGracefulShutdown: repeatSignalGraceMs must be a finite number >= 0.");
|
|
34596
|
+
}
|
|
34597
|
+
const repeatGraceMs = opts.repeatSignalGraceMs ?? DEFAULT_REPEAT_SIGNAL_GRACE_MS;
|
|
34573
34598
|
let shuttingDown = false;
|
|
34599
|
+
let firstSignalAt = 0;
|
|
34600
|
+
let exited = false;
|
|
34601
|
+
const exitOnce = () => {
|
|
34602
|
+
if (exited)
|
|
34603
|
+
return;
|
|
34604
|
+
exited = true;
|
|
34605
|
+
process.exit(0);
|
|
34606
|
+
};
|
|
34574
34607
|
const handler = (signal) => {
|
|
34575
|
-
if (shuttingDown)
|
|
34608
|
+
if (shuttingDown) {
|
|
34609
|
+
if (Date.now() - firstSignalAt < repeatGraceMs)
|
|
34610
|
+
return;
|
|
34611
|
+
if (shouldExit) {
|
|
34612
|
+
console.error(`[mcp-utils] second ${signal} during shutdown \u2014 exiting now`);
|
|
34613
|
+
exitOnce();
|
|
34614
|
+
}
|
|
34576
34615
|
return;
|
|
34616
|
+
}
|
|
34577
34617
|
shuttingDown = true;
|
|
34618
|
+
firstSignalAt = Date.now();
|
|
34619
|
+
let timer;
|
|
34620
|
+
if (shouldExit) {
|
|
34621
|
+
timer = setTimeout(() => {
|
|
34622
|
+
console.error(`[mcp-utils] graceful shutdown on ${signal} did not finish in ${timeoutMs}ms \u2014 exiting`);
|
|
34623
|
+
exitOnce();
|
|
34624
|
+
}, timeoutMs);
|
|
34625
|
+
timer.unref?.();
|
|
34626
|
+
}
|
|
34578
34627
|
void (async () => {
|
|
34579
34628
|
try {
|
|
34580
34629
|
if (opts.onSignal)
|
|
@@ -34583,8 +34632,10 @@ function withGracefulShutdown(target, opts = {}) {
|
|
|
34583
34632
|
} catch (err) {
|
|
34584
34633
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
34585
34634
|
} finally {
|
|
34635
|
+
if (timer !== void 0)
|
|
34636
|
+
clearTimeout(timer);
|
|
34586
34637
|
if (shouldExit)
|
|
34587
|
-
|
|
34638
|
+
exitOnce();
|
|
34588
34639
|
}
|
|
34589
34640
|
})();
|
|
34590
34641
|
};
|
|
@@ -34614,6 +34665,8 @@ function runMcp(opts) {
|
|
|
34614
34665
|
}
|
|
34615
34666
|
|
|
34616
34667
|
// ../../node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
34668
|
+
import { homedir } from "node:os";
|
|
34669
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
34617
34670
|
var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
|
|
34618
34671
|
function readEnvVar(key, opts = {}) {
|
|
34619
34672
|
const env = opts.env ?? process.env;
|
|
@@ -34640,6 +34693,50 @@ function parseBoolEnv(key, opts = {}) {
|
|
|
34640
34693
|
return false;
|
|
34641
34694
|
return fallback;
|
|
34642
34695
|
}
|
|
34696
|
+
function expandPath(p) {
|
|
34697
|
+
let expanded = p;
|
|
34698
|
+
if (p === "~") {
|
|
34699
|
+
expanded = homedir();
|
|
34700
|
+
} else if (p.startsWith("~/")) {
|
|
34701
|
+
expanded = join(homedir(), p.slice(2));
|
|
34702
|
+
}
|
|
34703
|
+
return isAbsolute(expanded) ? expanded : resolve(expanded);
|
|
34704
|
+
}
|
|
34705
|
+
|
|
34706
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/fs/confine.js
|
|
34707
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
34708
|
+
import { dirname, isAbsolute as isAbsolute2, relative, resolve as resolve2, sep } from "node:path";
|
|
34709
|
+
function isInside(root, target) {
|
|
34710
|
+
const rel = relative(root, target);
|
|
34711
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute2(rel);
|
|
34712
|
+
}
|
|
34713
|
+
function realPathAllowingMissing(p) {
|
|
34714
|
+
const abs = resolve2(p);
|
|
34715
|
+
let existing = abs;
|
|
34716
|
+
const tail = [];
|
|
34717
|
+
while (!existsSync(existing)) {
|
|
34718
|
+
const parent = dirname(existing);
|
|
34719
|
+
if (parent === existing)
|
|
34720
|
+
break;
|
|
34721
|
+
tail.unshift(existing.slice(parent.length).replace(/^[/\\]+/, ""));
|
|
34722
|
+
existing = parent;
|
|
34723
|
+
}
|
|
34724
|
+
let real;
|
|
34725
|
+
try {
|
|
34726
|
+
real = realpathSync(existing);
|
|
34727
|
+
} catch {
|
|
34728
|
+
real = existing;
|
|
34729
|
+
}
|
|
34730
|
+
return tail.length > 0 ? resolve2(real, ...tail) : real;
|
|
34731
|
+
}
|
|
34732
|
+
function assertPathWithinRoots(path, roots) {
|
|
34733
|
+
const target = realPathAllowingMissing(expandPath(path));
|
|
34734
|
+
for (const root of roots) {
|
|
34735
|
+
if (isInside(realPathAllowingMissing(expandPath(root)), target))
|
|
34736
|
+
return target;
|
|
34737
|
+
}
|
|
34738
|
+
throw new Error(`Path is outside the allowed directories: ${path}`);
|
|
34739
|
+
}
|
|
34643
34740
|
|
|
34644
34741
|
// ../../node_modules/@chrischall/mcp-utils/dist/zod/index.js
|
|
34645
34742
|
var PositiveInt = external_exports.number().int().positive();
|
|
@@ -34661,7 +34758,7 @@ var pageSchema = {
|
|
|
34661
34758
|
};
|
|
34662
34759
|
|
|
34663
34760
|
// ../gogcli-mcp/src/runner.ts
|
|
34664
|
-
import { delimiter, join } from "node:path";
|
|
34761
|
+
import { delimiter, join as join2 } from "node:path";
|
|
34665
34762
|
|
|
34666
34763
|
// ../gogcli-mcp/src/timestamps.ts
|
|
34667
34764
|
var DEFAULT_DISPLAY_TZ = "America/New_York";
|
|
@@ -34862,9 +34959,48 @@ function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSource
|
|
|
34862
34959
|
return JSON.stringify(parsed, null, detectIndent(text));
|
|
34863
34960
|
}
|
|
34864
34961
|
|
|
34962
|
+
// ../gogcli-mcp/src/arg-guard.ts
|
|
34963
|
+
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;
|
|
34964
|
+
var SHORT_ACCOUNT_CLUSTER = /^-(?!-)[A-Za-z]*a/;
|
|
34965
|
+
function forbiddenArgReason(arg) {
|
|
34966
|
+
if (arg === "--") {
|
|
34967
|
+
return 'The argument "--" is not allowed: it ends flag parsing and would disable safety flags appended after it.';
|
|
34968
|
+
}
|
|
34969
|
+
const match = FORBIDDEN_LONG_FLAG.exec(arg);
|
|
34970
|
+
if (match) {
|
|
34971
|
+
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.`;
|
|
34972
|
+
}
|
|
34973
|
+
if (SHORT_ACCOUNT_CLUSTER.test(arg)) {
|
|
34974
|
+
return `The flag ${arg} is not allowed here: -a selects the account. Use the tool's account parameter instead.`;
|
|
34975
|
+
}
|
|
34976
|
+
return void 0;
|
|
34977
|
+
}
|
|
34978
|
+
function assertSafeForwardedArgs(args) {
|
|
34979
|
+
for (const arg of args) {
|
|
34980
|
+
const reason = forbiddenArgReason(arg);
|
|
34981
|
+
if (reason) throw new Error(reason);
|
|
34982
|
+
}
|
|
34983
|
+
}
|
|
34984
|
+
var SUBCOMMAND_SHAPE = /^[a-z][a-z0-9-]*$/;
|
|
34985
|
+
function assertSafeSubcommand(subcommand) {
|
|
34986
|
+
if (!SUBCOMMAND_SHAPE.test(subcommand)) {
|
|
34987
|
+
throw new Error(
|
|
34988
|
+
`Invalid subcommand ${JSON.stringify(subcommand)}: pass a single gog subcommand name such as "list" or "mark-read", and put its arguments in args.`
|
|
34989
|
+
);
|
|
34990
|
+
}
|
|
34991
|
+
}
|
|
34992
|
+
|
|
34993
|
+
// ../gogcli-mcp/src/argv.ts
|
|
34994
|
+
function pos(value) {
|
|
34995
|
+
return { kind: "positional", value };
|
|
34996
|
+
}
|
|
34997
|
+
function isGogPositional(arg) {
|
|
34998
|
+
return typeof arg === "object" && arg !== null && arg.kind === "positional";
|
|
34999
|
+
}
|
|
35000
|
+
|
|
34865
35001
|
// ../gogcli-mcp/src/runner.ts
|
|
34866
35002
|
function isGogFileArg(arg) {
|
|
34867
|
-
return typeof arg !== "string";
|
|
35003
|
+
return typeof arg !== "string" && arg.kind === "file";
|
|
34868
35004
|
}
|
|
34869
35005
|
var TIMEOUT_MS = 3e4;
|
|
34870
35006
|
function readonlyEnvEnabled() {
|
|
@@ -34948,8 +35084,8 @@ function formatTimeout(ms) {
|
|
|
34948
35084
|
}
|
|
34949
35085
|
async function spawnWithTempFiles(args, opts) {
|
|
34950
35086
|
const { mkdtemp, mkdir, writeFile, rm } = await import("node:fs/promises");
|
|
34951
|
-
const { tmpdir } = await import("node:os");
|
|
34952
|
-
const dir = await mkdtemp(
|
|
35087
|
+
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
35088
|
+
const dir = await mkdtemp(join2(tmpdir2(), "gogcli-mcp-"));
|
|
34953
35089
|
try {
|
|
34954
35090
|
const argv = [];
|
|
34955
35091
|
let seq = 0;
|
|
@@ -34958,10 +35094,10 @@ async function spawnWithTempFiles(args, opts) {
|
|
|
34958
35094
|
argv.push(arg);
|
|
34959
35095
|
continue;
|
|
34960
35096
|
}
|
|
34961
|
-
const sub =
|
|
35097
|
+
const sub = join2(dir, String(seq));
|
|
34962
35098
|
seq += 1;
|
|
34963
35099
|
await mkdir(sub, { recursive: true, mode: 448 });
|
|
34964
|
-
const path =
|
|
35100
|
+
const path = join2(sub, arg.filename ?? `${arg.flag}.${arg.ext ?? "txt"}`);
|
|
34965
35101
|
const data = arg.encoding === "base64" ? Buffer.from(arg.contents, "base64") : Buffer.from(arg.contents, "utf8");
|
|
34966
35102
|
await writeFile(path, data, { mode: 384 });
|
|
34967
35103
|
argv.push(arg.positional ? path : `--${arg.flag}=${path}`);
|
|
@@ -34979,10 +35115,10 @@ function spawnExecutor(args, opts) {
|
|
|
34979
35115
|
return spawnGog(args, opts);
|
|
34980
35116
|
}
|
|
34981
35117
|
async function spawnGog(fullArgs, opts) {
|
|
34982
|
-
const { timeout, interactive = false, spawner, binary = false } = opts;
|
|
35118
|
+
const { timeout, interactive = false, spawner, binary = false, maxOutputBytes } = opts;
|
|
34983
35119
|
const spawn = spawner ?? (await import("node:child_process")).spawn;
|
|
34984
35120
|
const effectiveTimeout = timeout ?? TIMEOUT_MS;
|
|
34985
|
-
return new Promise((
|
|
35121
|
+
return new Promise((resolve4, reject) => {
|
|
34986
35122
|
const childEnv = { ...sanitizedEnv(), GOG_TIMEZONE: naiveSourceTimeZone(), PATH: augmentedPath() };
|
|
34987
35123
|
const child = spawn(readEnvVar("GOG_PATH") ?? "gog", fullArgs, { env: childEnv });
|
|
34988
35124
|
const stdoutChunks = [];
|
|
@@ -35000,7 +35136,17 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35000
35136
|
child.kill();
|
|
35001
35137
|
reject(new Error(`gog timed out after ${formatTimeout(effectiveTimeout)}`));
|
|
35002
35138
|
}, effectiveTimeout);
|
|
35139
|
+
let stdoutBytes = 0;
|
|
35003
35140
|
child.stdout.on("data", (chunk) => {
|
|
35141
|
+
if (settled) return;
|
|
35142
|
+
stdoutBytes += chunk.length;
|
|
35143
|
+
if (maxOutputBytes !== void 0 && stdoutBytes > maxOutputBytes) {
|
|
35144
|
+
settled = true;
|
|
35145
|
+
stopWatching();
|
|
35146
|
+
child.kill();
|
|
35147
|
+
reject(new Error(`gog output exceeded the limit: more than ${maxOutputBytes} bytes`));
|
|
35148
|
+
return;
|
|
35149
|
+
}
|
|
35004
35150
|
stdoutChunks.push(chunk);
|
|
35005
35151
|
});
|
|
35006
35152
|
child.stderr.on("data", (chunk) => {
|
|
@@ -35017,14 +35163,14 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35017
35163
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
35018
35164
|
if (code === 0) {
|
|
35019
35165
|
if (binary) {
|
|
35020
|
-
|
|
35166
|
+
resolve4(Buffer.concat(stdoutChunks).toString("base64"));
|
|
35021
35167
|
return;
|
|
35022
35168
|
}
|
|
35023
35169
|
const stdout = Buffer.concat(stdoutChunks).toString();
|
|
35024
35170
|
if (interactive && stderr) {
|
|
35025
|
-
|
|
35171
|
+
resolve4(stdout + "\n" + stderr);
|
|
35026
35172
|
} else {
|
|
35027
|
-
|
|
35173
|
+
resolve4(stdout);
|
|
35028
35174
|
}
|
|
35029
35175
|
} else {
|
|
35030
35176
|
reject(new Error(stderr || `gog exited with code ${code}`));
|
|
@@ -35044,7 +35190,33 @@ async function spawnGog(fullArgs, opts) {
|
|
|
35044
35190
|
});
|
|
35045
35191
|
});
|
|
35046
35192
|
}
|
|
35193
|
+
function placePositionals(args) {
|
|
35194
|
+
const flags = [];
|
|
35195
|
+
const positionals = [];
|
|
35196
|
+
let afterSeparator = false;
|
|
35197
|
+
for (const arg of args) {
|
|
35198
|
+
if (arg === "--") {
|
|
35199
|
+
afterSeparator = true;
|
|
35200
|
+
} else if (isGogPositional(arg)) {
|
|
35201
|
+
positionals.push(arg.value);
|
|
35202
|
+
} else if (afterSeparator || isGogFileArg(arg) && arg.positional) {
|
|
35203
|
+
positionals.push(arg);
|
|
35204
|
+
} else {
|
|
35205
|
+
flags.push(arg);
|
|
35206
|
+
}
|
|
35207
|
+
}
|
|
35208
|
+
return { flags, positionals };
|
|
35209
|
+
}
|
|
35210
|
+
function assertNoSafetyOverrides(flags) {
|
|
35211
|
+
for (const arg of flags) {
|
|
35212
|
+
if (typeof arg !== "string") continue;
|
|
35213
|
+
const reason = forbiddenArgReason(arg);
|
|
35214
|
+
if (reason) throw new Error(reason);
|
|
35215
|
+
}
|
|
35216
|
+
}
|
|
35047
35217
|
function assembleArgs(args, opts) {
|
|
35218
|
+
const { flags, positionals } = placePositionals(args);
|
|
35219
|
+
assertNoSafetyOverrides(flags);
|
|
35048
35220
|
const effectiveAccount = opts.account ?? readEnvVar("GOG_ACCOUNT");
|
|
35049
35221
|
const fullArgs = ["--json", "--color=never"];
|
|
35050
35222
|
if (!opts.interactive) {
|
|
@@ -35053,17 +35225,21 @@ function assembleArgs(args, opts) {
|
|
|
35053
35225
|
if (opts.readonly || readonlyEnvEnabled()) {
|
|
35054
35226
|
fullArgs.push("--readonly");
|
|
35055
35227
|
}
|
|
35228
|
+
if (opts.gmailNoSend) {
|
|
35229
|
+
fullArgs.push("--gmail-no-send");
|
|
35230
|
+
}
|
|
35056
35231
|
if (effectiveAccount) {
|
|
35057
35232
|
fullArgs.push("--account", effectiveAccount);
|
|
35058
35233
|
}
|
|
35059
|
-
fullArgs.push(...
|
|
35234
|
+
fullArgs.push(...flags);
|
|
35235
|
+
if (positionals.length > 0) fullArgs.push("--", ...positionals);
|
|
35060
35236
|
return fullArgs;
|
|
35061
35237
|
}
|
|
35062
35238
|
async function run(args, options = {}) {
|
|
35063
|
-
const { account, spawner, interactive = false, timeout, readonly: readonly2 = false, redactMode = "full", opaqueFields } = options;
|
|
35239
|
+
const { account, spawner, interactive = false, timeout, readonly: readonly2 = false, redactMode = "full", opaqueFields, gmailNoSend = false } = options;
|
|
35064
35240
|
const base = redactMode === "tokens" ? redactGoogleTokens : redactSecrets2;
|
|
35065
35241
|
const redact = opaqueFields?.length ? (text) => redactPreservingOpaqueFields(text, opaqueFields, base) : base;
|
|
35066
|
-
const fullArgs = assembleArgs(args, { account, interactive, readonly: readonly2 });
|
|
35242
|
+
const fullArgs = assembleArgs(args, { account, interactive, readonly: readonly2, gmailNoSend });
|
|
35067
35243
|
try {
|
|
35068
35244
|
return redact(await spawnExecutor(fullArgs, { timeout, interactive, spawner }));
|
|
35069
35245
|
} catch (err) {
|
|
@@ -35071,9 +35247,9 @@ async function run(args, options = {}) {
|
|
|
35071
35247
|
}
|
|
35072
35248
|
}
|
|
35073
35249
|
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 });
|
|
35250
|
+
const { account, spawner, timeout, readonly: readonly2 = false, gmailNoSend = false, maxOutputBytes } = options;
|
|
35251
|
+
const fullArgs = assembleArgs(args, { account, interactive: false, readonly: readonly2, gmailNoSend });
|
|
35252
|
+
return spawnExecutor(fullArgs, { timeout, interactive: false, spawner, binary: true, maxOutputBytes });
|
|
35077
35253
|
}
|
|
35078
35254
|
|
|
35079
35255
|
// ../gogcli-mcp/src/pagination.ts
|
|
@@ -35096,6 +35272,107 @@ function stripConsumedPageToken(text) {
|
|
|
35096
35272
|
return JSON.stringify(obj, null, detectIndent2(text));
|
|
35097
35273
|
}
|
|
35098
35274
|
|
|
35275
|
+
// ../gogcli-mcp/src/file-roots.ts
|
|
35276
|
+
import { homedir as homedir2 } from "node:os";
|
|
35277
|
+
import { delimiter as delimiter2, join as join4 } from "node:path";
|
|
35278
|
+
|
|
35279
|
+
// ../gogcli-mcp/src/attachment-root.ts
|
|
35280
|
+
import { tmpdir, userInfo } from "node:os";
|
|
35281
|
+
import { dirname as dirname2, join as join3, relative as relative2, resolve as resolve3, isAbsolute as isAbsolute3, sep as sep2 } from "node:path";
|
|
35282
|
+
var ATTACHMENT_DOWNLOAD_ROOT = join3(tmpdir(), `gogcli-mcp-attachments-${userInfo().uid}`);
|
|
35283
|
+
var ATTACHMENT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
35284
|
+
|
|
35285
|
+
// ../gogcli-mcp/src/file-roots.ts
|
|
35286
|
+
var FILE_ROOTS_ENV = "GOG_FILE_ROOTS";
|
|
35287
|
+
function defaultFileRoot() {
|
|
35288
|
+
return join4(homedir2(), "gogcli-mcp-files");
|
|
35289
|
+
}
|
|
35290
|
+
function fileRoots() {
|
|
35291
|
+
const raw = readEnvVar(FILE_ROOTS_ENV);
|
|
35292
|
+
const roots = (raw ?? "").split(delimiter2).map((r) => r.trim()).filter(Boolean);
|
|
35293
|
+
return roots.length > 0 ? roots : [defaultFileRoot()];
|
|
35294
|
+
}
|
|
35295
|
+
function confinePath(path, param, opts = {}) {
|
|
35296
|
+
if (opts.allowDash && path === "-") return path;
|
|
35297
|
+
const roots = [...fileRoots(), ATTACHMENT_DOWNLOAD_ROOT];
|
|
35298
|
+
try {
|
|
35299
|
+
assertPathWithinRoots(path, roots);
|
|
35300
|
+
} catch {
|
|
35301
|
+
throw new Error(
|
|
35302
|
+
`${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}.`
|
|
35303
|
+
);
|
|
35304
|
+
}
|
|
35305
|
+
return path;
|
|
35306
|
+
}
|
|
35307
|
+
|
|
35308
|
+
// ../gogcli-mcp/src/run-path-guard.ts
|
|
35309
|
+
var POSITIONAL_PATH_SUBCOMMANDS = {
|
|
35310
|
+
appscript: { pull: "gog_appscript_pull" },
|
|
35311
|
+
drive: { upload: "gog_drive_upload", sync: "gog_drive_sync_push" },
|
|
35312
|
+
gmail: { import: "gog_gmail_import" },
|
|
35313
|
+
slides: {
|
|
35314
|
+
"add-slide": "gog_slides_add_slide",
|
|
35315
|
+
"insert-image": "gog_slides_insert_image",
|
|
35316
|
+
"replace-slide": "gog_slides_replace_slide"
|
|
35317
|
+
}
|
|
35318
|
+
};
|
|
35319
|
+
var PATH_FLAGS = /* @__PURE__ */ new Set(["out", "output", "out-dir", "output-dir", "dir", "worker-dir", "attach", "file", "key", "cert", "replacements"]);
|
|
35320
|
+
var ID_FLAGS = {
|
|
35321
|
+
drive: /* @__PURE__ */ new Set(["file", "filter-file"])
|
|
35322
|
+
};
|
|
35323
|
+
var EXEC_FLAGS = /* @__PURE__ */ new Set(["on-change", "on-new", "mmdc"]);
|
|
35324
|
+
var SHORT_PATH_CLUSTER = /^-(?!-)[A-Za-z]*[of]/;
|
|
35325
|
+
var LONG_FLAG = /^--([A-Za-z0-9][A-Za-z0-9-]*)(?:=([\s\S]*))?$/;
|
|
35326
|
+
function isPathFlag(service, name) {
|
|
35327
|
+
if (ID_FLAGS[service]?.has(name)) return false;
|
|
35328
|
+
return PATH_FLAGS.has(name) || name.endsWith("-file");
|
|
35329
|
+
}
|
|
35330
|
+
function confineFlagValue(flag, value) {
|
|
35331
|
+
if (value === "-") return;
|
|
35332
|
+
confinePath(value, flag);
|
|
35333
|
+
for (const part of value.split(",")) {
|
|
35334
|
+
if (part !== "" && part !== "-") confinePath(part, flag);
|
|
35335
|
+
}
|
|
35336
|
+
}
|
|
35337
|
+
function positionalPathTool(service, subcommand) {
|
|
35338
|
+
return POSITIONAL_PATH_SUBCOMMANDS[service]?.[subcommand];
|
|
35339
|
+
}
|
|
35340
|
+
function assertRunPathsConfined(service, subcommand, args) {
|
|
35341
|
+
const dedicated = positionalPathTool(service, subcommand);
|
|
35342
|
+
if (dedicated) {
|
|
35343
|
+
throw new Error(
|
|
35344
|
+
`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.`
|
|
35345
|
+
);
|
|
35346
|
+
}
|
|
35347
|
+
for (let i = 0; i < args.length; i++) {
|
|
35348
|
+
const arg = args[i];
|
|
35349
|
+
if (SHORT_PATH_CLUSTER.test(arg)) {
|
|
35350
|
+
throw new Error(
|
|
35351
|
+
`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.`
|
|
35352
|
+
);
|
|
35353
|
+
}
|
|
35354
|
+
const match = LONG_FLAG.exec(arg);
|
|
35355
|
+
if (!match) continue;
|
|
35356
|
+
const name = match[1].toLowerCase();
|
|
35357
|
+
if (EXEC_FLAGS.has(name)) {
|
|
35358
|
+
throw new Error(`The flag --${name} is not allowed here: it runs a local program chosen by the caller.`);
|
|
35359
|
+
}
|
|
35360
|
+
const isJson = name.endsWith("-json");
|
|
35361
|
+
if (!isJson && !isPathFlag(service, name)) continue;
|
|
35362
|
+
let value = match[2];
|
|
35363
|
+
if (value === void 0) {
|
|
35364
|
+
value = args[i + 1];
|
|
35365
|
+
if (value === void 0) continue;
|
|
35366
|
+
i++;
|
|
35367
|
+
}
|
|
35368
|
+
if (isJson) {
|
|
35369
|
+
if (value.startsWith("@")) confineFlagValue(`--${name}`, value.slice(1));
|
|
35370
|
+
continue;
|
|
35371
|
+
}
|
|
35372
|
+
confineFlagValue(`--${name}`, value);
|
|
35373
|
+
}
|
|
35374
|
+
}
|
|
35375
|
+
|
|
35099
35376
|
// ../gogcli-mcp/src/tools/utils.ts
|
|
35100
35377
|
var accountParam = external_exports.string().optional().describe(
|
|
35101
35378
|
"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 +35423,17 @@ function pushPaginationFlags(args, p) {
|
|
|
35146
35423
|
if (p.all) args.push("--all");
|
|
35147
35424
|
}
|
|
35148
35425
|
function registerRunTool(server, options) {
|
|
35149
|
-
const { service, examples, omitAccount = false, note } = options;
|
|
35426
|
+
const { service, examples, omitAccount = false, note, allowedSubcommands, vet, gmailNoSend = false } = options;
|
|
35427
|
+
for (const [, example] of examples.matchAll(/"([^"]+)"/g)) {
|
|
35428
|
+
const refused = allowedSubcommands && !allowedSubcommands.includes(example) || vet?.(example, []) || positionalPathTool(service, example);
|
|
35429
|
+
if (refused) {
|
|
35430
|
+
throw new Error(`gog_${service}_run example "${example}" is refused by the tool itself; list a subcommand it runs.`);
|
|
35431
|
+
}
|
|
35432
|
+
}
|
|
35150
35433
|
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
|
|
35434
|
+
const restriction = allowedSubcommands ? ` Only these subcommands are available: ${allowedSubcommands.join(", ")}.` : "";
|
|
35435
|
+
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.';
|
|
35436
|
+
const description = `${baseDescription}${restriction}${safety}${note ? ` ${note}` : ""}`;
|
|
35152
35437
|
const inputSchema = {
|
|
35153
35438
|
subcommand: external_exports.string().describe(`The gog ${service} subcommand to run, e.g. ${examples}`),
|
|
35154
35439
|
args: external_exports.array(external_exports.string()).describe("Additional positional args and flags")
|
|
@@ -35162,7 +35447,21 @@ function registerRunTool(server, options) {
|
|
|
35162
35447
|
inputSchema: external_exports.object(inputSchema)
|
|
35163
35448
|
}, async (rawArgs) => {
|
|
35164
35449
|
const { subcommand, args, account } = rawArgs;
|
|
35165
|
-
|
|
35450
|
+
try {
|
|
35451
|
+
assertSafeSubcommand(subcommand);
|
|
35452
|
+
assertSafeForwardedArgs(args);
|
|
35453
|
+
if (allowedSubcommands && !allowedSubcommands.includes(subcommand)) {
|
|
35454
|
+
throw new Error(
|
|
35455
|
+
`gog ${service} ${subcommand} is not available through gog_${service}_run. Allowed: ${allowedSubcommands.join(", ")}.`
|
|
35456
|
+
);
|
|
35457
|
+
}
|
|
35458
|
+
const refusal = vet?.(subcommand, args);
|
|
35459
|
+
if (refusal) throw new Error(refusal);
|
|
35460
|
+
assertRunPathsConfined(service, subcommand, args);
|
|
35461
|
+
} catch (err) {
|
|
35462
|
+
return errorResult(errorText(err));
|
|
35463
|
+
}
|
|
35464
|
+
return runOrDiagnose([service, subcommand, ...args], gmailNoSend ? { account, gmailNoSend } : { account });
|
|
35166
35465
|
});
|
|
35167
35466
|
}
|
|
35168
35467
|
function errorText(err) {
|
|
@@ -35284,6 +35583,7 @@ function formatAuthHealth(raw, now) {
|
|
|
35284
35583
|
}
|
|
35285
35584
|
|
|
35286
35585
|
// ../gogcli-mcp/src/tools/auth.ts
|
|
35586
|
+
var AUTH_RUN_SUBCOMMANDS = ["list", "status", "services", "remove", "alias"];
|
|
35287
35587
|
function registerAuthToolsWith(server, defaultServices) {
|
|
35288
35588
|
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
35589
|
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 +35641,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35341
35641
|
})
|
|
35342
35642
|
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
35343
35643
|
try {
|
|
35344
|
-
const args = ["auth", "add", email3, "--services", services];
|
|
35644
|
+
const args = ["auth", "add", pos(email3), "--services", services];
|
|
35345
35645
|
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`, "--force-consent");
|
|
35346
35646
|
return rawTextResult(await run(args, {
|
|
35347
35647
|
interactive: true,
|
|
@@ -35361,7 +35661,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35361
35661
|
})
|
|
35362
35662
|
}, async ({ email: email3, services = defaultServices, extraScopes }) => {
|
|
35363
35663
|
try {
|
|
35364
|
-
const args = ["auth", "add", email3, "--remote", "--step", "1", "--services", services, "--force-consent"];
|
|
35664
|
+
const args = ["auth", "add", pos(email3), "--remote", "--step", "1", "--services", services, "--force-consent"];
|
|
35365
35665
|
if (extraScopes) args.push(`--extra-scopes=${extraScopes}`);
|
|
35366
35666
|
return rawTextResult(await run(args, { redactMode: "tokens" }));
|
|
35367
35667
|
} catch (err) {
|
|
@@ -35388,7 +35688,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35388
35688
|
const args = [
|
|
35389
35689
|
"auth",
|
|
35390
35690
|
"add",
|
|
35391
|
-
email3,
|
|
35691
|
+
pos(email3),
|
|
35392
35692
|
"--remote",
|
|
35393
35693
|
"--step",
|
|
35394
35694
|
"2",
|
|
@@ -35408,6 +35708,7 @@ function registerAuthToolsWith(server, defaultServices) {
|
|
|
35408
35708
|
service: "auth",
|
|
35409
35709
|
examples: '"remove", "alias", "list"',
|
|
35410
35710
|
omitAccount: true,
|
|
35711
|
+
allowedSubcommands: AUTH_RUN_SUBCOMMANDS,
|
|
35411
35712
|
note: "For browser-based authorization, use gog_auth_add instead."
|
|
35412
35713
|
});
|
|
35413
35714
|
}
|
|
@@ -35485,8 +35786,10 @@ var GOOGLE_DOC_MIME = "application/vnd.google-apps.document";
|
|
|
35485
35786
|
function fileMeta(raw) {
|
|
35486
35787
|
const parsed = JSON.parse(raw);
|
|
35487
35788
|
const f = parsed.file ?? parsed;
|
|
35488
|
-
|
|
35789
|
+
const size = f.size === void 0 ? void 0 : Number(f.size);
|
|
35790
|
+
return { name: f.name, mimeType: f.mimeType, size: Number.isFinite(size) ? size : void 0 };
|
|
35489
35791
|
}
|
|
35792
|
+
var MAX_DRIVE_READ_BYTES = MAX_INLINE_ATTACHMENT_BYTES;
|
|
35490
35793
|
var DRIVE_LS_COMPACT_FIELDS = "nextPageToken,files(id,name,mimeType,modifiedTime,size,webViewLink)";
|
|
35491
35794
|
function registerDriveTools(server) {
|
|
35492
35795
|
server.registerTool("gog_drive_ls", {
|
|
@@ -35530,7 +35833,7 @@ function registerDriveTools(server) {
|
|
|
35530
35833
|
account: accountParam
|
|
35531
35834
|
})
|
|
35532
35835
|
}, async ({ query, view, account }) => {
|
|
35533
|
-
return runOrDiagnose(["drive", "search", query], {
|
|
35836
|
+
return runOrDiagnose(["drive", "search", pos(query)], {
|
|
35534
35837
|
account,
|
|
35535
35838
|
stripMedia: resolveView(view, ["compact", "full"]) === "compact"
|
|
35536
35839
|
});
|
|
@@ -35550,7 +35853,7 @@ function registerDriveTools(server) {
|
|
|
35550
35853
|
account: accountParam
|
|
35551
35854
|
})
|
|
35552
35855
|
}, async ({ fileId, view, account }) => {
|
|
35553
|
-
return runOrDiagnose(["drive", "get", fileId], {
|
|
35856
|
+
return runOrDiagnose(["drive", "get", pos(fileId)], {
|
|
35554
35857
|
account,
|
|
35555
35858
|
stripMedia: resolveView(view, ["compact", "full"]) === "compact"
|
|
35556
35859
|
});
|
|
@@ -35563,7 +35866,7 @@ function registerDriveTools(server) {
|
|
|
35563
35866
|
account: accountParam
|
|
35564
35867
|
})
|
|
35565
35868
|
}, async ({ name, account }) => {
|
|
35566
|
-
return runOrDiagnose(["drive", "mkdir", name], { account });
|
|
35869
|
+
return runOrDiagnose(["drive", "mkdir", pos(name)], { account });
|
|
35567
35870
|
});
|
|
35568
35871
|
server.registerTool("gog_drive_rename", {
|
|
35569
35872
|
description: "Rename a file or folder in Google Drive.",
|
|
@@ -35574,7 +35877,7 @@ function registerDriveTools(server) {
|
|
|
35574
35877
|
account: accountParam
|
|
35575
35878
|
})
|
|
35576
35879
|
}, async ({ fileId, newName, account }) => {
|
|
35577
|
-
return runOrDiagnose(["drive", "rename", fileId, newName], { account });
|
|
35880
|
+
return runOrDiagnose(["drive", "rename", pos(fileId), pos(newName)], { account });
|
|
35578
35881
|
});
|
|
35579
35882
|
server.registerTool("gog_drive_move", {
|
|
35580
35883
|
description: "Move a file to a different folder in Google Drive.",
|
|
@@ -35585,7 +35888,7 @@ function registerDriveTools(server) {
|
|
|
35585
35888
|
account: accountParam
|
|
35586
35889
|
})
|
|
35587
35890
|
}, async ({ fileId, parentId, account }) => {
|
|
35588
|
-
return runOrDiagnose(["drive", "move", fileId, `--parent=${parentId}`], { account });
|
|
35891
|
+
return runOrDiagnose(["drive", "move", pos(fileId), `--parent=${parentId}`], { account });
|
|
35589
35892
|
});
|
|
35590
35893
|
server.registerTool("gog_drive_delete", {
|
|
35591
35894
|
description: "Move a Google Drive file to trash, or permanently delete it with permanent=true (irreversible).",
|
|
@@ -35596,7 +35899,7 @@ function registerDriveTools(server) {
|
|
|
35596
35899
|
account: accountParam
|
|
35597
35900
|
})
|
|
35598
35901
|
}, async ({ fileId, permanent, account }) => {
|
|
35599
|
-
const args = ["drive", "delete", fileId];
|
|
35902
|
+
const args = ["drive", "delete", pos(fileId)];
|
|
35600
35903
|
if (permanent) args.push("--permanent");
|
|
35601
35904
|
args.push("--force");
|
|
35602
35905
|
return runOrDiagnose(args, { account });
|
|
@@ -35613,7 +35916,7 @@ function registerDriveTools(server) {
|
|
|
35613
35916
|
account: accountParam
|
|
35614
35917
|
})
|
|
35615
35918
|
}, async ({ fileId, to, email: email3, domain: domain2, role, account }) => {
|
|
35616
|
-
const args = ["drive", "share", fileId, `--to=${to}`];
|
|
35919
|
+
const args = ["drive", "share", pos(fileId), `--to=${to}`];
|
|
35617
35920
|
if (email3) args.push(`--email=${email3}`);
|
|
35618
35921
|
if (domain2) args.push(`--domain=${domain2}`);
|
|
35619
35922
|
if (role) args.push(`--role=${role}`);
|
|
@@ -35636,7 +35939,7 @@ function registerDriveTools(server) {
|
|
|
35636
35939
|
}, async ({ fileId, ocrLanguage, offset = 0, maxChars, account }) => {
|
|
35637
35940
|
let tempDocId;
|
|
35638
35941
|
try {
|
|
35639
|
-
const { name, mimeType } = fileMeta(await run(["drive", "get", fileId], { account }));
|
|
35942
|
+
const { name, mimeType } = fileMeta(await run(["drive", "get", pos(fileId)], { account }));
|
|
35640
35943
|
let sourceId = fileId;
|
|
35641
35944
|
if (mimeType !== GOOGLE_DOC_MIME) {
|
|
35642
35945
|
const params = JSON.stringify({ fileId, ...ocrLanguage ? { ocrLanguage } : {} });
|
|
@@ -35681,13 +35984,13 @@ function registerDriveTools(server) {
|
|
|
35681
35984
|
return diagnose(err);
|
|
35682
35985
|
} finally {
|
|
35683
35986
|
if (tempDocId) {
|
|
35684
|
-
await run(["drive", "delete", tempDocId, "--permanent", "--force"], { account }).catch(() => {
|
|
35987
|
+
await run(["drive", "delete", pos(tempDocId), "--permanent", "--force"], { account }).catch(() => {
|
|
35685
35988
|
});
|
|
35686
35989
|
}
|
|
35687
35990
|
}
|
|
35688
35991
|
});
|
|
35689
35992
|
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.",
|
|
35993
|
+
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
35994
|
annotations: { readOnlyHint: true },
|
|
35692
35995
|
inputSchema: external_exports.object({
|
|
35693
35996
|
fileId: external_exports.string().describe("Drive file ID"),
|
|
@@ -35695,9 +35998,17 @@ function registerDriveTools(server) {
|
|
|
35695
35998
|
})
|
|
35696
35999
|
}, async ({ fileId, account }) => {
|
|
35697
36000
|
try {
|
|
35698
|
-
const { name, mimeType } = fileMeta(await run(["drive", "get", fileId], { account }));
|
|
36001
|
+
const { name, mimeType, size } = fileMeta(await run(["drive", "get", pos(fileId)], { account }));
|
|
36002
|
+
if (size !== void 0 && size > MAX_DRIVE_READ_BYTES) {
|
|
36003
|
+
return errorResult(
|
|
36004
|
+
`${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.`
|
|
36005
|
+
);
|
|
36006
|
+
}
|
|
35699
36007
|
const params = JSON.stringify({ fileId, alt: "media" });
|
|
35700
|
-
const blob = await runBinary(
|
|
36008
|
+
const blob = await runBinary(
|
|
36009
|
+
["api", "call", "drive", "v3", "files.get", `--params=${params}`],
|
|
36010
|
+
{ account, maxOutputBytes: MAX_DRIVE_READ_BYTES }
|
|
36011
|
+
);
|
|
35701
36012
|
const type = mimeType ?? "application/octet-stream";
|
|
35702
36013
|
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
36014
|
return {
|
|
@@ -35717,7 +36028,7 @@ function registerDriveTools(server) {
|
|
|
35717
36028
|
return diagnose(err);
|
|
35718
36029
|
}
|
|
35719
36030
|
});
|
|
35720
|
-
registerRunTool(server, { service: "drive", examples: '"copy", "
|
|
36031
|
+
registerRunTool(server, { service: "drive", examples: '"copy", "download", "permissions"' });
|
|
35721
36032
|
}
|
|
35722
36033
|
|
|
35723
36034
|
// ../gogcli-mcp/src/tools/gmail.ts
|
|
@@ -35732,7 +36043,7 @@ var replySchema = {
|
|
|
35732
36043
|
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
36044
|
subject: external_exports.string().optional().describe('Override reply subject (default: "Re: <original>"). A changed subject starts a NEW Gmail thread.'),
|
|
35734
36045
|
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.`),
|
|
36046
|
+
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
36047
|
attachInline: attachInlineParam,
|
|
35737
36048
|
from: external_exports.string().optional().describe("Send from this email address (must be a verified send-as alias)"),
|
|
35738
36049
|
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."),
|
|
@@ -35753,10 +36064,10 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
|
|
|
35753
36064
|
);
|
|
35754
36065
|
|
|
35755
36066
|
// ../gogcli-mcp/src/server.ts
|
|
35756
|
-
var VERSION = true ? "4.
|
|
36067
|
+
var VERSION = true ? "4.3.0" : "0.0.0";
|
|
35757
36068
|
|
|
35758
36069
|
// ../gogcli-mcp/src/bootstrap-auth.ts
|
|
35759
|
-
import { join as
|
|
36070
|
+
import { join as join5 } from "node:path";
|
|
35760
36071
|
var AUTH_BOOTSTRAP_MARKER = "auth-bootstrap.sha256";
|
|
35761
36072
|
var VARS = ["GOG_CLIENT_ID", "GOG_CLIENT_SECRET", "GOG_REFRESH_TOKEN", "GOG_ACCOUNT"];
|
|
35762
36073
|
var log = (line) => {
|
|
@@ -35793,8 +36104,8 @@ async function bootstrapGogAuth(env = process.env, options = {}) {
|
|
|
35793
36104
|
const { createHash } = await import("node:crypto");
|
|
35794
36105
|
const { mkdir, readFile, writeFile, chmod } = await import("node:fs/promises");
|
|
35795
36106
|
const home = options.home ?? (await import("node:os")).homedir();
|
|
35796
|
-
const dir =
|
|
35797
|
-
const marker =
|
|
36107
|
+
const dir = join5(home, ".gogcli-mcp");
|
|
36108
|
+
const marker = join5(dir, AUTH_BOOTSTRAP_MARKER);
|
|
35798
36109
|
const fingerprint = createHash("sha256").update(values.join("\0")).digest("hex");
|
|
35799
36110
|
const previous = await readFile(marker, "utf8").catch(() => void 0);
|
|
35800
36111
|
if (previous === fingerprint && await accountListed(account, spawner)) return "present";
|
|
@@ -35831,7 +36142,8 @@ var MAX_BLOB_UPLOAD_BYTES = 100 * 1024 * 1024;
|
|
|
35831
36142
|
function registerExtraDriveTools(server) {
|
|
35832
36143
|
server.registerTool("gog_drive_download", {
|
|
35833
36144
|
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
|
-
|
|
36145
|
+
// Writes a file on the gog host and can overwrite one: not read-only (audit SEC-4).
|
|
36146
|
+
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
35835
36147
|
inputSchema: external_exports.object({
|
|
35836
36148
|
fileId: external_exports.string().describe("File ID to download"),
|
|
35837
36149
|
out: external_exports.string().optional().describe("Output file path (default: gogcli config dir)"),
|
|
@@ -35840,7 +36152,8 @@ function registerExtraDriveTools(server) {
|
|
|
35840
36152
|
account: accountParam
|
|
35841
36153
|
})
|
|
35842
36154
|
}, async ({ fileId, out, format, overwrite, account }) => {
|
|
35843
|
-
|
|
36155
|
+
if (out) confinePath(out, "out");
|
|
36156
|
+
const args = ["drive", "download", pos(fileId)];
|
|
35844
36157
|
if (out) args.push(`--out=${out}`);
|
|
35845
36158
|
if (format) args.push(`--format=${format}`);
|
|
35846
36159
|
if (overwrite) args.push("--overwrite");
|
|
@@ -35850,7 +36163,7 @@ function registerExtraDriveTools(server) {
|
|
|
35850
36163
|
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
36164
|
annotations: { destructiveHint: false },
|
|
35852
36165
|
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.`),
|
|
36166
|
+
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
36167
|
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
36168
|
name: external_exports.string().optional().describe("Override filename (create) or rename target (replace)"),
|
|
35856
36169
|
parent: external_exports.string().optional().describe("Destination folder ID (create only)"),
|
|
@@ -35875,7 +36188,7 @@ function registerExtraDriveTools(server) {
|
|
|
35875
36188
|
}
|
|
35876
36189
|
let pathArg;
|
|
35877
36190
|
if (localPath !== void 0) {
|
|
35878
|
-
pathArg = localPath;
|
|
36191
|
+
pathArg = confinePath(localPath, "localPath");
|
|
35879
36192
|
} else {
|
|
35880
36193
|
if (!name) {
|
|
35881
36194
|
throw new Error("content requires name: there is no path to derive the Drive filename from.");
|
|
@@ -35886,7 +36199,7 @@ function registerExtraDriveTools(server) {
|
|
|
35886
36199
|
{ positional: true, where: "content" }
|
|
35887
36200
|
).arg;
|
|
35888
36201
|
}
|
|
35889
|
-
const args = ["drive", "upload", pathArg];
|
|
36202
|
+
const args = ["drive", "upload", typeof pathArg === "string" ? pos(pathArg) : pathArg];
|
|
35890
36203
|
if (name) args.push(`--name=${name}`);
|
|
35891
36204
|
if (parent) args.push(`--parent=${parent}`);
|
|
35892
36205
|
if (replace) args.push(`--replace=${replace}`);
|
|
@@ -35901,14 +36214,15 @@ function registerExtraDriveTools(server) {
|
|
|
35901
36214
|
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
36215
|
annotations: { destructiveHint: true },
|
|
35903
36216
|
inputSchema: external_exports.object({
|
|
35904
|
-
localPath: external_exports.string().describe("Local directory to push (its contents are mirrored into the parent folder)"),
|
|
36217
|
+
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
36218
|
parent: external_exports.string().describe("Existing destination Drive folder ID"),
|
|
35906
36219
|
dryRun: external_exports.boolean().optional().describe("Preview the planned actions without making any changes"),
|
|
35907
36220
|
allDrives: external_exports.boolean().optional().describe("Include shared drives (default: true; set false for My Drive only)"),
|
|
35908
36221
|
account: accountParam
|
|
35909
36222
|
})
|
|
35910
36223
|
}, async ({ localPath, parent, dryRun, allDrives, account }) => {
|
|
35911
|
-
|
|
36224
|
+
confinePath(localPath, "localPath");
|
|
36225
|
+
const args = ["drive", "sync", "push", pos(localPath), `--parent=${parent}`];
|
|
35912
36226
|
if (dryRun) args.push("--dry-run");
|
|
35913
36227
|
if (allDrives === false) args.push("--no-all-drives");
|
|
35914
36228
|
return runOrDiagnose(args, { account });
|
|
@@ -35923,7 +36237,7 @@ function registerExtraDriveTools(server) {
|
|
|
35923
36237
|
account: accountParam
|
|
35924
36238
|
})
|
|
35925
36239
|
}, async ({ fileId, name, parent, account }) => {
|
|
35926
|
-
const args = ["drive", "copy", fileId, name];
|
|
36240
|
+
const args = ["drive", "copy", pos(fileId), pos(name)];
|
|
35927
36241
|
if (parent) args.push(`--parent=${parent}`);
|
|
35928
36242
|
return runOrDiagnose(args, { account });
|
|
35929
36243
|
});
|
|
@@ -35935,7 +36249,7 @@ function registerExtraDriveTools(server) {
|
|
|
35935
36249
|
account: accountParam
|
|
35936
36250
|
})
|
|
35937
36251
|
}, async ({ fileIds, account }) => {
|
|
35938
|
-
return runOrDiagnose(["drive", "url", ...fileIds], { account });
|
|
36252
|
+
return runOrDiagnose(["drive", "url", ...fileIds.map(pos)], { account });
|
|
35939
36253
|
});
|
|
35940
36254
|
server.registerTool("gog_drive_permissions", {
|
|
35941
36255
|
description: "List permissions on a Drive file.",
|
|
@@ -35948,7 +36262,7 @@ function registerExtraDriveTools(server) {
|
|
|
35948
36262
|
account: accountParam
|
|
35949
36263
|
})
|
|
35950
36264
|
}, async ({ fileId, max, pageToken, page, account }) => {
|
|
35951
|
-
const args = ["drive", "permissions", fileId];
|
|
36265
|
+
const args = ["drive", "permissions", pos(fileId)];
|
|
35952
36266
|
if (max !== void 0) args.push(`--max=${max}`);
|
|
35953
36267
|
const token = resolvePageToken({ pageToken, page });
|
|
35954
36268
|
if (token) args.push(`--page=${token}`);
|
|
@@ -35963,7 +36277,7 @@ function registerExtraDriveTools(server) {
|
|
|
35963
36277
|
account: accountParam
|
|
35964
36278
|
})
|
|
35965
36279
|
}, async ({ fileId, permissionId, account }) => {
|
|
35966
|
-
return runOrDiagnose(["drive", "unshare", fileId, permissionId, "--force"], { account });
|
|
36280
|
+
return runOrDiagnose(["drive", "unshare", pos(fileId), pos(permissionId), "--force"], { account });
|
|
35967
36281
|
});
|
|
35968
36282
|
server.registerTool("gog_drive_drives_list", {
|
|
35969
36283
|
description: "List shared drives (Team Drives) accessible to the account.",
|
|
@@ -35996,7 +36310,7 @@ function registerExtraDriveTools(server) {
|
|
|
35996
36310
|
account: accountParam
|
|
35997
36311
|
})
|
|
35998
36312
|
}, async ({ fileId, since, includeQuoted, max, page, all, account }) => {
|
|
35999
|
-
const args = ["drive", "comments", "list", fileId];
|
|
36313
|
+
const args = ["drive", "comments", "list", pos(fileId)];
|
|
36000
36314
|
if (since) args.push(`--since=${since}`);
|
|
36001
36315
|
if (includeQuoted) args.push("--include-quoted");
|
|
36002
36316
|
pushPaginationFlags(args, { max, page, all });
|
|
@@ -36011,7 +36325,7 @@ function registerExtraDriveTools(server) {
|
|
|
36011
36325
|
account: accountParam
|
|
36012
36326
|
})
|
|
36013
36327
|
}, async ({ fileId, commentId, account }) => {
|
|
36014
|
-
return runOrDiagnose(["drive", "comments", "get", fileId, commentId], { account });
|
|
36328
|
+
return runOrDiagnose(["drive", "comments", "get", pos(fileId), pos(commentId)], { account });
|
|
36015
36329
|
});
|
|
36016
36330
|
server.registerTool("gog_drive_comments_add", {
|
|
36017
36331
|
description: "Add a new comment to a Drive file.",
|
|
@@ -36022,7 +36336,7 @@ function registerExtraDriveTools(server) {
|
|
|
36022
36336
|
account: accountParam
|
|
36023
36337
|
})
|
|
36024
36338
|
}, async ({ fileId, content, account }) => {
|
|
36025
|
-
return runOrDiagnose(["drive", "comments", "create", fileId, content], { account });
|
|
36339
|
+
return runOrDiagnose(["drive", "comments", "create", pos(fileId), pos(content)], { account });
|
|
36026
36340
|
});
|
|
36027
36341
|
server.registerTool("gog_drive_comments_update", {
|
|
36028
36342
|
description: "Update the text of an existing comment.",
|
|
@@ -36034,7 +36348,7 @@ function registerExtraDriveTools(server) {
|
|
|
36034
36348
|
account: accountParam
|
|
36035
36349
|
})
|
|
36036
36350
|
}, async ({ fileId, commentId, content, account }) => {
|
|
36037
|
-
return runOrDiagnose(["drive", "comments", "update", fileId, commentId, content], { account });
|
|
36351
|
+
return runOrDiagnose(["drive", "comments", "update", pos(fileId), pos(commentId), pos(content)], { account });
|
|
36038
36352
|
});
|
|
36039
36353
|
server.registerTool("gog_drive_comments_delete", {
|
|
36040
36354
|
description: "Delete a comment from a Drive file.",
|
|
@@ -36045,7 +36359,7 @@ function registerExtraDriveTools(server) {
|
|
|
36045
36359
|
account: accountParam
|
|
36046
36360
|
})
|
|
36047
36361
|
}, async ({ fileId, commentId, account }) => {
|
|
36048
|
-
return runOrDiagnose(["drive", "comments", "delete", fileId, commentId, "--force"], { account });
|
|
36362
|
+
return runOrDiagnose(["drive", "comments", "delete", pos(fileId), pos(commentId), "--force"], { account });
|
|
36049
36363
|
});
|
|
36050
36364
|
server.registerTool("gog_drive_comments_reply", {
|
|
36051
36365
|
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 +36372,7 @@ function registerExtraDriveTools(server) {
|
|
|
36058
36372
|
account: accountParam
|
|
36059
36373
|
})
|
|
36060
36374
|
}, async ({ fileId, commentId, content, action, account }) => {
|
|
36061
|
-
const args = ["drive", "comments", "reply", fileId, commentId, content];
|
|
36375
|
+
const args = ["drive", "comments", "reply", pos(fileId), pos(commentId), pos(content)];
|
|
36062
36376
|
if (action) args.push(`--action=${action}`);
|
|
36063
36377
|
return runOrDiagnose(args, { account });
|
|
36064
36378
|
});
|
|
@@ -36071,7 +36385,7 @@ function registerExtraDriveTools(server) {
|
|
|
36071
36385
|
account: accountParam
|
|
36072
36386
|
})
|
|
36073
36387
|
}, async ({ fileId, commentId, account }) => {
|
|
36074
|
-
return runOrDiagnose(["drive", "comments", "resolve", fileId, commentId], { account });
|
|
36388
|
+
return runOrDiagnose(["drive", "comments", "resolve", pos(fileId), pos(commentId)], { account });
|
|
36075
36389
|
});
|
|
36076
36390
|
server.registerTool("gog_drive_comments_reopen", {
|
|
36077
36391
|
description: 'Reopen a previously resolved comment on a Drive file. To reopen while replying, use gog_drive_comments_reply with action: "reopen".',
|
|
@@ -36082,7 +36396,7 @@ function registerExtraDriveTools(server) {
|
|
|
36082
36396
|
account: accountParam
|
|
36083
36397
|
})
|
|
36084
36398
|
}, async ({ fileId, commentId, account }) => {
|
|
36085
|
-
return runOrDiagnose(["drive", "comments", "reopen", fileId, commentId], { account });
|
|
36399
|
+
return runOrDiagnose(["drive", "comments", "reopen", pos(fileId), pos(commentId)], { account });
|
|
36086
36400
|
});
|
|
36087
36401
|
server.registerTool("gog_drive_du", {
|
|
36088
36402
|
description: "Summarize Drive folder sizes (disk-usage style) starting from a folder.",
|
|
@@ -36168,7 +36482,7 @@ function registerExtraDriveTools(server) {
|
|
|
36168
36482
|
account: accountParam
|
|
36169
36483
|
})
|
|
36170
36484
|
}, async ({ fileId, max, page, all, account }) => {
|
|
36171
|
-
const args = ["drive", "revisions", "list", fileId];
|
|
36485
|
+
const args = ["drive", "revisions", "list", pos(fileId)];
|
|
36172
36486
|
pushPaginationFlags(args, { max, page, all });
|
|
36173
36487
|
return runOrDiagnose(args, { account });
|
|
36174
36488
|
});
|
|
@@ -36181,7 +36495,7 @@ function registerExtraDriveTools(server) {
|
|
|
36181
36495
|
account: accountParam
|
|
36182
36496
|
})
|
|
36183
36497
|
}, async ({ fileId, revisionId, account }) => {
|
|
36184
|
-
return runOrDiagnose(["drive", "revisions", "get", fileId, revisionId], { account });
|
|
36498
|
+
return runOrDiagnose(["drive", "revisions", "get", pos(fileId), pos(revisionId)], { account });
|
|
36185
36499
|
});
|
|
36186
36500
|
server.registerTool("gog_drive_shortcut_create", {
|
|
36187
36501
|
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 +36507,7 @@ function registerExtraDriveTools(server) {
|
|
|
36193
36507
|
account: accountParam
|
|
36194
36508
|
})
|
|
36195
36509
|
}, async ({ targetId, parent, name, account }) => {
|
|
36196
|
-
const args = ["drive", "shortcut", "create", targetId, `--parent=${parent}`];
|
|
36510
|
+
const args = ["drive", "shortcut", "create", pos(targetId), `--parent=${parent}`];
|
|
36197
36511
|
if (name) args.push(`--name=${name}`);
|
|
36198
36512
|
return runOrDiagnose(args, { account });
|
|
36199
36513
|
});
|
|
@@ -36234,7 +36548,7 @@ function registerExtraDriveTools(server) {
|
|
|
36234
36548
|
account: accountParam
|
|
36235
36549
|
})
|
|
36236
36550
|
}, async ({ name, language, view, adminAccess, account }) => {
|
|
36237
|
-
const args = ["drive", "labels", "get", name];
|
|
36551
|
+
const args = ["drive", "labels", "get", pos(name)];
|
|
36238
36552
|
if (language) args.push(`--language=${language}`);
|
|
36239
36553
|
if (view) args.push(`--view=${view}`);
|
|
36240
36554
|
if (adminAccess) args.push("--admin-access");
|
|
@@ -36251,7 +36565,7 @@ function registerExtraDriveTools(server) {
|
|
|
36251
36565
|
account: accountParam
|
|
36252
36566
|
})
|
|
36253
36567
|
}, async ({ fileId, max, pageToken, page, account }) => {
|
|
36254
|
-
const args = ["drive", "labels", "file", "list", fileId];
|
|
36568
|
+
const args = ["drive", "labels", "file", "list", pos(fileId)];
|
|
36255
36569
|
if (max !== void 0) args.push(`--max=${max}`);
|
|
36256
36570
|
const token = resolvePageToken({ pageToken, page });
|
|
36257
36571
|
if (token) args.push(`--page=${token}`);
|
|
@@ -36273,7 +36587,7 @@ function registerExtraDriveTools(server) {
|
|
|
36273
36587
|
account: accountParam
|
|
36274
36588
|
})
|
|
36275
36589
|
}, async ({ fileId, labelId, text, selection, integer: integer2, date: date5, user, unset, fieldsJson, account }) => {
|
|
36276
|
-
const args = ["drive", "labels", "file", "apply", fileId, labelId];
|
|
36590
|
+
const args = ["drive", "labels", "file", "apply", pos(fileId), pos(labelId)];
|
|
36277
36591
|
if (text) for (const t of text) args.push(`--text=${t}`);
|
|
36278
36592
|
if (selection) for (const s of selection) args.push(`--selection=${s}`);
|
|
36279
36593
|
if (integer2) for (const i of integer2) args.push(`--integer=${i}`);
|
|
@@ -36292,7 +36606,7 @@ function registerExtraDriveTools(server) {
|
|
|
36292
36606
|
account: accountParam
|
|
36293
36607
|
})
|
|
36294
36608
|
}, async ({ fileId, labelId, account }) => {
|
|
36295
|
-
return runOrDiagnose(["drive", "labels", "file", "remove", fileId, labelId, "--force"], { account });
|
|
36609
|
+
return runOrDiagnose(["drive", "labels", "file", "remove", pos(fileId), pos(labelId), "--force"], { account });
|
|
36296
36610
|
});
|
|
36297
36611
|
server.registerTool("gog_drive_activity", {
|
|
36298
36612
|
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 +36679,7 @@ function registerExtraDriveTools(server) {
|
|
|
36365
36679
|
account: accountParam
|
|
36366
36680
|
})
|
|
36367
36681
|
}, async ({ user, file: file2, parent, depth, max, noAllDrives, account }) => {
|
|
36368
|
-
const args = ["drive", "audit", "user", user];
|
|
36682
|
+
const args = ["drive", "audit", "user", pos(user)];
|
|
36369
36683
|
if (file2) args.push(`--file=${file2}`);
|
|
36370
36684
|
if (parent) args.push(`--parent=${parent}`);
|
|
36371
36685
|
if (depth !== void 0) args.push(`--depth=${depth}`);
|