nworks 0.5.0 → 0.6.2
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/README.md +33 -6
- package/dist/index.js +383 -67
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +298 -61
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -14060,6 +14060,9 @@ async function listUsers(profile = "default") {
|
|
|
14060
14060
|
return { users: result.users ?? [], responseMetaData: result.responseMetaData };
|
|
14061
14061
|
}
|
|
14062
14062
|
|
|
14063
|
+
// src/api/calendar.ts
|
|
14064
|
+
import { randomUUID } from "crypto";
|
|
14065
|
+
|
|
14063
14066
|
// src/auth/oauth-user.ts
|
|
14064
14067
|
import { createServer } from "http";
|
|
14065
14068
|
import { URL as URL2 } from "url";
|
|
@@ -14110,50 +14113,177 @@ async function getValidUserToken(profile = "default") {
|
|
|
14110
14113
|
|
|
14111
14114
|
// src/api/calendar.ts
|
|
14112
14115
|
var BASE_URL2 = "https://www.worksapis.com/v1.0";
|
|
14113
|
-
async function
|
|
14116
|
+
async function authedFetch(url2, init, profile) {
|
|
14114
14117
|
const token = await getValidUserToken(profile);
|
|
14118
|
+
const headers = new Headers(init.headers);
|
|
14119
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
14120
|
+
return fetch(url2, { ...init, headers });
|
|
14121
|
+
}
|
|
14122
|
+
async function handleError(res) {
|
|
14123
|
+
if (res.status === 401) {
|
|
14124
|
+
throw new AuthError("User token expired. Run `nworks login --user --scope calendar` again.");
|
|
14125
|
+
}
|
|
14126
|
+
let code = "UNKNOWN";
|
|
14127
|
+
let description = `HTTP ${res.status}`;
|
|
14128
|
+
try {
|
|
14129
|
+
const body = await res.json();
|
|
14130
|
+
code = body.code ?? code;
|
|
14131
|
+
description = body.description ?? description;
|
|
14132
|
+
} catch {
|
|
14133
|
+
}
|
|
14134
|
+
throw new ApiError(code, description, res.status);
|
|
14135
|
+
}
|
|
14136
|
+
function generateEventId() {
|
|
14137
|
+
return `event-${randomUUID()}`;
|
|
14138
|
+
}
|
|
14139
|
+
function normalizeDateTime(dt) {
|
|
14140
|
+
const match = dt.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2})([+-]\d{2}:\d{2}|Z)?$/);
|
|
14141
|
+
if (match) {
|
|
14142
|
+
return `${match[1]}:00${match[2] ?? ""}`;
|
|
14143
|
+
}
|
|
14144
|
+
return dt;
|
|
14145
|
+
}
|
|
14146
|
+
async function listEvents(fromDateTime, untilDateTime, userId = "me", profile = "default") {
|
|
14115
14147
|
const from = encodeURIComponent(fromDateTime);
|
|
14116
14148
|
const until = encodeURIComponent(untilDateTime);
|
|
14117
14149
|
const url2 = `${BASE_URL2}/users/${userId}/calendar/events?fromDateTime=${from}&untilDateTime=${until}`;
|
|
14118
14150
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14119
14151
|
console.error(`[nworks] GET ${url2}`);
|
|
14120
14152
|
}
|
|
14121
|
-
const res = await
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
|
|
14129
|
-
|
|
14153
|
+
const res = await authedFetch(url2, { method: "GET" }, profile);
|
|
14154
|
+
if (!res.ok) return handleError(res);
|
|
14155
|
+
const data = await res.json();
|
|
14156
|
+
return { events: data.events ?? [] };
|
|
14157
|
+
}
|
|
14158
|
+
async function createEvent(opts) {
|
|
14159
|
+
const userId = opts.userId ?? "me";
|
|
14160
|
+
const profile = opts.profile ?? "default";
|
|
14161
|
+
const timeZone = opts.timeZone ?? "Asia/Seoul";
|
|
14162
|
+
const eventId = generateEventId();
|
|
14163
|
+
const eventComponent = {
|
|
14164
|
+
eventId,
|
|
14165
|
+
summary: opts.summary,
|
|
14166
|
+
start: { dateTime: normalizeDateTime(opts.start), timeZone },
|
|
14167
|
+
end: { dateTime: normalizeDateTime(opts.end), timeZone }
|
|
14168
|
+
};
|
|
14169
|
+
if (opts.description) eventComponent.description = opts.description;
|
|
14170
|
+
if (opts.location) eventComponent.location = opts.location;
|
|
14171
|
+
if (opts.transparency) eventComponent.transparency = opts.transparency;
|
|
14172
|
+
if (opts.visibility) eventComponent.visibility = opts.visibility;
|
|
14173
|
+
if (opts.attendees) {
|
|
14174
|
+
eventComponent.attendees = opts.attendees.map((a) => ({
|
|
14175
|
+
email: a.email,
|
|
14176
|
+
displayName: a.displayName ?? "",
|
|
14177
|
+
partstat: "NEEDS-ACTION",
|
|
14178
|
+
isOptional: false,
|
|
14179
|
+
isResource: false
|
|
14180
|
+
}));
|
|
14130
14181
|
}
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14182
|
+
const body = {
|
|
14183
|
+
eventComponents: [eventComponent],
|
|
14184
|
+
sendNotification: opts.sendNotification ?? false
|
|
14185
|
+
};
|
|
14186
|
+
const url2 = `${BASE_URL2}/users/${userId}/calendar/events`;
|
|
14187
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14188
|
+
console.error(`[nworks] POST ${url2}`);
|
|
14189
|
+
console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
|
|
14190
|
+
}
|
|
14191
|
+
const res = await authedFetch(
|
|
14192
|
+
url2,
|
|
14193
|
+
{
|
|
14194
|
+
method: "POST",
|
|
14195
|
+
headers: { "Content-Type": "application/json" },
|
|
14196
|
+
body: JSON.stringify(body)
|
|
14197
|
+
},
|
|
14198
|
+
profile
|
|
14199
|
+
);
|
|
14200
|
+
if (res.status === 201) {
|
|
14201
|
+
return await res.json();
|
|
14202
|
+
}
|
|
14203
|
+
if (!res.ok) return handleError(res);
|
|
14204
|
+
return await res.json();
|
|
14205
|
+
}
|
|
14206
|
+
async function getEvent(eventId, userId = "me", profile = "default") {
|
|
14207
|
+
const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${eventId}`;
|
|
14208
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14209
|
+
console.error(`[nworks] GET ${url2}`);
|
|
14141
14210
|
}
|
|
14211
|
+
const res = await authedFetch(url2, { method: "GET" }, profile);
|
|
14212
|
+
if (!res.ok) return handleError(res);
|
|
14142
14213
|
const data = await res.json();
|
|
14143
|
-
return
|
|
14214
|
+
return data.eventComponents[0];
|
|
14215
|
+
}
|
|
14216
|
+
async function updateEvent(opts) {
|
|
14217
|
+
const userId = opts.userId ?? "me";
|
|
14218
|
+
const profile = opts.profile ?? "default";
|
|
14219
|
+
const timeZone = opts.timeZone ?? "Asia/Seoul";
|
|
14220
|
+
const existing = await getEvent(opts.eventId, userId, profile);
|
|
14221
|
+
const eventComponent = {
|
|
14222
|
+
eventId: opts.eventId,
|
|
14223
|
+
summary: opts.summary ?? existing.summary,
|
|
14224
|
+
start: opts.start ? { dateTime: normalizeDateTime(opts.start), timeZone } : existing.start,
|
|
14225
|
+
end: opts.end ? { dateTime: normalizeDateTime(opts.end), timeZone } : existing.end
|
|
14226
|
+
};
|
|
14227
|
+
if (opts.description !== void 0) eventComponent.description = opts.description;
|
|
14228
|
+
else if (existing.description) eventComponent.description = existing.description;
|
|
14229
|
+
if (opts.location !== void 0) eventComponent.location = opts.location;
|
|
14230
|
+
else if (existing.location) eventComponent.location = existing.location;
|
|
14231
|
+
if (opts.transparency !== void 0) eventComponent.transparency = opts.transparency;
|
|
14232
|
+
if (opts.visibility !== void 0) eventComponent.visibility = opts.visibility;
|
|
14233
|
+
if (opts.attendees !== void 0) {
|
|
14234
|
+
eventComponent.attendees = opts.attendees.map((a) => ({
|
|
14235
|
+
email: a.email,
|
|
14236
|
+
displayName: a.displayName ?? "",
|
|
14237
|
+
partstat: "NEEDS-ACTION",
|
|
14238
|
+
isOptional: false,
|
|
14239
|
+
isResource: false
|
|
14240
|
+
}));
|
|
14241
|
+
} else if (existing.attendees) {
|
|
14242
|
+
eventComponent.attendees = existing.attendees;
|
|
14243
|
+
}
|
|
14244
|
+
const body = {
|
|
14245
|
+
eventComponents: [eventComponent],
|
|
14246
|
+
sendNotification: opts.sendNotification ?? false
|
|
14247
|
+
};
|
|
14248
|
+
const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${opts.eventId}`;
|
|
14249
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14250
|
+
console.error(`[nworks] PUT ${url2}`);
|
|
14251
|
+
console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
|
|
14252
|
+
}
|
|
14253
|
+
const res = await authedFetch(
|
|
14254
|
+
url2,
|
|
14255
|
+
{
|
|
14256
|
+
method: "PUT",
|
|
14257
|
+
headers: { "Content-Type": "application/json" },
|
|
14258
|
+
body: JSON.stringify(body)
|
|
14259
|
+
},
|
|
14260
|
+
profile
|
|
14261
|
+
);
|
|
14262
|
+
if (!res.ok) return handleError(res);
|
|
14263
|
+
}
|
|
14264
|
+
async function deleteEvent(eventId, userId = "me", sendNotification = false, profile = "default") {
|
|
14265
|
+
const params = new URLSearchParams();
|
|
14266
|
+
params.set("sendNotification", String(sendNotification));
|
|
14267
|
+
const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${eventId}?${params.toString()}`;
|
|
14268
|
+
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14269
|
+
console.error(`[nworks] DELETE ${url2}`);
|
|
14270
|
+
}
|
|
14271
|
+
const res = await authedFetch(url2, { method: "DELETE" }, profile);
|
|
14272
|
+
if (res.status === 204) return;
|
|
14273
|
+
if (!res.ok) return handleError(res);
|
|
14144
14274
|
}
|
|
14145
14275
|
|
|
14146
14276
|
// src/api/drive.ts
|
|
14147
14277
|
import { readFile as readFile3, stat } from "fs/promises";
|
|
14148
14278
|
import { basename } from "path";
|
|
14149
14279
|
var BASE_URL3 = "https://www.worksapis.com/v1.0";
|
|
14150
|
-
async function
|
|
14280
|
+
async function authedFetch2(url2, init, profile) {
|
|
14151
14281
|
const token = await getValidUserToken(profile);
|
|
14152
14282
|
const headers = new Headers(init.headers);
|
|
14153
14283
|
headers.set("Authorization", `Bearer ${token}`);
|
|
14154
14284
|
return fetch(url2, { ...init, headers });
|
|
14155
14285
|
}
|
|
14156
|
-
async function
|
|
14286
|
+
async function handleError2(res) {
|
|
14157
14287
|
if (res.status === 401) {
|
|
14158
14288
|
throw new AuthError("User token expired. Run `nworks login --user --scope file` again.");
|
|
14159
14289
|
}
|
|
@@ -14177,8 +14307,8 @@ async function listFiles(userId = "me", folderId, count = 20, cursor, profile =
|
|
|
14177
14307
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14178
14308
|
console.error(`[nworks] GET ${url2}`);
|
|
14179
14309
|
}
|
|
14180
|
-
const res = await
|
|
14181
|
-
if (!res.ok) return
|
|
14310
|
+
const res = await authedFetch2(url2, { method: "GET" }, profile);
|
|
14311
|
+
if (!res.ok) return handleError2(res);
|
|
14182
14312
|
const data = await res.json();
|
|
14183
14313
|
return { files: data.files ?? [], responseMetaData: data.responseMetaData };
|
|
14184
14314
|
}
|
|
@@ -14191,7 +14321,7 @@ async function uploadFile(localPath, userId = "me", folderId, overwrite = false,
|
|
|
14191
14321
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14192
14322
|
console.error(`[nworks] POST ${createUrl} (create upload URL)`);
|
|
14193
14323
|
}
|
|
14194
|
-
const createRes = await
|
|
14324
|
+
const createRes = await authedFetch2(
|
|
14195
14325
|
createUrl,
|
|
14196
14326
|
{
|
|
14197
14327
|
method: "POST",
|
|
@@ -14200,7 +14330,7 @@ async function uploadFile(localPath, userId = "me", folderId, overwrite = false,
|
|
|
14200
14330
|
},
|
|
14201
14331
|
profile
|
|
14202
14332
|
);
|
|
14203
|
-
if (!createRes.ok) return
|
|
14333
|
+
if (!createRes.ok) return handleError2(createRes);
|
|
14204
14334
|
const { uploadUrl } = await createRes.json();
|
|
14205
14335
|
const fileBuffer = await readFile3(localPath);
|
|
14206
14336
|
const boundary = `----nworks${Date.now()}`;
|
|
@@ -14218,7 +14348,7 @@ Content-Type: application/octet-stream\r
|
|
|
14218
14348
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14219
14349
|
console.error(`[nworks] POST ${uploadUrl} (upload content, ${fileSize} bytes)`);
|
|
14220
14350
|
}
|
|
14221
|
-
const uploadRes = await
|
|
14351
|
+
const uploadRes = await authedFetch2(
|
|
14222
14352
|
uploadUrl,
|
|
14223
14353
|
{
|
|
14224
14354
|
method: "POST",
|
|
@@ -14227,7 +14357,7 @@ Content-Type: application/octet-stream\r
|
|
|
14227
14357
|
},
|
|
14228
14358
|
profile
|
|
14229
14359
|
);
|
|
14230
|
-
if (!uploadRes.ok) return
|
|
14360
|
+
if (!uploadRes.ok) return handleError2(uploadRes);
|
|
14231
14361
|
return await uploadRes.json();
|
|
14232
14362
|
}
|
|
14233
14363
|
async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overwrite = false, profile = "default") {
|
|
@@ -14237,7 +14367,7 @@ async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overw
|
|
|
14237
14367
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14238
14368
|
console.error(`[nworks] POST ${createUrl} (create upload URL for buffer)`);
|
|
14239
14369
|
}
|
|
14240
|
-
const createRes = await
|
|
14370
|
+
const createRes = await authedFetch2(
|
|
14241
14371
|
createUrl,
|
|
14242
14372
|
{
|
|
14243
14373
|
method: "POST",
|
|
@@ -14246,7 +14376,7 @@ async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overw
|
|
|
14246
14376
|
},
|
|
14247
14377
|
profile
|
|
14248
14378
|
);
|
|
14249
|
-
if (!createRes.ok) return
|
|
14379
|
+
if (!createRes.ok) return handleError2(createRes);
|
|
14250
14380
|
const { uploadUrl } = await createRes.json();
|
|
14251
14381
|
const boundary = `----nworks${Date.now()}`;
|
|
14252
14382
|
const header = Buffer.from(
|
|
@@ -14263,7 +14393,7 @@ Content-Type: application/octet-stream\r
|
|
|
14263
14393
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14264
14394
|
console.error(`[nworks] POST ${uploadUrl} (upload buffer, ${fileSize} bytes)`);
|
|
14265
14395
|
}
|
|
14266
|
-
const uploadRes = await
|
|
14396
|
+
const uploadRes = await authedFetch2(
|
|
14267
14397
|
uploadUrl,
|
|
14268
14398
|
{
|
|
14269
14399
|
method: "POST",
|
|
@@ -14272,7 +14402,7 @@ Content-Type: application/octet-stream\r
|
|
|
14272
14402
|
},
|
|
14273
14403
|
profile
|
|
14274
14404
|
);
|
|
14275
|
-
if (!uploadRes.ok) return
|
|
14405
|
+
if (!uploadRes.ok) return handleError2(uploadRes);
|
|
14276
14406
|
return await uploadRes.json();
|
|
14277
14407
|
}
|
|
14278
14408
|
async function downloadFile(fileId, userId = "me", profile = "default") {
|
|
@@ -14280,7 +14410,7 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
|
|
|
14280
14410
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14281
14411
|
console.error(`[nworks] GET ${url2} (get download URL)`);
|
|
14282
14412
|
}
|
|
14283
|
-
const redirectRes = await
|
|
14413
|
+
const redirectRes = await authedFetch2(
|
|
14284
14414
|
url2,
|
|
14285
14415
|
{ method: "GET", redirect: "manual" },
|
|
14286
14416
|
profile
|
|
@@ -14290,14 +14420,14 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
|
|
|
14290
14420
|
}
|
|
14291
14421
|
const location = redirectRes.headers.get("location");
|
|
14292
14422
|
if (!location) {
|
|
14293
|
-
if (!redirectRes.ok) return
|
|
14423
|
+
if (!redirectRes.ok) return handleError2(redirectRes);
|
|
14294
14424
|
throw new ApiError("NO_REDIRECT", "No download URL returned", redirectRes.status);
|
|
14295
14425
|
}
|
|
14296
14426
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14297
14427
|
console.error(`[nworks] GET ${location} (download content)`);
|
|
14298
14428
|
}
|
|
14299
|
-
const downloadRes = await
|
|
14300
|
-
if (!downloadRes.ok) return
|
|
14429
|
+
const downloadRes = await authedFetch2(location, { method: "GET" }, profile);
|
|
14430
|
+
if (!downloadRes.ok) return handleError2(downloadRes);
|
|
14301
14431
|
const arrayBuffer = await downloadRes.arrayBuffer();
|
|
14302
14432
|
const buffer = Buffer.from(arrayBuffer);
|
|
14303
14433
|
const disposition = downloadRes.headers.get("content-disposition");
|
|
@@ -14313,13 +14443,13 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
|
|
|
14313
14443
|
|
|
14314
14444
|
// src/api/mail.ts
|
|
14315
14445
|
var BASE_URL4 = "https://www.worksapis.com/v1.0";
|
|
14316
|
-
async function
|
|
14446
|
+
async function authedFetch3(url2, init, profile) {
|
|
14317
14447
|
const token = await getValidUserToken(profile);
|
|
14318
14448
|
const headers = new Headers(init.headers);
|
|
14319
14449
|
headers.set("Authorization", `Bearer ${token}`);
|
|
14320
14450
|
return fetch(url2, { ...init, headers });
|
|
14321
14451
|
}
|
|
14322
|
-
async function
|
|
14452
|
+
async function handleError3(res) {
|
|
14323
14453
|
if (res.status === 401) {
|
|
14324
14454
|
throw new AuthError("User token expired. Run `nworks login --user --scope mail` again.");
|
|
14325
14455
|
}
|
|
@@ -14348,7 +14478,7 @@ async function sendMail(opts) {
|
|
|
14348
14478
|
if (opts.cc) body.cc = opts.cc;
|
|
14349
14479
|
if (opts.bcc) body.bcc = opts.bcc;
|
|
14350
14480
|
if (opts.contentType) body.contentType = opts.contentType;
|
|
14351
|
-
const res = await
|
|
14481
|
+
const res = await authedFetch3(
|
|
14352
14482
|
url2,
|
|
14353
14483
|
{
|
|
14354
14484
|
method: "POST",
|
|
@@ -14358,7 +14488,7 @@ async function sendMail(opts) {
|
|
|
14358
14488
|
profile
|
|
14359
14489
|
);
|
|
14360
14490
|
if (res.status === 202) return;
|
|
14361
|
-
if (!res.ok) return
|
|
14491
|
+
if (!res.ok) return handleError3(res);
|
|
14362
14492
|
}
|
|
14363
14493
|
async function listMails(folderId = 0, userId = "me", count = 30, cursor, isUnread, profile = "default") {
|
|
14364
14494
|
const params = new URLSearchParams();
|
|
@@ -14369,8 +14499,8 @@ async function listMails(folderId = 0, userId = "me", count = 30, cursor, isUnre
|
|
|
14369
14499
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14370
14500
|
console.error(`[nworks] GET ${url2}`);
|
|
14371
14501
|
}
|
|
14372
|
-
const res = await
|
|
14373
|
-
if (!res.ok) return
|
|
14502
|
+
const res = await authedFetch3(url2, { method: "GET" }, profile);
|
|
14503
|
+
if (!res.ok) return handleError3(res);
|
|
14374
14504
|
const data = await res.json();
|
|
14375
14505
|
return {
|
|
14376
14506
|
mails: data.mails ?? [],
|
|
@@ -14385,20 +14515,20 @@ async function readMail(mailId, userId = "me", profile = "default") {
|
|
|
14385
14515
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14386
14516
|
console.error(`[nworks] GET ${url2}`);
|
|
14387
14517
|
}
|
|
14388
|
-
const res = await
|
|
14389
|
-
if (!res.ok) return
|
|
14518
|
+
const res = await authedFetch3(url2, { method: "GET" }, profile);
|
|
14519
|
+
if (!res.ok) return handleError3(res);
|
|
14390
14520
|
return await res.json();
|
|
14391
14521
|
}
|
|
14392
14522
|
|
|
14393
14523
|
// src/api/task.ts
|
|
14394
14524
|
var BASE_URL5 = "https://www.worksapis.com/v1.0";
|
|
14395
|
-
async function
|
|
14525
|
+
async function authedFetch4(url2, init, profile) {
|
|
14396
14526
|
const token = await getValidUserToken(profile);
|
|
14397
14527
|
const headers = new Headers(init.headers);
|
|
14398
14528
|
headers.set("Authorization", `Bearer ${token}`);
|
|
14399
14529
|
return fetch(url2, { ...init, headers });
|
|
14400
14530
|
}
|
|
14401
|
-
async function
|
|
14531
|
+
async function handleError4(res) {
|
|
14402
14532
|
if (res.status === 401) {
|
|
14403
14533
|
throw new AuthError("User token expired. Run `nworks login --user --scope task` again.");
|
|
14404
14534
|
}
|
|
@@ -14415,8 +14545,8 @@ async function handleError3(res) {
|
|
|
14415
14545
|
async function resolveUserId(userId, profile) {
|
|
14416
14546
|
if (userId !== "me") return userId;
|
|
14417
14547
|
const url2 = `${BASE_URL5}/users/me`;
|
|
14418
|
-
const res = await
|
|
14419
|
-
if (!res.ok) return
|
|
14548
|
+
const res = await authedFetch4(url2, { method: "GET" }, profile);
|
|
14549
|
+
if (!res.ok) return handleError4(res);
|
|
14420
14550
|
const data = await res.json();
|
|
14421
14551
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14422
14552
|
console.error(`[nworks] Resolved "me" \u2192 ${data.userId}`);
|
|
@@ -14433,8 +14563,8 @@ async function listTasks(categoryId = "default", userId = "me", count = 50, curs
|
|
|
14433
14563
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14434
14564
|
console.error(`[nworks] GET ${url2}`);
|
|
14435
14565
|
}
|
|
14436
|
-
const res = await
|
|
14437
|
-
if (!res.ok) return
|
|
14566
|
+
const res = await authedFetch4(url2, { method: "GET" }, profile);
|
|
14567
|
+
if (!res.ok) return handleError4(res);
|
|
14438
14568
|
const data = await res.json();
|
|
14439
14569
|
return { tasks: data.tasks ?? [], responseMetaData: data.responseMetaData };
|
|
14440
14570
|
}
|
|
@@ -14458,7 +14588,7 @@ async function createTask(opts) {
|
|
|
14458
14588
|
console.error(`[nworks] POST ${url2}`);
|
|
14459
14589
|
console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
|
|
14460
14590
|
}
|
|
14461
|
-
const res = await
|
|
14591
|
+
const res = await authedFetch4(
|
|
14462
14592
|
url2,
|
|
14463
14593
|
{
|
|
14464
14594
|
method: "POST",
|
|
@@ -14470,7 +14600,7 @@ async function createTask(opts) {
|
|
|
14470
14600
|
if (res.status === 201) {
|
|
14471
14601
|
return await res.json();
|
|
14472
14602
|
}
|
|
14473
|
-
if (!res.ok) return
|
|
14603
|
+
if (!res.ok) return handleError4(res);
|
|
14474
14604
|
return await res.json();
|
|
14475
14605
|
}
|
|
14476
14606
|
async function updateTask(opts) {
|
|
@@ -14483,7 +14613,7 @@ async function updateTask(opts) {
|
|
|
14483
14613
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14484
14614
|
console.error(`[nworks] PATCH ${url2}`);
|
|
14485
14615
|
}
|
|
14486
|
-
const res = await
|
|
14616
|
+
const res = await authedFetch4(
|
|
14487
14617
|
url2,
|
|
14488
14618
|
{
|
|
14489
14619
|
method: "PATCH",
|
|
@@ -14492,7 +14622,7 @@ async function updateTask(opts) {
|
|
|
14492
14622
|
},
|
|
14493
14623
|
profile
|
|
14494
14624
|
);
|
|
14495
|
-
if (!res.ok) return
|
|
14625
|
+
if (!res.ok) return handleError4(res);
|
|
14496
14626
|
return await res.json();
|
|
14497
14627
|
}
|
|
14498
14628
|
async function completeTask(taskId, profile = "default") {
|
|
@@ -14500,39 +14630,39 @@ async function completeTask(taskId, profile = "default") {
|
|
|
14500
14630
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14501
14631
|
console.error(`[nworks] POST ${url2}`);
|
|
14502
14632
|
}
|
|
14503
|
-
const res = await
|
|
14633
|
+
const res = await authedFetch4(
|
|
14504
14634
|
url2,
|
|
14505
14635
|
{ method: "POST" },
|
|
14506
14636
|
profile
|
|
14507
14637
|
);
|
|
14508
14638
|
if (res.status === 204) return;
|
|
14509
|
-
if (!res.ok) return
|
|
14639
|
+
if (!res.ok) return handleError4(res);
|
|
14510
14640
|
}
|
|
14511
14641
|
async function incompleteTask(taskId, profile = "default") {
|
|
14512
14642
|
const url2 = `${BASE_URL5}/tasks/${taskId}/incomplete`;
|
|
14513
14643
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14514
14644
|
console.error(`[nworks] POST ${url2}`);
|
|
14515
14645
|
}
|
|
14516
|
-
const res = await
|
|
14646
|
+
const res = await authedFetch4(
|
|
14517
14647
|
url2,
|
|
14518
14648
|
{ method: "POST" },
|
|
14519
14649
|
profile
|
|
14520
14650
|
);
|
|
14521
14651
|
if (res.status === 204) return;
|
|
14522
|
-
if (!res.ok) return
|
|
14652
|
+
if (!res.ok) return handleError4(res);
|
|
14523
14653
|
}
|
|
14524
14654
|
async function deleteTask(taskId, profile = "default") {
|
|
14525
14655
|
const url2 = `${BASE_URL5}/tasks/${taskId}`;
|
|
14526
14656
|
if (process.env["NWORKS_VERBOSE"] === "1") {
|
|
14527
14657
|
console.error(`[nworks] DELETE ${url2}`);
|
|
14528
14658
|
}
|
|
14529
|
-
const res = await
|
|
14659
|
+
const res = await authedFetch4(
|
|
14530
14660
|
url2,
|
|
14531
14661
|
{ method: "DELETE" },
|
|
14532
14662
|
profile
|
|
14533
14663
|
);
|
|
14534
14664
|
if (res.status === 204) return;
|
|
14535
|
-
if (!res.ok) return
|
|
14665
|
+
if (!res.ok) return handleError4(res);
|
|
14536
14666
|
}
|
|
14537
14667
|
|
|
14538
14668
|
// src/mcp/tools.ts
|
|
@@ -14627,6 +14757,7 @@ function registerTools(server) {
|
|
|
14627
14757
|
);
|
|
14628
14758
|
const events = result.events.flatMap(
|
|
14629
14759
|
(e) => e.eventComponents.map((c) => ({
|
|
14760
|
+
eventId: c.eventId,
|
|
14630
14761
|
summary: c.summary,
|
|
14631
14762
|
start: c.start.dateTime ?? c.start.date ?? "",
|
|
14632
14763
|
end: c.end.dateTime ?? c.end.date ?? "",
|
|
@@ -14645,6 +14776,112 @@ function registerTools(server) {
|
|
|
14645
14776
|
}
|
|
14646
14777
|
}
|
|
14647
14778
|
);
|
|
14779
|
+
server.tool(
|
|
14780
|
+
"nworks_calendar_create",
|
|
14781
|
+
"\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
|
|
14782
|
+
{
|
|
14783
|
+
summary: external_exports.string().describe("\uC77C\uC815 \uC81C\uBAA9"),
|
|
14784
|
+
start: external_exports.string().describe("\uC2DC\uC791 \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
|
|
14785
|
+
end: external_exports.string().describe("\uC885\uB8CC \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
|
|
14786
|
+
timeZone: external_exports.string().optional().describe("\uD0C0\uC784\uC874 (\uAE30\uBCF8: Asia/Seoul)"),
|
|
14787
|
+
description: external_exports.string().optional().describe("\uC77C\uC815 \uC124\uBA85"),
|
|
14788
|
+
location: external_exports.string().optional().describe("\uC7A5\uC18C"),
|
|
14789
|
+
attendees: external_exports.array(external_exports.object({ email: external_exports.string(), displayName: external_exports.string().optional() })).optional().describe("\uCC38\uC11D\uC790 \uBAA9\uB85D"),
|
|
14790
|
+
sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
|
|
14791
|
+
userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
|
|
14792
|
+
},
|
|
14793
|
+
async ({ summary, start, end, timeZone, description, location, attendees, sendNotification, userId }) => {
|
|
14794
|
+
try {
|
|
14795
|
+
const result = await createEvent({
|
|
14796
|
+
summary,
|
|
14797
|
+
start,
|
|
14798
|
+
end,
|
|
14799
|
+
timeZone,
|
|
14800
|
+
description,
|
|
14801
|
+
location,
|
|
14802
|
+
attendees,
|
|
14803
|
+
sendNotification,
|
|
14804
|
+
userId: userId ?? "me"
|
|
14805
|
+
});
|
|
14806
|
+
const event = result.eventComponents?.[0];
|
|
14807
|
+
return {
|
|
14808
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, eventId: event?.eventId, summary: event?.summary, start: event?.start, end: event?.end }) }]
|
|
14809
|
+
};
|
|
14810
|
+
} catch (err) {
|
|
14811
|
+
const error48 = err;
|
|
14812
|
+
return {
|
|
14813
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
14814
|
+
isError: true
|
|
14815
|
+
};
|
|
14816
|
+
}
|
|
14817
|
+
}
|
|
14818
|
+
);
|
|
14819
|
+
server.tool(
|
|
14820
|
+
"nworks_calendar_update",
|
|
14821
|
+
"\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC218\uC815\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
|
|
14822
|
+
{
|
|
14823
|
+
eventId: external_exports.string().describe("\uC77C\uC815 ID"),
|
|
14824
|
+
summary: external_exports.string().optional().describe("\uC0C8 \uC81C\uBAA9"),
|
|
14825
|
+
start: external_exports.string().optional().describe("\uC0C8 \uC2DC\uC791 \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
|
|
14826
|
+
end: external_exports.string().optional().describe("\uC0C8 \uC885\uB8CC \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
|
|
14827
|
+
timeZone: external_exports.string().optional().describe("\uD0C0\uC784\uC874 (\uAE30\uBCF8: Asia/Seoul)"),
|
|
14828
|
+
description: external_exports.string().optional().describe("\uC0C8 \uC124\uBA85"),
|
|
14829
|
+
location: external_exports.string().optional().describe("\uC0C8 \uC7A5\uC18C"),
|
|
14830
|
+
sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
|
|
14831
|
+
userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
|
|
14832
|
+
},
|
|
14833
|
+
async ({ eventId, summary, start, end, timeZone, description, location, sendNotification, userId }) => {
|
|
14834
|
+
try {
|
|
14835
|
+
await updateEvent({
|
|
14836
|
+
eventId,
|
|
14837
|
+
summary,
|
|
14838
|
+
start,
|
|
14839
|
+
end,
|
|
14840
|
+
timeZone,
|
|
14841
|
+
description,
|
|
14842
|
+
location,
|
|
14843
|
+
sendNotification,
|
|
14844
|
+
userId: userId ?? "me"
|
|
14845
|
+
});
|
|
14846
|
+
return {
|
|
14847
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, eventId, message: "Event updated" }) }]
|
|
14848
|
+
};
|
|
14849
|
+
} catch (err) {
|
|
14850
|
+
const error48 = err;
|
|
14851
|
+
return {
|
|
14852
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
14853
|
+
isError: true
|
|
14854
|
+
};
|
|
14855
|
+
}
|
|
14856
|
+
}
|
|
14857
|
+
);
|
|
14858
|
+
server.tool(
|
|
14859
|
+
"nworks_calendar_delete",
|
|
14860
|
+
"\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
|
|
14861
|
+
{
|
|
14862
|
+
eventId: external_exports.string().describe("\uC0AD\uC81C\uD560 \uC77C\uC815 ID"),
|
|
14863
|
+
sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
|
|
14864
|
+
userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
|
|
14865
|
+
},
|
|
14866
|
+
async ({ eventId, sendNotification, userId }) => {
|
|
14867
|
+
try {
|
|
14868
|
+
await deleteEvent(
|
|
14869
|
+
eventId,
|
|
14870
|
+
userId ?? "me",
|
|
14871
|
+
sendNotification ?? false
|
|
14872
|
+
);
|
|
14873
|
+
return {
|
|
14874
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, eventId, message: "Event deleted" }) }]
|
|
14875
|
+
};
|
|
14876
|
+
} catch (err) {
|
|
14877
|
+
const error48 = err;
|
|
14878
|
+
return {
|
|
14879
|
+
content: [{ type: "text", text: `Error: ${error48.message}` }],
|
|
14880
|
+
isError: true
|
|
14881
|
+
};
|
|
14882
|
+
}
|
|
14883
|
+
}
|
|
14884
|
+
);
|
|
14648
14885
|
server.tool(
|
|
14649
14886
|
"nworks_drive_list",
|
|
14650
14887
|
"\uB4DC\uB77C\uC774\uBE0C \uD30C\uC77C/\uD3F4\uB354 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4 (User OAuth file \uB610\uB294 file.read scope \uD544\uC694)",
|