@lifeaitools/clauth 1.5.5 → 1.5.6
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/cli/commands/serve.js +210 -25
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -747,8 +747,12 @@ function dashboardHtml(port, whitelist, isStaged = false) {
|
|
|
747
747
|
<h3>Add New Service</h3>
|
|
748
748
|
<div class="add-row">
|
|
749
749
|
<div class="add-field">
|
|
750
|
-
<label>
|
|
751
|
-
<input class="add-input" id="add-name" type="text" placeholder="e.g. coolify-admin" autocomplete="off" spellcheck="false">
|
|
750
|
+
<label>Slug <span style="color:#475569;font-weight:400">(used in <code style="font-size:.72rem">clauth get <slug></code>)</span></label>
|
|
751
|
+
<input class="add-input" id="add-name" type="text" placeholder="e.g. coolify-admin" autocomplete="off" spellcheck="false" style="font-family:'Courier New',monospace">
|
|
752
|
+
</div>
|
|
753
|
+
<div class="add-field">
|
|
754
|
+
<label>Label <span style="color:#475569;font-weight:400">(display name)</span></label>
|
|
755
|
+
<input class="add-input" id="add-label" type="text" placeholder="e.g. Coolify Admin Token" autocomplete="off" spellcheck="false">
|
|
752
756
|
</div>
|
|
753
757
|
<div class="add-field">
|
|
754
758
|
<label>Key type</label>
|
|
@@ -756,6 +760,12 @@ function dashboardHtml(port, whitelist, isStaged = false) {
|
|
|
756
760
|
<option value="">Loading…</option>
|
|
757
761
|
</select>
|
|
758
762
|
</div>
|
|
763
|
+
</div>
|
|
764
|
+
<div class="add-row">
|
|
765
|
+
<div class="add-field">
|
|
766
|
+
<label>Description <span style="color:#475569;font-weight:400">(optional)</span></label>
|
|
767
|
+
<input class="add-input" id="add-description" type="text" placeholder="e.g. API token for Coolify deployments" autocomplete="off" spellcheck="false" style="width:420px">
|
|
768
|
+
</div>
|
|
759
769
|
<div class="add-field">
|
|
760
770
|
<label>Project <span style="color:#475569;font-weight:400">(optional)</span></label>
|
|
761
771
|
<input class="add-input" id="add-project" type="text" placeholder="e.g. marketing-engine" autocomplete="off" spellcheck="false">
|
|
@@ -1176,14 +1186,18 @@ function renderServiceGrid(services) {
|
|
|
1176
1186
|
grid.innerHTML = filtered.map(s => \`
|
|
1177
1187
|
<div class="card">
|
|
1178
1188
|
<div style="display:flex;align-items:flex-start;justify-content:space-between">
|
|
1179
|
-
<div>
|
|
1180
|
-
<div
|
|
1189
|
+
<div style="flex:1;min-width:0">
|
|
1190
|
+
<div style="display:flex;align-items:baseline;gap:8px;flex-wrap:wrap">
|
|
1191
|
+
<span class="card-name" id="label-display-\${s.name}">\${s.label && s.label !== s.name ? s.label : s.name}</span>
|
|
1192
|
+
<code style="font-family:'Courier New',monospace;font-size:.75rem;color:#64748b;background:rgba(100,116,139,.1);padding:1px 6px;border-radius:3px;letter-spacing:.3px">\${s.name}</code>
|
|
1193
|
+
</div>
|
|
1181
1194
|
<div style="display:flex;align-items:center;gap:6px;margin-top:2px">
|
|
1182
1195
|
<div class="card-type">\${s.key_type || "secret"}</div>
|
|
1183
1196
|
<span class="svc-badge \${s.enabled === false ? "off" : "on"}" id="badge-\${s.name}">\${s.enabled === false ? "disabled" : "enabled"}</span>
|
|
1184
1197
|
<span class="expiry-badge" id="expiry-\${s.name}" style="font-size:.65rem;border-radius:3px;padding:1px 6px;display:none"></span>
|
|
1185
1198
|
\${s.project ? \`<span style="font-size:.68rem;color:#3b82f6;background:rgba(59,130,246,.1);border:1px solid rgba(59,130,246,.2);border-radius:3px;padding:1px 6px">\${s.project}</span>\` : ""}
|
|
1186
1199
|
</div>
|
|
1200
|
+
\${s.description ? \`<div style="font-size:.78rem;color:#64748b;margin-top:4px;line-height:1.3">\${s.description}</div>\` : ""}
|
|
1187
1201
|
\${KEY_URLS[s.name] ? \`<a class="card-getkey" href="\${KEY_URLS[s.name]}" target="_blank" rel="noopener">↗ Get / rotate key</a>\` : ""}
|
|
1188
1202
|
\${(EXTRA_LINKS[s.name] || []).map(l => \`<a class="card-getkey" href="\${l.url}" target="_blank" rel="noopener" style="margin-left:0">\${l.label}</a>\`).join("")}
|
|
1189
1203
|
</div>
|
|
@@ -1197,14 +1211,22 @@ function renderServiceGrid(services) {
|
|
|
1197
1211
|
<button class="btn-project" onclick="toggleProjectEdit('\${s.name}')">\${s.project ? "✎ Project" : "+ Project"}</button>
|
|
1198
1212
|
<button class="btn \${s.enabled === false ? "btn-enable" : "btn-disable"}" id="togbtn-\${s.name}" onclick="toggleService('\${s.name}')">\${s.enabled === false ? "Enable" : "Disable"}</button>
|
|
1199
1213
|
<button class="btn-rotate" id="rotbtn-\${s.name}" style="display:none;background:#0e7490;border:1px solid #06b6d4;color:#cffafe;font-size:.75rem;padding:3px 8px;border-radius:4px;cursor:pointer" onclick="rotateKey('\${s.name}')">↻ Rotate</button>
|
|
1200
|
-
<button class="btn-rename" onclick="
|
|
1214
|
+
<button class="btn-rename" onclick="toggleLabelEdit('\${s.name}')" title="Edit display label">✏️</button>
|
|
1201
1215
|
<button class="btn-delete" onclick="deleteService('\${s.name}')" title="Delete service">✕</button>
|
|
1202
1216
|
</div>
|
|
1203
1217
|
<div class="rename-panel" id="rn-\${s.name}">
|
|
1204
|
-
<
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1218
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
|
|
1219
|
+
<span style="font-size:.72rem;color:#64748b">Edit label for</span>
|
|
1220
|
+
<code style="font-family:'Courier New',monospace;font-size:.75rem;color:#94a3b8;background:rgba(100,116,139,.1);padding:1px 5px;border-radius:3px">\${s.name}</code>
|
|
1221
|
+
<span style="font-size:.68rem;color:#475569">(slug unchanged)</span>
|
|
1222
|
+
</div>
|
|
1223
|
+
<div style="display:flex;gap:6px;align-items:center">
|
|
1224
|
+
<input class="rename-input" id="rn-input-\${s.name}" value="\${s.label || s.name}" spellcheck="false" autocomplete="off" placeholder="Human-readable label…"
|
|
1225
|
+
onkeydown="if(event.key==='Enter')saveLabel('\${s.name}');if(event.key==='Escape')toggleLabelEdit('\${s.name}')">
|
|
1226
|
+
<button class="btn" onclick="saveLabel('\${s.name}')" style="padding:4px 10px;font-size:.8rem">Save</button>
|
|
1227
|
+
<button class="btn" onclick="toggleLabelEdit('\${s.name}')" style="padding:4px 10px;font-size:.8rem;background:#1e293b">Cancel</button>
|
|
1228
|
+
<span class="rename-msg" id="rn-msg-\${s.name}"></span>
|
|
1229
|
+
</div>
|
|
1208
1230
|
</div>
|
|
1209
1231
|
<div class="project-edit" id="pe-\${s.name}">
|
|
1210
1232
|
<input type="text" id="pe-input-\${s.name}" value="\${s.project || ""}" placeholder="Project name…" spellcheck="false" autocomplete="off">
|
|
@@ -1428,39 +1450,50 @@ async function clearProject(name) {
|
|
|
1428
1450
|
}
|
|
1429
1451
|
|
|
1430
1452
|
// ── Rename service ───────────────────────────
|
|
1431
|
-
function
|
|
1453
|
+
function toggleLabelEdit(name) {
|
|
1432
1454
|
const panel = document.getElementById("rn-" + name);
|
|
1433
1455
|
const open = panel.style.display === "block";
|
|
1434
1456
|
panel.style.display = open ? "none" : "block";
|
|
1435
1457
|
if (!open) {
|
|
1436
1458
|
const inp = document.getElementById("rn-input-" + name);
|
|
1437
|
-
|
|
1459
|
+
const svc = allServices.find(s => s.name === name);
|
|
1460
|
+
inp.value = (svc && svc.label) ? svc.label : name;
|
|
1438
1461
|
inp.focus(); inp.select();
|
|
1439
1462
|
document.getElementById("rn-msg-" + name).textContent = "";
|
|
1440
1463
|
}
|
|
1441
1464
|
}
|
|
1442
1465
|
|
|
1443
|
-
async function
|
|
1444
|
-
const inp = document.getElementById("rn-input-" +
|
|
1445
|
-
const msg = document.getElementById("rn-msg-" +
|
|
1446
|
-
const
|
|
1447
|
-
if (!
|
|
1466
|
+
async function saveLabel(name) {
|
|
1467
|
+
const inp = document.getElementById("rn-input-" + name);
|
|
1468
|
+
const msg = document.getElementById("rn-msg-" + name);
|
|
1469
|
+
const newLabel = inp.value.trim();
|
|
1470
|
+
if (!newLabel) { toggleLabelEdit(name); return; }
|
|
1471
|
+
const svc = allServices.find(s => s.name === name);
|
|
1472
|
+
if (svc && newLabel === svc.label) { toggleLabelEdit(name); return; }
|
|
1448
1473
|
msg.style.color = "#94a3b8"; msg.textContent = "Saving…";
|
|
1449
1474
|
try {
|
|
1450
|
-
const r = await fetch(BASE + "/
|
|
1475
|
+
const r = await fetch(BASE + "/update-service", {
|
|
1451
1476
|
method: "POST",
|
|
1452
1477
|
headers: { "Content-Type": "application/json" },
|
|
1453
|
-
body: JSON.stringify({
|
|
1478
|
+
body: JSON.stringify({ service: name, label: newLabel })
|
|
1454
1479
|
}).then(r => r.json());
|
|
1455
1480
|
if (r.locked) { showLockScreen(false); return; }
|
|
1456
1481
|
if (r.error) throw new Error(r.error);
|
|
1457
|
-
msg.style.color = "#4ade80"; msg.textContent = "✓
|
|
1458
|
-
|
|
1482
|
+
msg.style.color = "#4ade80"; msg.textContent = "✓ Label updated";
|
|
1483
|
+
// Update in-memory and DOM immediately
|
|
1484
|
+
if (svc) svc.label = newLabel;
|
|
1485
|
+
const labelEl = document.getElementById("label-display-" + name);
|
|
1486
|
+
if (labelEl) labelEl.textContent = newLabel;
|
|
1487
|
+
setTimeout(() => { toggleLabelEdit(name); }, 800);
|
|
1459
1488
|
} catch (e) {
|
|
1460
1489
|
msg.style.color = "#f87171"; msg.textContent = "✗ " + e.message;
|
|
1461
1490
|
}
|
|
1462
1491
|
}
|
|
1463
1492
|
|
|
1493
|
+
// Legacy rename (slug) — kept for API compatibility but hidden from UI
|
|
1494
|
+
function toggleRename(name) { toggleLabelEdit(name); }
|
|
1495
|
+
async function saveRename(oldName) { await saveLabel(oldName); }
|
|
1496
|
+
|
|
1464
1497
|
// ── Delete service ───────────────────────────
|
|
1465
1498
|
async function deleteService(name) {
|
|
1466
1499
|
if (!confirm(\`Delete service "\${name}"? This cannot be undone.\`)) return;
|
|
@@ -1706,6 +1739,8 @@ async function toggleAddService() {
|
|
|
1706
1739
|
panel.style.display = open ? "none" : "block";
|
|
1707
1740
|
if (!open) {
|
|
1708
1741
|
document.getElementById("add-name").value = "";
|
|
1742
|
+
document.getElementById("add-label").value = "";
|
|
1743
|
+
document.getElementById("add-description").value = "";
|
|
1709
1744
|
document.getElementById("add-project").value = "";
|
|
1710
1745
|
document.getElementById("add-msg").textContent = "";
|
|
1711
1746
|
// Fetch available key types from server
|
|
@@ -1728,16 +1763,19 @@ async function toggleAddService() {
|
|
|
1728
1763
|
|
|
1729
1764
|
async function addService() {
|
|
1730
1765
|
const name = document.getElementById("add-name").value.trim().toLowerCase();
|
|
1766
|
+
const label = document.getElementById("add-label").value.trim();
|
|
1767
|
+
const description = document.getElementById("add-description").value.trim();
|
|
1731
1768
|
const type = document.getElementById("add-type").value;
|
|
1732
1769
|
const project = document.getElementById("add-project").value.trim();
|
|
1733
1770
|
const msg = document.getElementById("add-msg");
|
|
1734
1771
|
|
|
1735
|
-
if (!name) { msg.className = "add-msg fail"; msg.textContent = "
|
|
1736
|
-
if (!/^[a-z0-9][a-z0-9_-]*$/.test(name)) { msg.className = "add-msg fail"; msg.textContent = "
|
|
1772
|
+
if (!name) { msg.className = "add-msg fail"; msg.textContent = "Slug is required."; return; }
|
|
1773
|
+
if (!/^[a-z0-9][a-z0-9_-]*$/.test(name)) { msg.className = "add-msg fail"; msg.textContent = "Slug: lowercase letters, numbers, hyphens, underscores only."; return; }
|
|
1737
1774
|
|
|
1738
1775
|
msg.className = "add-msg"; msg.textContent = "Creating…";
|
|
1739
1776
|
try {
|
|
1740
|
-
const payload = { name, key_type: type, label: name };
|
|
1777
|
+
const payload = { name, key_type: type, label: label || name };
|
|
1778
|
+
if (description) payload.description = description;
|
|
1741
1779
|
if (project) payload.project = project;
|
|
1742
1780
|
const r = await fetch(BASE + "/add-service", {
|
|
1743
1781
|
method: "POST",
|
|
@@ -1764,8 +1802,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
1764
1802
|
document.getElementById("lock-input").addEventListener("keydown", e => {
|
|
1765
1803
|
if (e.key === "Enter") unlock();
|
|
1766
1804
|
});
|
|
1767
|
-
|
|
1768
|
-
|
|
1805
|
+
["add-name", "add-label", "add-description", "add-project"].forEach(id => {
|
|
1806
|
+
const el = document.getElementById(id);
|
|
1807
|
+
if (el) el.addEventListener("keydown", e => { if (e.key === "Enter") addService(); });
|
|
1769
1808
|
});
|
|
1770
1809
|
});
|
|
1771
1810
|
|
|
@@ -4671,6 +4710,88 @@ const MCP_TOOLS = [
|
|
|
4671
4710
|
description: "Test whether the clauth MCP connector is reachable via the Cloudflare tunnel. Returns connectivity status and tunnel URL.",
|
|
4672
4711
|
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
4673
4712
|
},
|
|
4713
|
+
|
|
4714
|
+
// ── Google Workspace (gws CLI) ──────────────────────────────────────────
|
|
4715
|
+
{
|
|
4716
|
+
name: "gws_run",
|
|
4717
|
+
description: "Run any gws CLI command for Google Workspace (Drive, Gmail, Calendar, Docs, Sheets, Slides, Tasks, People, Chat, etc.).\nCLI pattern: gws <service> <resource> [sub_resource] <method> [--params JSON] [--body JSON]",
|
|
4718
|
+
inputSchema: {
|
|
4719
|
+
type: "object",
|
|
4720
|
+
properties: {
|
|
4721
|
+
service: { type: "string", description: "Google Workspace service: drive, sheets, gmail, calendar, docs, slides, tasks, people, chat, classroom, forms, keep, meet, script" },
|
|
4722
|
+
resource: { type: "string", description: "Resource noun, e.g. 'files', 'users', 'events'" },
|
|
4723
|
+
sub_resource: { type: "string", description: "Optional sub-resource, e.g. 'messages' in 'users messages'" },
|
|
4724
|
+
method: { type: "string", description: "Method verb: list, get, insert, update, delete, send, create" },
|
|
4725
|
+
params: { type: "object", description: "Query/path params passed as --params JSON" },
|
|
4726
|
+
body: { type: "object", description: "Request body passed as --json JSON" }
|
|
4727
|
+
},
|
|
4728
|
+
required: ["service", "resource", "method"],
|
|
4729
|
+
additionalProperties: false
|
|
4730
|
+
}
|
|
4731
|
+
},
|
|
4732
|
+
{
|
|
4733
|
+
name: "gws_gmail_list",
|
|
4734
|
+
description: "List Gmail messages. Supports Gmail search syntax (e.g. 'from:alice subject:meeting is:unread').",
|
|
4735
|
+
inputSchema: {
|
|
4736
|
+
type: "object",
|
|
4737
|
+
properties: {
|
|
4738
|
+
query: { type: "string", description: "Gmail search query" },
|
|
4739
|
+
max_results: { type: "number", description: "Max messages (1-500, default 10)" }
|
|
4740
|
+
},
|
|
4741
|
+
additionalProperties: false
|
|
4742
|
+
}
|
|
4743
|
+
},
|
|
4744
|
+
{
|
|
4745
|
+
name: "gws_gmail_read",
|
|
4746
|
+
description: "Read a single Gmail message by ID. Returns full message with headers and body.",
|
|
4747
|
+
inputSchema: {
|
|
4748
|
+
type: "object",
|
|
4749
|
+
properties: { message_id: { type: "string", description: "Gmail message ID" } },
|
|
4750
|
+
required: ["message_id"],
|
|
4751
|
+
additionalProperties: false
|
|
4752
|
+
}
|
|
4753
|
+
},
|
|
4754
|
+
{
|
|
4755
|
+
name: "gws_gmail_send",
|
|
4756
|
+
description: "Send an email via Gmail.",
|
|
4757
|
+
inputSchema: {
|
|
4758
|
+
type: "object",
|
|
4759
|
+
properties: {
|
|
4760
|
+
to: { type: "string", description: "Recipient email address" },
|
|
4761
|
+
subject: { type: "string", description: "Email subject" },
|
|
4762
|
+
body: { type: "string", description: "Plain-text email body" },
|
|
4763
|
+
from: { type: "string", description: "Sender name/address (optional)" }
|
|
4764
|
+
},
|
|
4765
|
+
required: ["to", "subject", "body"],
|
|
4766
|
+
additionalProperties: false
|
|
4767
|
+
}
|
|
4768
|
+
},
|
|
4769
|
+
{
|
|
4770
|
+
name: "gws_calendar_list",
|
|
4771
|
+
description: "List upcoming Google Calendar events.",
|
|
4772
|
+
inputSchema: {
|
|
4773
|
+
type: "object",
|
|
4774
|
+
properties: {
|
|
4775
|
+
calendar_id: { type: "string", description: "Calendar ID (default: primary)" },
|
|
4776
|
+
max_results: { type: "number", description: "Max events (default 10)" },
|
|
4777
|
+
time_min: { type: "string", description: "Start bound ISO 8601, e.g. '2026-04-10T00:00:00Z'" },
|
|
4778
|
+
time_max: { type: "string", description: "End bound ISO 8601" }
|
|
4779
|
+
},
|
|
4780
|
+
additionalProperties: false
|
|
4781
|
+
}
|
|
4782
|
+
},
|
|
4783
|
+
{
|
|
4784
|
+
name: "gws_drive_list",
|
|
4785
|
+
description: "List files in Google Drive. Supports Drive search query syntax.",
|
|
4786
|
+
inputSchema: {
|
|
4787
|
+
type: "object",
|
|
4788
|
+
properties: {
|
|
4789
|
+
query: { type: "string", description: "Drive search query, e.g. \"name contains 'report'\"" },
|
|
4790
|
+
max_results: { type: "number", description: "Max files (default 10)" }
|
|
4791
|
+
},
|
|
4792
|
+
additionalProperties: false
|
|
4793
|
+
}
|
|
4794
|
+
},
|
|
4674
4795
|
];
|
|
4675
4796
|
|
|
4676
4797
|
function writeTempSecret(service, value) {
|
|
@@ -4963,6 +5084,70 @@ async function handleMcpTool(vault, name, args) {
|
|
|
4963
5084
|
return mcpResult(results.join("\n"));
|
|
4964
5085
|
}
|
|
4965
5086
|
|
|
5087
|
+
// ── Google Workspace (gws CLI) ───────────────────────────────────────
|
|
5088
|
+
case "gws_run": {
|
|
5089
|
+
const { service, resource, sub_resource, method, params, body } = args;
|
|
5090
|
+
const cmdArgs = [service, resource];
|
|
5091
|
+
if (sub_resource) cmdArgs.push(sub_resource);
|
|
5092
|
+
cmdArgs.push(method);
|
|
5093
|
+
if (params) cmdArgs.push("--params", `'${JSON.stringify(params)}'`);
|
|
5094
|
+
if (body) cmdArgs.push("--json", `'${JSON.stringify(body)}'`);
|
|
5095
|
+
try {
|
|
5096
|
+
const raw = execSyncTop(["gws", ...cmdArgs].join(" "), { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5097
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5098
|
+
} catch (err) {
|
|
5099
|
+
return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`);
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5103
|
+
case "gws_gmail_list": {
|
|
5104
|
+
const p = { userId: "me", maxResults: args.max_results ?? 10 };
|
|
5105
|
+
if (args.query) p.q = args.query;
|
|
5106
|
+
try {
|
|
5107
|
+
const raw = execSyncTop(`gws gmail users messages list --params '${JSON.stringify(p)}'`, { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5108
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5109
|
+
} catch (err) { return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`); }
|
|
5110
|
+
}
|
|
5111
|
+
|
|
5112
|
+
case "gws_gmail_read": {
|
|
5113
|
+
const p = { userId: "me", id: args.message_id, format: "full" };
|
|
5114
|
+
try {
|
|
5115
|
+
const raw = execSyncTop(`gws gmail users messages get --params '${JSON.stringify(p)}'`, { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5116
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5117
|
+
} catch (err) { return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`); }
|
|
5118
|
+
}
|
|
5119
|
+
|
|
5120
|
+
case "gws_gmail_send": {
|
|
5121
|
+
const lines = [];
|
|
5122
|
+
if (args.from) lines.push(`From: ${args.from}`);
|
|
5123
|
+
lines.push(`To: ${args.to}`, `Subject: ${args.subject}`, "Content-Type: text/plain; charset=utf-8", "MIME-Version: 1.0", "", args.body);
|
|
5124
|
+
const encoded = Buffer.from(lines.join("\r\n")).toString("base64url");
|
|
5125
|
+
const bodyObj = { userId: "me", resource: { raw: encoded } };
|
|
5126
|
+
try {
|
|
5127
|
+
const raw = execSyncTop(`gws gmail users messages send --json '${JSON.stringify(bodyObj)}'`, { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5128
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5129
|
+
} catch (err) { return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`); }
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
case "gws_calendar_list": {
|
|
5133
|
+
const p = { calendarId: args.calendar_id ?? "primary", maxResults: args.max_results ?? 10, singleEvents: true, orderBy: "startTime" };
|
|
5134
|
+
if (args.time_min) p.timeMin = args.time_min;
|
|
5135
|
+
if (args.time_max) p.timeMax = args.time_max;
|
|
5136
|
+
try {
|
|
5137
|
+
const raw = execSyncTop(`gws calendar events list --params '${JSON.stringify(p)}'`, { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5138
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5139
|
+
} catch (err) { return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`); }
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
case "gws_drive_list": {
|
|
5143
|
+
const p = { pageSize: args.max_results ?? 10, fields: "files(id,name,mimeType,modifiedTime,size,webViewLink)" };
|
|
5144
|
+
if (args.query) p.q = args.query;
|
|
5145
|
+
try {
|
|
5146
|
+
const raw = execSyncTop(`gws drive files list --params '${JSON.stringify(p)}'`, { encoding: "utf8", timeout: 30000, windowsHide: true });
|
|
5147
|
+
try { return mcpResult(JSON.stringify(JSON.parse(raw.trim()), null, 2)); } catch { return mcpResult(raw); }
|
|
5148
|
+
} catch (err) { return mcpError(`gws failed: ${err.stderr || err.stdout || err.message}`); }
|
|
5149
|
+
}
|
|
5150
|
+
|
|
4966
5151
|
default:
|
|
4967
5152
|
return mcpError(`Unknown tool: ${name}`);
|
|
4968
5153
|
}
|