gogcli-mcp 2.18.3 → 2.19.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 +278 -3
- package/dist/lib.js +279 -4
- package/manifest.json +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +6 -0
- package/src/lib.ts +1 -0
- package/src/remote-runner.ts +49 -0
- package/src/timestamps.ts +312 -0
- package/src/tools/utils.ts +14 -2
- package/src/worker.ts +1 -1
- package/tests/remote-runner.test.ts +53 -0
- package/tests/timestamps.test.ts +318 -0
- package/tests/tools/utils.test.ts +19 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.19.0"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "gogcli",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
|
|
18
|
-
"version": "2.
|
|
18
|
+
"version": "2.19.0",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
package/dist/index.js
CHANGED
|
@@ -3644,7 +3644,12 @@ var require_fast_uri = __commonJS({
|
|
|
3644
3644
|
}
|
|
3645
3645
|
function resolve(baseURI, relativeURI, options) {
|
|
3646
3646
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3647
|
-
const
|
|
3647
|
+
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
3648
|
+
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
3649
|
+
if (baseMalformed || relativeMalformed) {
|
|
3650
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3651
|
+
}
|
|
3652
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3648
3653
|
schemelessOptions.skipEscape = true;
|
|
3649
3654
|
return serialize(resolved, schemelessOptions);
|
|
3650
3655
|
}
|
|
@@ -3770,6 +3775,7 @@ var require_fast_uri = __commonJS({
|
|
|
3770
3775
|
}
|
|
3771
3776
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3772
3777
|
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3778
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
3773
3779
|
function getParseError(parsed, matches) {
|
|
3774
3780
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3775
3781
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3804,6 +3810,20 @@ var require_fast_uri = __commonJS({
|
|
|
3804
3810
|
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3805
3811
|
malformedAuthorityOrPort = true;
|
|
3806
3812
|
}
|
|
3813
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
3814
|
+
if (introducerMatch !== null) {
|
|
3815
|
+
const region = introducerMatch[1];
|
|
3816
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
3817
|
+
if (normalizedRegion.length >= 2) {
|
|
3818
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
3819
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
3820
|
+
malformedAuthorityOrPort = true;
|
|
3821
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
3822
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
3823
|
+
malformedAuthorityOrPort = true;
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3807
3827
|
const matches = uri.match(URI_PARSE);
|
|
3808
3828
|
if (matches) {
|
|
3809
3829
|
parsed.scheme = matches[1];
|
|
@@ -31285,6 +31305,198 @@ async function runBinary(args, options = {}) {
|
|
|
31285
31305
|
return spawnExecutor(fullArgs, { timeout, interactive: false, spawner, binary: true });
|
|
31286
31306
|
}
|
|
31287
31307
|
|
|
31308
|
+
// src/timestamps.ts
|
|
31309
|
+
var DEFAULT_DISPLAY_TZ = "America/New_York";
|
|
31310
|
+
function isValidTimeZone(tz) {
|
|
31311
|
+
try {
|
|
31312
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
31313
|
+
return true;
|
|
31314
|
+
} catch {
|
|
31315
|
+
return false;
|
|
31316
|
+
}
|
|
31317
|
+
}
|
|
31318
|
+
function displayTimeZone() {
|
|
31319
|
+
const configured = readEnvVar("DISPLAY_TZ");
|
|
31320
|
+
if (configured && isValidTimeZone(configured)) return configured;
|
|
31321
|
+
return DEFAULT_DISPLAY_TZ;
|
|
31322
|
+
}
|
|
31323
|
+
function naiveSourceTimeZone() {
|
|
31324
|
+
const configured = readEnvVar("GOG_TIMEZONE");
|
|
31325
|
+
if (configured && isValidTimeZone(configured)) return configured;
|
|
31326
|
+
return displayTimeZone();
|
|
31327
|
+
}
|
|
31328
|
+
function offsetAt(instant, tz) {
|
|
31329
|
+
const w = wallPartsIn(instant, tz);
|
|
31330
|
+
const asUTC = Date.UTC(w.year, w.month - 1, w.day, w.hour, w.minute, w.second, instant.getUTCMilliseconds());
|
|
31331
|
+
const minutes = Math.round((asUTC - instant.getTime()) / 6e4);
|
|
31332
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
31333
|
+
const abs = Math.abs(minutes);
|
|
31334
|
+
return `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;
|
|
31335
|
+
}
|
|
31336
|
+
function wallPartsIn(instant, tz) {
|
|
31337
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
31338
|
+
timeZone: tz,
|
|
31339
|
+
year: "numeric",
|
|
31340
|
+
month: "2-digit",
|
|
31341
|
+
day: "2-digit",
|
|
31342
|
+
hour: "2-digit",
|
|
31343
|
+
minute: "2-digit",
|
|
31344
|
+
second: "2-digit",
|
|
31345
|
+
// h23 pins midnight to hour 00; without it some ICU builds render hour 24.
|
|
31346
|
+
hourCycle: "h23"
|
|
31347
|
+
}).formatToParts(instant);
|
|
31348
|
+
const out = {};
|
|
31349
|
+
for (const p of parts) {
|
|
31350
|
+
if (p.type !== "literal") out[p.type] = Number(p.value);
|
|
31351
|
+
}
|
|
31352
|
+
return out;
|
|
31353
|
+
}
|
|
31354
|
+
function wallTimeToInstant(y, mo, d, h, mi, s, ms, tz) {
|
|
31355
|
+
let guess = Date.UTC(y, mo - 1, d, h, mi, s, ms);
|
|
31356
|
+
for (let i = 0; i < 2; i += 1) {
|
|
31357
|
+
const seen = wallPartsIn(new Date(guess), tz);
|
|
31358
|
+
const seenUTC = Date.UTC(seen.year, seen.month - 1, seen.day, seen.hour, seen.minute, seen.second, ms);
|
|
31359
|
+
const drift = Date.UTC(y, mo - 1, d, h, mi, s, ms) - seenUTC;
|
|
31360
|
+
if (drift === 0) break;
|
|
31361
|
+
guess += drift;
|
|
31362
|
+
}
|
|
31363
|
+
return new Date(guess);
|
|
31364
|
+
}
|
|
31365
|
+
function pad(n, width = 2) {
|
|
31366
|
+
return String(n).padStart(width, "0");
|
|
31367
|
+
}
|
|
31368
|
+
function isoWithOffset(instant, tz, offset) {
|
|
31369
|
+
const w = wallPartsIn(instant, tz);
|
|
31370
|
+
const msPart = instant.getUTCMilliseconds();
|
|
31371
|
+
const frac = msPart ? `.${pad(msPart, 3)}` : "";
|
|
31372
|
+
return `${pad(w.year, 4)}-${pad(w.month)}-${pad(w.day)}T${pad(w.hour)}:${pad(w.minute)}:${pad(w.second)}${frac}${offset}`;
|
|
31373
|
+
}
|
|
31374
|
+
function formatInstant(instant, tz = displayTimeZone()) {
|
|
31375
|
+
const offset = offsetAt(instant, tz);
|
|
31376
|
+
const display = new Intl.DateTimeFormat("en-US", {
|
|
31377
|
+
timeZone: tz,
|
|
31378
|
+
weekday: "short",
|
|
31379
|
+
month: "short",
|
|
31380
|
+
day: "numeric",
|
|
31381
|
+
year: "numeric",
|
|
31382
|
+
hour: "numeric",
|
|
31383
|
+
minute: "2-digit",
|
|
31384
|
+
timeZoneName: "short"
|
|
31385
|
+
}).format(instant);
|
|
31386
|
+
return { iso: isoWithOffset(instant, tz, offset), display };
|
|
31387
|
+
}
|
|
31388
|
+
var TIMESTAMP_KEYS = /* @__PURE__ */ new Set([
|
|
31389
|
+
"date",
|
|
31390
|
+
// gog gmail message/thread listings ("2026-07-28 03:36")
|
|
31391
|
+
"dateTime",
|
|
31392
|
+
// Calendar event start/end
|
|
31393
|
+
"internalDate",
|
|
31394
|
+
// Gmail, epoch milliseconds (authoritative)
|
|
31395
|
+
"modifiedTime",
|
|
31396
|
+
// Drive
|
|
31397
|
+
"createdTime",
|
|
31398
|
+
// Drive
|
|
31399
|
+
"createTime",
|
|
31400
|
+
"updateTime",
|
|
31401
|
+
"updated",
|
|
31402
|
+
"originalStartTime",
|
|
31403
|
+
"expirationTime",
|
|
31404
|
+
"lastModified",
|
|
31405
|
+
"sentAt",
|
|
31406
|
+
"viewedAt",
|
|
31407
|
+
"modifiedAt",
|
|
31408
|
+
"fetchedBodyAt",
|
|
31409
|
+
"asOf"
|
|
31410
|
+
]);
|
|
31411
|
+
var ZONE_NAME_KEYS = /* @__PURE__ */ new Set(["timeZone", "timezone"]);
|
|
31412
|
+
var RFC3339_WITH_OFFSET = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d{1,9}))?(Z|[+-]\d{2}:?\d{2})$/;
|
|
31413
|
+
var NAIVE_DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d{1,9}))?$/;
|
|
31414
|
+
var EPOCH_MILLIS = /^\d{13}$/;
|
|
31415
|
+
var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
31416
|
+
function isRealCalendarDate(p) {
|
|
31417
|
+
const utc = new Date(Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second));
|
|
31418
|
+
return utc.getUTCFullYear() === p.year && utc.getUTCMonth() === p.month - 1 && utc.getUTCDate() === p.day && utc.getUTCHours() === p.hour && utc.getUTCMinutes() === p.minute && utc.getUTCSeconds() === p.second;
|
|
31419
|
+
}
|
|
31420
|
+
function parseTimestampValue(key, value, assumeNaiveIn) {
|
|
31421
|
+
if (typeof value !== "string") return null;
|
|
31422
|
+
const raw = value.trim();
|
|
31423
|
+
if (raw === "" || DATE_ONLY.test(raw)) return null;
|
|
31424
|
+
if (key === "internalDate" && EPOCH_MILLIS.test(raw)) {
|
|
31425
|
+
return new Date(Number(raw));
|
|
31426
|
+
}
|
|
31427
|
+
if (RFC3339_WITH_OFFSET.test(raw)) {
|
|
31428
|
+
const parsed = new Date(raw.replace(" ", "T"));
|
|
31429
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
31430
|
+
}
|
|
31431
|
+
const naive = NAIVE_DATE_TIME.exec(raw);
|
|
31432
|
+
if (naive) {
|
|
31433
|
+
const [, y, mo, d, h, mi, s, frac] = naive;
|
|
31434
|
+
const ms = frac ? Number(frac.padEnd(3, "0").slice(0, 3)) : 0;
|
|
31435
|
+
const parts = {
|
|
31436
|
+
year: Number(y),
|
|
31437
|
+
month: Number(mo),
|
|
31438
|
+
day: Number(d),
|
|
31439
|
+
hour: Number(h),
|
|
31440
|
+
minute: Number(mi),
|
|
31441
|
+
second: Number(s ?? "0")
|
|
31442
|
+
};
|
|
31443
|
+
if (!isRealCalendarDate(parts)) return null;
|
|
31444
|
+
return wallTimeToInstant(
|
|
31445
|
+
parts.year,
|
|
31446
|
+
parts.month,
|
|
31447
|
+
parts.day,
|
|
31448
|
+
parts.hour,
|
|
31449
|
+
parts.minute,
|
|
31450
|
+
parts.second,
|
|
31451
|
+
ms,
|
|
31452
|
+
assumeNaiveIn
|
|
31453
|
+
);
|
|
31454
|
+
}
|
|
31455
|
+
return null;
|
|
31456
|
+
}
|
|
31457
|
+
function walk(node, tz, naiveTz) {
|
|
31458
|
+
let changed = false;
|
|
31459
|
+
if (Array.isArray(node)) {
|
|
31460
|
+
for (const item of node) {
|
|
31461
|
+
if (walk(item, tz, naiveTz)) changed = true;
|
|
31462
|
+
}
|
|
31463
|
+
return changed;
|
|
31464
|
+
}
|
|
31465
|
+
if (node === null || typeof node !== "object") return false;
|
|
31466
|
+
const obj = node;
|
|
31467
|
+
for (const key of Object.keys(obj)) {
|
|
31468
|
+
const value = obj[key];
|
|
31469
|
+
if (value !== null && typeof value === "object") {
|
|
31470
|
+
if (walk(value, tz, naiveTz)) changed = true;
|
|
31471
|
+
continue;
|
|
31472
|
+
}
|
|
31473
|
+
if (ZONE_NAME_KEYS.has(key) || !TIMESTAMP_KEYS.has(key)) continue;
|
|
31474
|
+
const instant = parseTimestampValue(key, value, naiveTz);
|
|
31475
|
+
if (!instant) continue;
|
|
31476
|
+
const { iso, display } = formatInstant(instant, tz);
|
|
31477
|
+
obj[key] = iso;
|
|
31478
|
+
obj[`${key}Display`] = display;
|
|
31479
|
+
changed = true;
|
|
31480
|
+
}
|
|
31481
|
+
return changed;
|
|
31482
|
+
}
|
|
31483
|
+
function detectIndent(text) {
|
|
31484
|
+
const match = /\n(\s+)\S/.exec(text);
|
|
31485
|
+
return match ? match[1].replace(/\t/g, " ").length : 0;
|
|
31486
|
+
}
|
|
31487
|
+
function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSourceTimeZone()) {
|
|
31488
|
+
const trimmed = text.trim();
|
|
31489
|
+
if (trimmed === "" || !/^[[{]/.test(trimmed)) return text;
|
|
31490
|
+
let parsed;
|
|
31491
|
+
try {
|
|
31492
|
+
parsed = JSON.parse(trimmed);
|
|
31493
|
+
} catch {
|
|
31494
|
+
return text;
|
|
31495
|
+
}
|
|
31496
|
+
if (!walk(parsed, tz, naiveTz)) return text;
|
|
31497
|
+
return JSON.stringify(parsed, null, detectIndent(text));
|
|
31498
|
+
}
|
|
31499
|
+
|
|
31288
31500
|
// src/tools/utils.ts
|
|
31289
31501
|
var PAYLOAD_INLINE_MAX = 4096;
|
|
31290
31502
|
function payloadArg(inlineFlag, fileFlag, value, ext) {
|
|
@@ -31385,7 +31597,8 @@ ${accounts || "(none)"}${hint}`);
|
|
|
31385
31597
|
}
|
|
31386
31598
|
async function runOrDiagnose(args, options) {
|
|
31387
31599
|
try {
|
|
31388
|
-
|
|
31600
|
+
const raw = await run(args, options);
|
|
31601
|
+
return rawTextResult(options.lossless ? raw : normalizeTimestamps(raw));
|
|
31389
31602
|
} catch (err) {
|
|
31390
31603
|
return diagnose(err);
|
|
31391
31604
|
}
|
|
@@ -32859,7 +33072,7 @@ function registerTasksTools(server) {
|
|
|
32859
33072
|
}
|
|
32860
33073
|
|
|
32861
33074
|
// src/server.ts
|
|
32862
|
-
var VERSION = true ? "2.
|
|
33075
|
+
var VERSION = true ? "2.19.0" : "0.0.0";
|
|
32863
33076
|
var BASE_TOOL_REGISTRARS = [
|
|
32864
33077
|
registerApiTools,
|
|
32865
33078
|
registerAuthTools,
|
|
@@ -32874,7 +33087,69 @@ var BASE_TOOL_REGISTRARS = [
|
|
|
32874
33087
|
registerTasksTools
|
|
32875
33088
|
];
|
|
32876
33089
|
|
|
33090
|
+
// src/connector-runtime.ts
|
|
33091
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
33092
|
+
var DEADLINE_GRACE_MS = 5e3;
|
|
33093
|
+
var RUNNER_GOG_FAILED = 422;
|
|
33094
|
+
var RUNNER_DRAINING = 503;
|
|
33095
|
+
function makeFlyExecutor(endpoint, key) {
|
|
33096
|
+
return async (args, opts) => {
|
|
33097
|
+
const deadlineMs = (opts?.timeout ?? DEFAULT_TIMEOUT_MS) + DEADLINE_GRACE_MS;
|
|
33098
|
+
let res;
|
|
33099
|
+
try {
|
|
33100
|
+
res = await fetch(endpoint + "/run", {
|
|
33101
|
+
method: "POST",
|
|
33102
|
+
headers: {
|
|
33103
|
+
Authorization: "Bearer " + key,
|
|
33104
|
+
"Content-Type": "application/json"
|
|
33105
|
+
},
|
|
33106
|
+
body: JSON.stringify({ args }),
|
|
33107
|
+
signal: AbortSignal.timeout(deadlineMs)
|
|
33108
|
+
});
|
|
33109
|
+
} catch (err) {
|
|
33110
|
+
const name = err instanceof Error ? err.name : "";
|
|
33111
|
+
if (name === "TimeoutError" || name === "AbortError") {
|
|
33112
|
+
throw new Error(
|
|
33113
|
+
`gog-runner did not respond within ${deadlineMs}ms (${endpoint}) \u2014 the Fly backend may be cold or wedged`
|
|
33114
|
+
);
|
|
33115
|
+
}
|
|
33116
|
+
throw err;
|
|
33117
|
+
}
|
|
33118
|
+
if (!res.ok) {
|
|
33119
|
+
const body = await res.json().catch(() => null);
|
|
33120
|
+
const detail = body && typeof body.error === "string" ? body.stderr && body.stderr.trim() && body.stderr.trim() !== body.error.trim() ? `${body.error}
|
|
33121
|
+
${body.stderr}` : body.error : "";
|
|
33122
|
+
if (res.status === RUNNER_GOG_FAILED) {
|
|
33123
|
+
throw new Error(detail || "gog failed on the runner (no detail supplied)");
|
|
33124
|
+
}
|
|
33125
|
+
if (res.status === RUNNER_DRAINING || body?.retryable === true) {
|
|
33126
|
+
throw new Error(
|
|
33127
|
+
`gog-runner is restarting; retry this call.${detail ? ` ${detail}` : ""}`
|
|
33128
|
+
);
|
|
33129
|
+
}
|
|
33130
|
+
if (detail) {
|
|
33131
|
+
throw new Error(detail);
|
|
33132
|
+
}
|
|
33133
|
+
throw new Error(
|
|
33134
|
+
`gog-runner HTTP ${res.status}: the response did not come from the runner, so the request never reached gog. The backend Machine was most likely starting or shutting down \u2014 this is transient, retry the same call.`
|
|
33135
|
+
);
|
|
33136
|
+
}
|
|
33137
|
+
const { stdout } = await res.json();
|
|
33138
|
+
return stdout;
|
|
33139
|
+
};
|
|
33140
|
+
}
|
|
33141
|
+
|
|
33142
|
+
// src/remote-runner.ts
|
|
33143
|
+
function useRemoteGogRunner(env = process.env) {
|
|
33144
|
+
const endpoint = readEnvVar("GOG_RUNNER_URL", { env });
|
|
33145
|
+
const key = readEnvVar("GOG_RUNNER_KEY", { env });
|
|
33146
|
+
if (!endpoint || !key) return false;
|
|
33147
|
+
runExecutor.enterWith({ executor: makeFlyExecutor(endpoint.replace(/\/+$/, ""), key) });
|
|
33148
|
+
return true;
|
|
33149
|
+
}
|
|
33150
|
+
|
|
32877
33151
|
// src/index.ts
|
|
33152
|
+
useRemoteGogRunner();
|
|
32878
33153
|
await runMcp({
|
|
32879
33154
|
name: "gogcli",
|
|
32880
33155
|
version: VERSION,
|
package/dist/lib.js
CHANGED
|
@@ -3643,7 +3643,12 @@ var require_fast_uri = __commonJS({
|
|
|
3643
3643
|
}
|
|
3644
3644
|
function resolve(baseURI, relativeURI, options) {
|
|
3645
3645
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3646
|
-
const
|
|
3646
|
+
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
3647
|
+
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
3648
|
+
if (baseMalformed || relativeMalformed) {
|
|
3649
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3650
|
+
}
|
|
3651
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3647
3652
|
schemelessOptions.skipEscape = true;
|
|
3648
3653
|
return serialize(resolved, schemelessOptions);
|
|
3649
3654
|
}
|
|
@@ -3769,6 +3774,7 @@ var require_fast_uri = __commonJS({
|
|
|
3769
3774
|
}
|
|
3770
3775
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3771
3776
|
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3777
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
3772
3778
|
function getParseError(parsed, matches) {
|
|
3773
3779
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3774
3780
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3803,6 +3809,20 @@ var require_fast_uri = __commonJS({
|
|
|
3803
3809
|
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3804
3810
|
malformedAuthorityOrPort = true;
|
|
3805
3811
|
}
|
|
3812
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
3813
|
+
if (introducerMatch !== null) {
|
|
3814
|
+
const region = introducerMatch[1];
|
|
3815
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
3816
|
+
if (normalizedRegion.length >= 2) {
|
|
3817
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
3818
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
3819
|
+
malformedAuthorityOrPort = true;
|
|
3820
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
3821
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
3822
|
+
malformedAuthorityOrPort = true;
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3806
3826
|
const matches = uri.match(URI_PARSE);
|
|
3807
3827
|
if (matches) {
|
|
3808
3828
|
parsed.scheme = matches[1];
|
|
@@ -23183,6 +23203,198 @@ async function runBinary(args, options = {}) {
|
|
|
23183
23203
|
return spawnExecutor(fullArgs, { timeout, interactive: false, spawner, binary: true });
|
|
23184
23204
|
}
|
|
23185
23205
|
|
|
23206
|
+
// src/timestamps.ts
|
|
23207
|
+
var DEFAULT_DISPLAY_TZ = "America/New_York";
|
|
23208
|
+
function isValidTimeZone(tz) {
|
|
23209
|
+
try {
|
|
23210
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
23211
|
+
return true;
|
|
23212
|
+
} catch {
|
|
23213
|
+
return false;
|
|
23214
|
+
}
|
|
23215
|
+
}
|
|
23216
|
+
function displayTimeZone() {
|
|
23217
|
+
const configured = readEnvVar("DISPLAY_TZ");
|
|
23218
|
+
if (configured && isValidTimeZone(configured)) return configured;
|
|
23219
|
+
return DEFAULT_DISPLAY_TZ;
|
|
23220
|
+
}
|
|
23221
|
+
function naiveSourceTimeZone() {
|
|
23222
|
+
const configured = readEnvVar("GOG_TIMEZONE");
|
|
23223
|
+
if (configured && isValidTimeZone(configured)) return configured;
|
|
23224
|
+
return displayTimeZone();
|
|
23225
|
+
}
|
|
23226
|
+
function offsetAt(instant, tz) {
|
|
23227
|
+
const w = wallPartsIn(instant, tz);
|
|
23228
|
+
const asUTC = Date.UTC(w.year, w.month - 1, w.day, w.hour, w.minute, w.second, instant.getUTCMilliseconds());
|
|
23229
|
+
const minutes = Math.round((asUTC - instant.getTime()) / 6e4);
|
|
23230
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
23231
|
+
const abs = Math.abs(minutes);
|
|
23232
|
+
return `${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`;
|
|
23233
|
+
}
|
|
23234
|
+
function wallPartsIn(instant, tz) {
|
|
23235
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
23236
|
+
timeZone: tz,
|
|
23237
|
+
year: "numeric",
|
|
23238
|
+
month: "2-digit",
|
|
23239
|
+
day: "2-digit",
|
|
23240
|
+
hour: "2-digit",
|
|
23241
|
+
minute: "2-digit",
|
|
23242
|
+
second: "2-digit",
|
|
23243
|
+
// h23 pins midnight to hour 00; without it some ICU builds render hour 24.
|
|
23244
|
+
hourCycle: "h23"
|
|
23245
|
+
}).formatToParts(instant);
|
|
23246
|
+
const out = {};
|
|
23247
|
+
for (const p of parts) {
|
|
23248
|
+
if (p.type !== "literal") out[p.type] = Number(p.value);
|
|
23249
|
+
}
|
|
23250
|
+
return out;
|
|
23251
|
+
}
|
|
23252
|
+
function wallTimeToInstant(y, mo, d, h, mi, s, ms, tz) {
|
|
23253
|
+
let guess = Date.UTC(y, mo - 1, d, h, mi, s, ms);
|
|
23254
|
+
for (let i = 0; i < 2; i += 1) {
|
|
23255
|
+
const seen = wallPartsIn(new Date(guess), tz);
|
|
23256
|
+
const seenUTC = Date.UTC(seen.year, seen.month - 1, seen.day, seen.hour, seen.minute, seen.second, ms);
|
|
23257
|
+
const drift = Date.UTC(y, mo - 1, d, h, mi, s, ms) - seenUTC;
|
|
23258
|
+
if (drift === 0) break;
|
|
23259
|
+
guess += drift;
|
|
23260
|
+
}
|
|
23261
|
+
return new Date(guess);
|
|
23262
|
+
}
|
|
23263
|
+
function pad(n, width = 2) {
|
|
23264
|
+
return String(n).padStart(width, "0");
|
|
23265
|
+
}
|
|
23266
|
+
function isoWithOffset(instant, tz, offset) {
|
|
23267
|
+
const w = wallPartsIn(instant, tz);
|
|
23268
|
+
const msPart = instant.getUTCMilliseconds();
|
|
23269
|
+
const frac = msPart ? `.${pad(msPart, 3)}` : "";
|
|
23270
|
+
return `${pad(w.year, 4)}-${pad(w.month)}-${pad(w.day)}T${pad(w.hour)}:${pad(w.minute)}:${pad(w.second)}${frac}${offset}`;
|
|
23271
|
+
}
|
|
23272
|
+
function formatInstant(instant, tz = displayTimeZone()) {
|
|
23273
|
+
const offset = offsetAt(instant, tz);
|
|
23274
|
+
const display = new Intl.DateTimeFormat("en-US", {
|
|
23275
|
+
timeZone: tz,
|
|
23276
|
+
weekday: "short",
|
|
23277
|
+
month: "short",
|
|
23278
|
+
day: "numeric",
|
|
23279
|
+
year: "numeric",
|
|
23280
|
+
hour: "numeric",
|
|
23281
|
+
minute: "2-digit",
|
|
23282
|
+
timeZoneName: "short"
|
|
23283
|
+
}).format(instant);
|
|
23284
|
+
return { iso: isoWithOffset(instant, tz, offset), display };
|
|
23285
|
+
}
|
|
23286
|
+
var TIMESTAMP_KEYS = /* @__PURE__ */ new Set([
|
|
23287
|
+
"date",
|
|
23288
|
+
// gog gmail message/thread listings ("2026-07-28 03:36")
|
|
23289
|
+
"dateTime",
|
|
23290
|
+
// Calendar event start/end
|
|
23291
|
+
"internalDate",
|
|
23292
|
+
// Gmail, epoch milliseconds (authoritative)
|
|
23293
|
+
"modifiedTime",
|
|
23294
|
+
// Drive
|
|
23295
|
+
"createdTime",
|
|
23296
|
+
// Drive
|
|
23297
|
+
"createTime",
|
|
23298
|
+
"updateTime",
|
|
23299
|
+
"updated",
|
|
23300
|
+
"originalStartTime",
|
|
23301
|
+
"expirationTime",
|
|
23302
|
+
"lastModified",
|
|
23303
|
+
"sentAt",
|
|
23304
|
+
"viewedAt",
|
|
23305
|
+
"modifiedAt",
|
|
23306
|
+
"fetchedBodyAt",
|
|
23307
|
+
"asOf"
|
|
23308
|
+
]);
|
|
23309
|
+
var ZONE_NAME_KEYS = /* @__PURE__ */ new Set(["timeZone", "timezone"]);
|
|
23310
|
+
var RFC3339_WITH_OFFSET = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d{1,9}))?(Z|[+-]\d{2}:?\d{2})$/;
|
|
23311
|
+
var NAIVE_DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d{1,9}))?$/;
|
|
23312
|
+
var EPOCH_MILLIS = /^\d{13}$/;
|
|
23313
|
+
var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
23314
|
+
function isRealCalendarDate(p) {
|
|
23315
|
+
const utc = new Date(Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second));
|
|
23316
|
+
return utc.getUTCFullYear() === p.year && utc.getUTCMonth() === p.month - 1 && utc.getUTCDate() === p.day && utc.getUTCHours() === p.hour && utc.getUTCMinutes() === p.minute && utc.getUTCSeconds() === p.second;
|
|
23317
|
+
}
|
|
23318
|
+
function parseTimestampValue(key, value, assumeNaiveIn) {
|
|
23319
|
+
if (typeof value !== "string") return null;
|
|
23320
|
+
const raw = value.trim();
|
|
23321
|
+
if (raw === "" || DATE_ONLY.test(raw)) return null;
|
|
23322
|
+
if (key === "internalDate" && EPOCH_MILLIS.test(raw)) {
|
|
23323
|
+
return new Date(Number(raw));
|
|
23324
|
+
}
|
|
23325
|
+
if (RFC3339_WITH_OFFSET.test(raw)) {
|
|
23326
|
+
const parsed = new Date(raw.replace(" ", "T"));
|
|
23327
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
23328
|
+
}
|
|
23329
|
+
const naive = NAIVE_DATE_TIME.exec(raw);
|
|
23330
|
+
if (naive) {
|
|
23331
|
+
const [, y, mo, d, h, mi, s, frac] = naive;
|
|
23332
|
+
const ms = frac ? Number(frac.padEnd(3, "0").slice(0, 3)) : 0;
|
|
23333
|
+
const parts = {
|
|
23334
|
+
year: Number(y),
|
|
23335
|
+
month: Number(mo),
|
|
23336
|
+
day: Number(d),
|
|
23337
|
+
hour: Number(h),
|
|
23338
|
+
minute: Number(mi),
|
|
23339
|
+
second: Number(s ?? "0")
|
|
23340
|
+
};
|
|
23341
|
+
if (!isRealCalendarDate(parts)) return null;
|
|
23342
|
+
return wallTimeToInstant(
|
|
23343
|
+
parts.year,
|
|
23344
|
+
parts.month,
|
|
23345
|
+
parts.day,
|
|
23346
|
+
parts.hour,
|
|
23347
|
+
parts.minute,
|
|
23348
|
+
parts.second,
|
|
23349
|
+
ms,
|
|
23350
|
+
assumeNaiveIn
|
|
23351
|
+
);
|
|
23352
|
+
}
|
|
23353
|
+
return null;
|
|
23354
|
+
}
|
|
23355
|
+
function walk(node, tz, naiveTz) {
|
|
23356
|
+
let changed = false;
|
|
23357
|
+
if (Array.isArray(node)) {
|
|
23358
|
+
for (const item of node) {
|
|
23359
|
+
if (walk(item, tz, naiveTz)) changed = true;
|
|
23360
|
+
}
|
|
23361
|
+
return changed;
|
|
23362
|
+
}
|
|
23363
|
+
if (node === null || typeof node !== "object") return false;
|
|
23364
|
+
const obj = node;
|
|
23365
|
+
for (const key of Object.keys(obj)) {
|
|
23366
|
+
const value = obj[key];
|
|
23367
|
+
if (value !== null && typeof value === "object") {
|
|
23368
|
+
if (walk(value, tz, naiveTz)) changed = true;
|
|
23369
|
+
continue;
|
|
23370
|
+
}
|
|
23371
|
+
if (ZONE_NAME_KEYS.has(key) || !TIMESTAMP_KEYS.has(key)) continue;
|
|
23372
|
+
const instant = parseTimestampValue(key, value, naiveTz);
|
|
23373
|
+
if (!instant) continue;
|
|
23374
|
+
const { iso, display } = formatInstant(instant, tz);
|
|
23375
|
+
obj[key] = iso;
|
|
23376
|
+
obj[`${key}Display`] = display;
|
|
23377
|
+
changed = true;
|
|
23378
|
+
}
|
|
23379
|
+
return changed;
|
|
23380
|
+
}
|
|
23381
|
+
function detectIndent(text) {
|
|
23382
|
+
const match = /\n(\s+)\S/.exec(text);
|
|
23383
|
+
return match ? match[1].replace(/\t/g, " ").length : 0;
|
|
23384
|
+
}
|
|
23385
|
+
function normalizeTimestamps(text, tz = displayTimeZone(), naiveTz = naiveSourceTimeZone()) {
|
|
23386
|
+
const trimmed = text.trim();
|
|
23387
|
+
if (trimmed === "" || !/^[[{]/.test(trimmed)) return text;
|
|
23388
|
+
let parsed;
|
|
23389
|
+
try {
|
|
23390
|
+
parsed = JSON.parse(trimmed);
|
|
23391
|
+
} catch {
|
|
23392
|
+
return text;
|
|
23393
|
+
}
|
|
23394
|
+
if (!walk(parsed, tz, naiveTz)) return text;
|
|
23395
|
+
return JSON.stringify(parsed, null, detectIndent(text));
|
|
23396
|
+
}
|
|
23397
|
+
|
|
23186
23398
|
// src/tools/utils.ts
|
|
23187
23399
|
var PAYLOAD_INLINE_MAX = 4096;
|
|
23188
23400
|
function payloadArg(inlineFlag, fileFlag, value, ext) {
|
|
@@ -23288,7 +23500,8 @@ ${accounts || "(none)"}${hint}`);
|
|
|
23288
23500
|
}
|
|
23289
23501
|
async function runOrDiagnose(args, options) {
|
|
23290
23502
|
try {
|
|
23291
|
-
|
|
23503
|
+
const raw = await run(args, options);
|
|
23504
|
+
return rawTextResult(options.lossless ? raw : normalizeTimestamps(raw));
|
|
23292
23505
|
} catch (err) {
|
|
23293
23506
|
return diagnose(err);
|
|
23294
23507
|
}
|
|
@@ -24765,7 +24978,7 @@ function registerTasksTools(server) {
|
|
|
24765
24978
|
}
|
|
24766
24979
|
|
|
24767
24980
|
// src/server.ts
|
|
24768
|
-
var VERSION = true ? "2.
|
|
24981
|
+
var VERSION = true ? "2.19.0" : "0.0.0";
|
|
24769
24982
|
var BASE_TOOL_REGISTRARS = [
|
|
24770
24983
|
registerApiTools,
|
|
24771
24984
|
registerAuthTools,
|
|
@@ -24779,6 +24992,67 @@ var BASE_TOOL_REGISTRARS = [
|
|
|
24779
24992
|
registerSlidesTools,
|
|
24780
24993
|
registerTasksTools
|
|
24781
24994
|
];
|
|
24995
|
+
|
|
24996
|
+
// src/connector-runtime.ts
|
|
24997
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
24998
|
+
var DEADLINE_GRACE_MS = 5e3;
|
|
24999
|
+
var RUNNER_GOG_FAILED = 422;
|
|
25000
|
+
var RUNNER_DRAINING = 503;
|
|
25001
|
+
function makeFlyExecutor(endpoint, key) {
|
|
25002
|
+
return async (args, opts) => {
|
|
25003
|
+
const deadlineMs = (opts?.timeout ?? DEFAULT_TIMEOUT_MS) + DEADLINE_GRACE_MS;
|
|
25004
|
+
let res;
|
|
25005
|
+
try {
|
|
25006
|
+
res = await fetch(endpoint + "/run", {
|
|
25007
|
+
method: "POST",
|
|
25008
|
+
headers: {
|
|
25009
|
+
Authorization: "Bearer " + key,
|
|
25010
|
+
"Content-Type": "application/json"
|
|
25011
|
+
},
|
|
25012
|
+
body: JSON.stringify({ args }),
|
|
25013
|
+
signal: AbortSignal.timeout(deadlineMs)
|
|
25014
|
+
});
|
|
25015
|
+
} catch (err) {
|
|
25016
|
+
const name = err instanceof Error ? err.name : "";
|
|
25017
|
+
if (name === "TimeoutError" || name === "AbortError") {
|
|
25018
|
+
throw new Error(
|
|
25019
|
+
`gog-runner did not respond within ${deadlineMs}ms (${endpoint}) \u2014 the Fly backend may be cold or wedged`
|
|
25020
|
+
);
|
|
25021
|
+
}
|
|
25022
|
+
throw err;
|
|
25023
|
+
}
|
|
25024
|
+
if (!res.ok) {
|
|
25025
|
+
const body = await res.json().catch(() => null);
|
|
25026
|
+
const detail = body && typeof body.error === "string" ? body.stderr && body.stderr.trim() && body.stderr.trim() !== body.error.trim() ? `${body.error}
|
|
25027
|
+
${body.stderr}` : body.error : "";
|
|
25028
|
+
if (res.status === RUNNER_GOG_FAILED) {
|
|
25029
|
+
throw new Error(detail || "gog failed on the runner (no detail supplied)");
|
|
25030
|
+
}
|
|
25031
|
+
if (res.status === RUNNER_DRAINING || body?.retryable === true) {
|
|
25032
|
+
throw new Error(
|
|
25033
|
+
`gog-runner is restarting; retry this call.${detail ? ` ${detail}` : ""}`
|
|
25034
|
+
);
|
|
25035
|
+
}
|
|
25036
|
+
if (detail) {
|
|
25037
|
+
throw new Error(detail);
|
|
25038
|
+
}
|
|
25039
|
+
throw new Error(
|
|
25040
|
+
`gog-runner HTTP ${res.status}: the response did not come from the runner, so the request never reached gog. The backend Machine was most likely starting or shutting down \u2014 this is transient, retry the same call.`
|
|
25041
|
+
);
|
|
25042
|
+
}
|
|
25043
|
+
const { stdout } = await res.json();
|
|
25044
|
+
return stdout;
|
|
25045
|
+
};
|
|
25046
|
+
}
|
|
25047
|
+
|
|
25048
|
+
// src/remote-runner.ts
|
|
25049
|
+
function useRemoteGogRunner(env = process.env) {
|
|
25050
|
+
const endpoint = readEnvVar("GOG_RUNNER_URL", { env });
|
|
25051
|
+
const key = readEnvVar("GOG_RUNNER_KEY", { env });
|
|
25052
|
+
if (!endpoint || !key) return false;
|
|
25053
|
+
runExecutor.enterWith({ executor: makeFlyExecutor(endpoint.replace(/\/+$/, ""), key) });
|
|
25054
|
+
return true;
|
|
25055
|
+
}
|
|
24782
25056
|
export {
|
|
24783
25057
|
BASE_TOOL_REGISTRARS,
|
|
24784
25058
|
MIN_GOG_VERSION,
|
|
@@ -24808,5 +25082,6 @@ export {
|
|
|
24808
25082
|
run,
|
|
24809
25083
|
runBinary,
|
|
24810
25084
|
runExecutor,
|
|
24811
|
-
runOrDiagnose
|
|
25085
|
+
runOrDiagnose,
|
|
25086
|
+
useRemoteGogRunner
|
|
24812
25087
|
};
|