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/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 listEvents(fromDateTime, untilDateTime, userId = "me", profile = "default") {
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 fetch(url2, {
14122
- method: "GET",
14123
- headers: {
14124
- Authorization: `Bearer ${token}`,
14125
- "Content-Type": "application/json"
14126
- }
14127
- });
14128
- if (res.status === 401) {
14129
- throw new AuthError("User token expired. Run `nworks login --user` again.");
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
- if (!res.ok) {
14132
- let code = "UNKNOWN";
14133
- let description = `HTTP ${res.status}`;
14134
- try {
14135
- const errorBody = await res.json();
14136
- code = errorBody.code ?? code;
14137
- description = errorBody.description ?? description;
14138
- } catch {
14139
- }
14140
- throw new ApiError(code, description, res.status);
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 { events: data.events ?? [] };
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 authedFetch(url2, init, profile) {
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 handleError(res) {
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 authedFetch(url2, { method: "GET" }, profile);
14181
- if (!res.ok) return handleError(res);
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 authedFetch(
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 handleError(createRes);
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 authedFetch(
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 handleError(uploadRes);
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 authedFetch(
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 handleError(createRes);
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 authedFetch(
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 handleError(uploadRes);
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 authedFetch(
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 handleError(redirectRes);
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 authedFetch(location, { method: "GET" }, profile);
14300
- if (!downloadRes.ok) return handleError(downloadRes);
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 authedFetch2(url2, init, profile) {
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 handleError2(res) {
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 authedFetch2(
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 handleError2(res);
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 authedFetch2(url2, { method: "GET" }, profile);
14373
- if (!res.ok) return handleError2(res);
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 authedFetch2(url2, { method: "GET" }, profile);
14389
- if (!res.ok) return handleError2(res);
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 authedFetch3(url2, init, profile) {
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 handleError3(res) {
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 authedFetch3(url2, { method: "GET" }, profile);
14419
- if (!res.ok) return handleError3(res);
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 authedFetch3(url2, { method: "GET" }, profile);
14437
- if (!res.ok) return handleError3(res);
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 authedFetch3(
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 handleError3(res);
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 authedFetch3(
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 handleError3(res);
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 authedFetch3(
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 handleError3(res);
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 authedFetch3(
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 handleError3(res);
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 authedFetch3(
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 handleError3(res);
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)",