nworks 0.4.0 → 0.6.1

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/index.js CHANGED
@@ -7,7 +7,7 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/index.ts
9
9
  import { createRequire } from "module";
10
- import { Command as Command10 } from "commander";
10
+ import { Command as Command11 } from "commander";
11
11
 
12
12
  // src/commands/login.ts
13
13
  import { Command } from "commander";
@@ -736,6 +736,9 @@ var directoryCommand = new Command5("directory").description("Directory (organiz
736
736
  // src/commands/calendar.ts
737
737
  import { Command as Command6 } from "commander";
738
738
 
739
+ // src/api/calendar.ts
740
+ import { randomUUID } from "crypto";
741
+
739
742
  // src/auth/token-user.ts
740
743
  async function getValidUserToken(profile = "default") {
741
744
  const cached2 = await loadUserToken(profile);
@@ -754,37 +757,164 @@ async function getValidUserToken(profile = "default") {
754
757
 
755
758
  // src/api/calendar.ts
756
759
  var BASE_URL2 = "https://www.worksapis.com/v1.0";
757
- async function listEvents(fromDateTime, untilDateTime, userId = "me", profile = "default") {
760
+ async function authedFetch(url2, init, profile) {
758
761
  const token = await getValidUserToken(profile);
762
+ const headers = new Headers(init.headers);
763
+ headers.set("Authorization", `Bearer ${token}`);
764
+ return fetch(url2, { ...init, headers });
765
+ }
766
+ async function handleError(res) {
767
+ if (res.status === 401) {
768
+ throw new AuthError("User token expired. Run `nworks login --user --scope calendar` again.");
769
+ }
770
+ let code = "UNKNOWN";
771
+ let description = `HTTP ${res.status}`;
772
+ try {
773
+ const body = await res.json();
774
+ code = body.code ?? code;
775
+ description = body.description ?? description;
776
+ } catch {
777
+ }
778
+ throw new ApiError(code, description, res.status);
779
+ }
780
+ function generateEventId() {
781
+ return `event-${randomUUID()}`;
782
+ }
783
+ function normalizeDateTime(dt) {
784
+ const match = dt.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2})([+-]\d{2}:\d{2}|Z)?$/);
785
+ if (match) {
786
+ return `${match[1]}:00${match[2] ?? ""}`;
787
+ }
788
+ return dt;
789
+ }
790
+ async function listEvents(fromDateTime, untilDateTime, userId = "me", profile = "default") {
759
791
  const from = encodeURIComponent(fromDateTime);
760
792
  const until = encodeURIComponent(untilDateTime);
761
793
  const url2 = `${BASE_URL2}/users/${userId}/calendar/events?fromDateTime=${from}&untilDateTime=${until}`;
762
794
  if (process.env["NWORKS_VERBOSE"] === "1") {
763
795
  console.error(`[nworks] GET ${url2}`);
764
796
  }
765
- const res = await fetch(url2, {
766
- method: "GET",
767
- headers: {
768
- Authorization: `Bearer ${token}`,
769
- "Content-Type": "application/json"
770
- }
771
- });
772
- if (res.status === 401) {
773
- throw new AuthError("User token expired. Run `nworks login --user` again.");
797
+ const res = await authedFetch(url2, { method: "GET" }, profile);
798
+ if (!res.ok) return handleError(res);
799
+ const data = await res.json();
800
+ return { events: data.events ?? [] };
801
+ }
802
+ async function createEvent(opts) {
803
+ const userId = opts.userId ?? "me";
804
+ const profile = opts.profile ?? "default";
805
+ const timeZone = opts.timeZone ?? "Asia/Seoul";
806
+ const eventId = generateEventId();
807
+ const eventComponent = {
808
+ eventId,
809
+ summary: opts.summary,
810
+ start: { dateTime: normalizeDateTime(opts.start), timeZone },
811
+ end: { dateTime: normalizeDateTime(opts.end), timeZone }
812
+ };
813
+ if (opts.description) eventComponent.description = opts.description;
814
+ if (opts.location) eventComponent.location = opts.location;
815
+ if (opts.transparency) eventComponent.transparency = opts.transparency;
816
+ if (opts.visibility) eventComponent.visibility = opts.visibility;
817
+ if (opts.attendees) {
818
+ eventComponent.attendees = opts.attendees.map((a) => ({
819
+ email: a.email,
820
+ displayName: a.displayName ?? "",
821
+ partstat: "NEEDS-ACTION",
822
+ isOptional: false,
823
+ isResource: false
824
+ }));
774
825
  }
775
- if (!res.ok) {
776
- let code = "UNKNOWN";
777
- let description = `HTTP ${res.status}`;
778
- try {
779
- const errorBody = await res.json();
780
- code = errorBody.code ?? code;
781
- description = errorBody.description ?? description;
782
- } catch {
783
- }
784
- throw new ApiError(code, description, res.status);
826
+ const body = {
827
+ eventComponents: [eventComponent],
828
+ sendNotification: opts.sendNotification ?? false
829
+ };
830
+ const url2 = `${BASE_URL2}/users/${userId}/calendar/events`;
831
+ if (process.env["NWORKS_VERBOSE"] === "1") {
832
+ console.error(`[nworks] POST ${url2}`);
833
+ console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
834
+ }
835
+ const res = await authedFetch(
836
+ url2,
837
+ {
838
+ method: "POST",
839
+ headers: { "Content-Type": "application/json" },
840
+ body: JSON.stringify(body)
841
+ },
842
+ profile
843
+ );
844
+ if (res.status === 201) {
845
+ return await res.json();
785
846
  }
847
+ if (!res.ok) return handleError(res);
848
+ return await res.json();
849
+ }
850
+ async function getEvent(eventId, userId = "me", profile = "default") {
851
+ const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${eventId}`;
852
+ if (process.env["NWORKS_VERBOSE"] === "1") {
853
+ console.error(`[nworks] GET ${url2}`);
854
+ }
855
+ const res = await authedFetch(url2, { method: "GET" }, profile);
856
+ if (!res.ok) return handleError(res);
786
857
  const data = await res.json();
787
- return { events: data.events ?? [] };
858
+ return data.eventComponents[0];
859
+ }
860
+ async function updateEvent(opts) {
861
+ const userId = opts.userId ?? "me";
862
+ const profile = opts.profile ?? "default";
863
+ const timeZone = opts.timeZone ?? "Asia/Seoul";
864
+ const existing = await getEvent(opts.eventId, userId, profile);
865
+ const eventComponent = {
866
+ eventId: opts.eventId,
867
+ summary: opts.summary ?? existing.summary,
868
+ start: opts.start ? { dateTime: normalizeDateTime(opts.start), timeZone } : existing.start,
869
+ end: opts.end ? { dateTime: normalizeDateTime(opts.end), timeZone } : existing.end
870
+ };
871
+ if (opts.description !== void 0) eventComponent.description = opts.description;
872
+ else if (existing.description) eventComponent.description = existing.description;
873
+ if (opts.location !== void 0) eventComponent.location = opts.location;
874
+ else if (existing.location) eventComponent.location = existing.location;
875
+ if (opts.transparency !== void 0) eventComponent.transparency = opts.transparency;
876
+ if (opts.visibility !== void 0) eventComponent.visibility = opts.visibility;
877
+ if (opts.attendees !== void 0) {
878
+ eventComponent.attendees = opts.attendees.map((a) => ({
879
+ email: a.email,
880
+ displayName: a.displayName ?? "",
881
+ partstat: "NEEDS-ACTION",
882
+ isOptional: false,
883
+ isResource: false
884
+ }));
885
+ } else if (existing.attendees) {
886
+ eventComponent.attendees = existing.attendees;
887
+ }
888
+ const body = {
889
+ eventComponents: [eventComponent],
890
+ sendNotification: opts.sendNotification ?? false
891
+ };
892
+ const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${opts.eventId}`;
893
+ if (process.env["NWORKS_VERBOSE"] === "1") {
894
+ console.error(`[nworks] PUT ${url2}`);
895
+ console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
896
+ }
897
+ const res = await authedFetch(
898
+ url2,
899
+ {
900
+ method: "PUT",
901
+ headers: { "Content-Type": "application/json" },
902
+ body: JSON.stringify(body)
903
+ },
904
+ profile
905
+ );
906
+ if (!res.ok) return handleError(res);
907
+ }
908
+ async function deleteEvent(eventId, userId = "me", sendNotification = false, profile = "default") {
909
+ const params = new URLSearchParams();
910
+ params.set("sendNotification", String(sendNotification));
911
+ const url2 = `${BASE_URL2}/users/${userId}/calendar/events/${eventId}?${params.toString()}`;
912
+ if (process.env["NWORKS_VERBOSE"] === "1") {
913
+ console.error(`[nworks] DELETE ${url2}`);
914
+ }
915
+ const res = await authedFetch(url2, { method: "DELETE" }, profile);
916
+ if (res.status === 204) return;
917
+ if (!res.ok) return handleError(res);
788
918
  }
789
919
 
790
920
  // src/commands/calendar.ts
@@ -798,7 +928,7 @@ function todayRange() {
798
928
  until: `${yyyy}-${mm}-${dd}T23:59:59+09:00`
799
929
  };
800
930
  }
801
- var listCommand = new Command6("list").description("List calendar events (requires User OAuth with calendar.read scope)").option("--user <userId>", "Target user ID (default: me)").option("--from <dateTime>", "Start (YYYY-MM-DDThh:mm:ss+09:00, default: today 00:00)").option("--until <dateTime>", "End (YYYY-MM-DDThh:mm:ss+09:00, default: today 23:59)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
931
+ var listCommand = new Command6("list").description("List calendar events (requires User OAuth with calendar.read or calendar scope)").option("--user <userId>", "Target user ID (default: me)").option("--from <dateTime>", "Start (YYYY-MM-DDThh:mm:ss+09:00, default: today 00:00)").option("--until <dateTime>", "End (YYYY-MM-DDThh:mm:ss+09:00, default: today 23:59)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
802
932
  try {
803
933
  const defaults = todayRange();
804
934
  const from = opts.from ?? defaults.from;
@@ -812,6 +942,7 @@ var listCommand = new Command6("list").description("List calendar events (requir
812
942
  );
813
943
  const events = result.events.flatMap(
814
944
  (e) => e.eventComponents.map((c) => ({
945
+ eventId: c.eventId,
815
946
  summary: c.summary,
816
947
  start: c.start.dateTime ? `${c.start.dateTime} (${c.start.timeZone ?? ""})` : c.start.date ?? "",
817
948
  end: c.end.dateTime ? `${c.end.dateTime} (${c.end.timeZone ?? ""})` : c.end.date ?? "",
@@ -825,7 +956,85 @@ var listCommand = new Command6("list").description("List calendar events (requir
825
956
  process.exitCode = 1;
826
957
  }
827
958
  });
828
- var calendarCommand = new Command6("calendar").description("Calendar operations (requires User OAuth)").addCommand(listCommand);
959
+ var createCommand = new Command6("create").description("Create a calendar event (requires User OAuth with calendar scope)").requiredOption("--title <title>", "Event title (summary)").requiredOption("--start <dateTime>", "Start (YYYY-MM-DDThh:mm:ss)").requiredOption("--end <dateTime>", "End (YYYY-MM-DDThh:mm:ss)").option("--tz <timeZone>", "Time zone (default: Asia/Seoul)", "Asia/Seoul").option("--description <text>", "Event description").option("--location <place>", "Event location").option("--attendees <emails>", "Attendee emails (comma-separated)").option("--notify", "Send notification to attendees").option("--user <userId>", "Target user ID (default: me)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
960
+ try {
961
+ const attendees = opts.attendees ? opts.attendees.split(",").map((e) => ({ email: e.trim() })) : void 0;
962
+ const result = await createEvent({
963
+ summary: opts.title,
964
+ start: opts.start,
965
+ end: opts.end,
966
+ timeZone: opts.tz,
967
+ description: opts.description,
968
+ location: opts.location,
969
+ attendees,
970
+ sendNotification: opts.notify ?? false,
971
+ userId: opts.user ?? "me",
972
+ profile: opts.profile
973
+ });
974
+ const event = result.eventComponents?.[0];
975
+ const fmt = (t) => t?.dateTime ? `${t.dateTime} (${t.timeZone ?? ""})` : "";
976
+ output(
977
+ {
978
+ success: true,
979
+ eventId: event?.eventId,
980
+ summary: event?.summary,
981
+ start: fmt(event?.start),
982
+ end: fmt(event?.end)
983
+ },
984
+ opts
985
+ );
986
+ } catch (err) {
987
+ const error48 = err;
988
+ errorOutput({ code: error48.code, message: error48.message }, opts);
989
+ process.exitCode = 1;
990
+ }
991
+ });
992
+ var updateCommand = new Command6("update").description("Update a calendar event (requires User OAuth with calendar scope)").requiredOption("--id <eventId>", "Event ID").option("--title <title>", "New title (summary)").option("--start <dateTime>", "New start (YYYY-MM-DDThh:mm:ss)").option("--end <dateTime>", "New end (YYYY-MM-DDThh:mm:ss)").option("--tz <timeZone>", "Time zone (default: Asia/Seoul)", "Asia/Seoul").option("--description <text>", "New description").option("--location <place>", "New location").option("--attendees <emails>", "Attendee emails (comma-separated)").option("--notify", "Send notification to attendees").option("--user <userId>", "Target user ID (default: me)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
993
+ try {
994
+ const hasUpdate = opts.title || opts.start || opts.end || opts.description || opts.location || opts.attendees;
995
+ if (!hasUpdate) {
996
+ throw new Error("Specify at least one of: --title, --start, --end, --description, --location, --attendees");
997
+ }
998
+ const attendees = opts.attendees ? opts.attendees.split(",").map((e) => ({ email: e.trim() })) : void 0;
999
+ await updateEvent({
1000
+ eventId: opts.id,
1001
+ summary: opts.title,
1002
+ start: opts.start,
1003
+ end: opts.end,
1004
+ timeZone: opts.tz,
1005
+ description: opts.description,
1006
+ location: opts.location,
1007
+ attendees,
1008
+ sendNotification: opts.notify ?? false,
1009
+ userId: opts.user ?? "me",
1010
+ profile: opts.profile
1011
+ });
1012
+ output(
1013
+ { success: true, eventId: opts.id, message: "Event updated" },
1014
+ opts
1015
+ );
1016
+ } catch (err) {
1017
+ const error48 = err;
1018
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1019
+ process.exitCode = 1;
1020
+ }
1021
+ });
1022
+ var deleteCommand = new Command6("delete").description("Delete a calendar event (requires User OAuth with calendar scope)").requiredOption("--id <eventId>", "Event ID").option("--notify", "Send notification to attendees").option("--user <userId>", "Target user ID (default: me)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
1023
+ try {
1024
+ await deleteEvent(
1025
+ opts.id,
1026
+ opts.user ?? "me",
1027
+ opts.notify ?? false,
1028
+ opts.profile
1029
+ );
1030
+ output({ success: true, eventId: opts.id, message: "Event deleted" }, opts);
1031
+ } catch (err) {
1032
+ const error48 = err;
1033
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1034
+ process.exitCode = 1;
1035
+ }
1036
+ });
1037
+ var calendarCommand = new Command6("calendar").description("Calendar operations (requires User OAuth)").addCommand(listCommand).addCommand(createCommand).addCommand(updateCommand).addCommand(deleteCommand);
829
1038
 
830
1039
  // src/commands/drive.ts
831
1040
  import { writeFile as writeFile2 } from "fs/promises";
@@ -836,13 +1045,13 @@ import { Command as Command7 } from "commander";
836
1045
  import { readFile as readFile4, stat } from "fs/promises";
837
1046
  import { basename } from "path";
838
1047
  var BASE_URL3 = "https://www.worksapis.com/v1.0";
839
- async function authedFetch(url2, init, profile) {
1048
+ async function authedFetch2(url2, init, profile) {
840
1049
  const token = await getValidUserToken(profile);
841
1050
  const headers = new Headers(init.headers);
842
1051
  headers.set("Authorization", `Bearer ${token}`);
843
1052
  return fetch(url2, { ...init, headers });
844
1053
  }
845
- async function handleError(res) {
1054
+ async function handleError2(res) {
846
1055
  if (res.status === 401) {
847
1056
  throw new AuthError("User token expired. Run `nworks login --user --scope file` again.");
848
1057
  }
@@ -866,8 +1075,8 @@ async function listFiles(userId = "me", folderId, count = 20, cursor, profile =
866
1075
  if (process.env["NWORKS_VERBOSE"] === "1") {
867
1076
  console.error(`[nworks] GET ${url2}`);
868
1077
  }
869
- const res = await authedFetch(url2, { method: "GET" }, profile);
870
- if (!res.ok) return handleError(res);
1078
+ const res = await authedFetch2(url2, { method: "GET" }, profile);
1079
+ if (!res.ok) return handleError2(res);
871
1080
  const data = await res.json();
872
1081
  return { files: data.files ?? [], responseMetaData: data.responseMetaData };
873
1082
  }
@@ -880,7 +1089,7 @@ async function uploadFile(localPath, userId = "me", folderId, overwrite = false,
880
1089
  if (process.env["NWORKS_VERBOSE"] === "1") {
881
1090
  console.error(`[nworks] POST ${createUrl} (create upload URL)`);
882
1091
  }
883
- const createRes = await authedFetch(
1092
+ const createRes = await authedFetch2(
884
1093
  createUrl,
885
1094
  {
886
1095
  method: "POST",
@@ -889,7 +1098,7 @@ async function uploadFile(localPath, userId = "me", folderId, overwrite = false,
889
1098
  },
890
1099
  profile
891
1100
  );
892
- if (!createRes.ok) return handleError(createRes);
1101
+ if (!createRes.ok) return handleError2(createRes);
893
1102
  const { uploadUrl } = await createRes.json();
894
1103
  const fileBuffer = await readFile4(localPath);
895
1104
  const boundary = `----nworks${Date.now()}`;
@@ -907,7 +1116,7 @@ Content-Type: application/octet-stream\r
907
1116
  if (process.env["NWORKS_VERBOSE"] === "1") {
908
1117
  console.error(`[nworks] POST ${uploadUrl} (upload content, ${fileSize} bytes)`);
909
1118
  }
910
- const uploadRes = await authedFetch(
1119
+ const uploadRes = await authedFetch2(
911
1120
  uploadUrl,
912
1121
  {
913
1122
  method: "POST",
@@ -916,7 +1125,7 @@ Content-Type: application/octet-stream\r
916
1125
  },
917
1126
  profile
918
1127
  );
919
- if (!uploadRes.ok) return handleError(uploadRes);
1128
+ if (!uploadRes.ok) return handleError2(uploadRes);
920
1129
  return await uploadRes.json();
921
1130
  }
922
1131
  async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overwrite = false, profile = "default") {
@@ -926,7 +1135,7 @@ async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overw
926
1135
  if (process.env["NWORKS_VERBOSE"] === "1") {
927
1136
  console.error(`[nworks] POST ${createUrl} (create upload URL for buffer)`);
928
1137
  }
929
- const createRes = await authedFetch(
1138
+ const createRes = await authedFetch2(
930
1139
  createUrl,
931
1140
  {
932
1141
  method: "POST",
@@ -935,7 +1144,7 @@ async function uploadBuffer(fileBuffer, fileName, userId = "me", folderId, overw
935
1144
  },
936
1145
  profile
937
1146
  );
938
- if (!createRes.ok) return handleError(createRes);
1147
+ if (!createRes.ok) return handleError2(createRes);
939
1148
  const { uploadUrl } = await createRes.json();
940
1149
  const boundary = `----nworks${Date.now()}`;
941
1150
  const header = Buffer.from(
@@ -952,7 +1161,7 @@ Content-Type: application/octet-stream\r
952
1161
  if (process.env["NWORKS_VERBOSE"] === "1") {
953
1162
  console.error(`[nworks] POST ${uploadUrl} (upload buffer, ${fileSize} bytes)`);
954
1163
  }
955
- const uploadRes = await authedFetch(
1164
+ const uploadRes = await authedFetch2(
956
1165
  uploadUrl,
957
1166
  {
958
1167
  method: "POST",
@@ -961,7 +1170,7 @@ Content-Type: application/octet-stream\r
961
1170
  },
962
1171
  profile
963
1172
  );
964
- if (!uploadRes.ok) return handleError(uploadRes);
1173
+ if (!uploadRes.ok) return handleError2(uploadRes);
965
1174
  return await uploadRes.json();
966
1175
  }
967
1176
  async function downloadFile(fileId, userId = "me", profile = "default") {
@@ -969,7 +1178,7 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
969
1178
  if (process.env["NWORKS_VERBOSE"] === "1") {
970
1179
  console.error(`[nworks] GET ${url2} (get download URL)`);
971
1180
  }
972
- const redirectRes = await authedFetch(
1181
+ const redirectRes = await authedFetch2(
973
1182
  url2,
974
1183
  { method: "GET", redirect: "manual" },
975
1184
  profile
@@ -979,14 +1188,14 @@ async function downloadFile(fileId, userId = "me", profile = "default") {
979
1188
  }
980
1189
  const location = redirectRes.headers.get("location");
981
1190
  if (!location) {
982
- if (!redirectRes.ok) return handleError(redirectRes);
1191
+ if (!redirectRes.ok) return handleError2(redirectRes);
983
1192
  throw new ApiError("NO_REDIRECT", "No download URL returned", redirectRes.status);
984
1193
  }
985
1194
  if (process.env["NWORKS_VERBOSE"] === "1") {
986
1195
  console.error(`[nworks] GET ${location} (download content)`);
987
1196
  }
988
- const downloadRes = await authedFetch(location, { method: "GET" }, profile);
989
- if (!downloadRes.ok) return handleError(downloadRes);
1197
+ const downloadRes = await authedFetch2(location, { method: "GET" }, profile);
1198
+ if (!downloadRes.ok) return handleError2(downloadRes);
990
1199
  const arrayBuffer = await downloadRes.arrayBuffer();
991
1200
  const buffer = Buffer.from(arrayBuffer);
992
1201
  const disposition = downloadRes.headers.get("content-disposition");
@@ -1105,13 +1314,13 @@ import { Command as Command8 } from "commander";
1105
1314
 
1106
1315
  // src/api/mail.ts
1107
1316
  var BASE_URL4 = "https://www.worksapis.com/v1.0";
1108
- async function authedFetch2(url2, init, profile) {
1317
+ async function authedFetch3(url2, init, profile) {
1109
1318
  const token = await getValidUserToken(profile);
1110
1319
  const headers = new Headers(init.headers);
1111
1320
  headers.set("Authorization", `Bearer ${token}`);
1112
1321
  return fetch(url2, { ...init, headers });
1113
1322
  }
1114
- async function handleError2(res) {
1323
+ async function handleError3(res) {
1115
1324
  if (res.status === 401) {
1116
1325
  throw new AuthError("User token expired. Run `nworks login --user --scope mail` again.");
1117
1326
  }
@@ -1140,7 +1349,7 @@ async function sendMail(opts) {
1140
1349
  if (opts.cc) body.cc = opts.cc;
1141
1350
  if (opts.bcc) body.bcc = opts.bcc;
1142
1351
  if (opts.contentType) body.contentType = opts.contentType;
1143
- const res = await authedFetch2(
1352
+ const res = await authedFetch3(
1144
1353
  url2,
1145
1354
  {
1146
1355
  method: "POST",
@@ -1150,7 +1359,7 @@ async function sendMail(opts) {
1150
1359
  profile
1151
1360
  );
1152
1361
  if (res.status === 202) return;
1153
- if (!res.ok) return handleError2(res);
1362
+ if (!res.ok) return handleError3(res);
1154
1363
  }
1155
1364
  async function listMails(folderId = 0, userId = "me", count = 30, cursor, isUnread, profile = "default") {
1156
1365
  const params = new URLSearchParams();
@@ -1161,8 +1370,8 @@ async function listMails(folderId = 0, userId = "me", count = 30, cursor, isUnre
1161
1370
  if (process.env["NWORKS_VERBOSE"] === "1") {
1162
1371
  console.error(`[nworks] GET ${url2}`);
1163
1372
  }
1164
- const res = await authedFetch2(url2, { method: "GET" }, profile);
1165
- if (!res.ok) return handleError2(res);
1373
+ const res = await authedFetch3(url2, { method: "GET" }, profile);
1374
+ if (!res.ok) return handleError3(res);
1166
1375
  const data = await res.json();
1167
1376
  return {
1168
1377
  mails: data.mails ?? [],
@@ -1177,8 +1386,8 @@ async function readMail(mailId, userId = "me", profile = "default") {
1177
1386
  if (process.env["NWORKS_VERBOSE"] === "1") {
1178
1387
  console.error(`[nworks] GET ${url2}`);
1179
1388
  }
1180
- const res = await authedFetch2(url2, { method: "GET" }, profile);
1181
- if (!res.ok) return handleError2(res);
1389
+ const res = await authedFetch3(url2, { method: "GET" }, profile);
1390
+ if (!res.ok) return handleError3(res);
1182
1391
  return await res.json();
1183
1392
  }
1184
1393
 
@@ -1276,9 +1485,280 @@ var readCommand = new Command8("read").description("Read a specific mail (requir
1276
1485
  });
1277
1486
  var mailCommand = new Command8("mail").description("Mail operations (requires User OAuth with mail scope)").addCommand(sendCommand2).addCommand(listCommand3).addCommand(readCommand);
1278
1487
 
1279
- // src/commands/mcp-cmd.ts
1488
+ // src/commands/task.ts
1280
1489
  import { Command as Command9 } from "commander";
1281
1490
 
1491
+ // src/api/task.ts
1492
+ var BASE_URL5 = "https://www.worksapis.com/v1.0";
1493
+ async function authedFetch4(url2, init, profile) {
1494
+ const token = await getValidUserToken(profile);
1495
+ const headers = new Headers(init.headers);
1496
+ headers.set("Authorization", `Bearer ${token}`);
1497
+ return fetch(url2, { ...init, headers });
1498
+ }
1499
+ async function handleError4(res) {
1500
+ if (res.status === 401) {
1501
+ throw new AuthError("User token expired. Run `nworks login --user --scope task` again.");
1502
+ }
1503
+ let code = "UNKNOWN";
1504
+ let description = `HTTP ${res.status}`;
1505
+ try {
1506
+ const body = await res.json();
1507
+ code = body.code ?? code;
1508
+ description = body.description ?? description;
1509
+ } catch {
1510
+ }
1511
+ throw new ApiError(code, description, res.status);
1512
+ }
1513
+ async function resolveUserId(userId, profile) {
1514
+ if (userId !== "me") return userId;
1515
+ const url2 = `${BASE_URL5}/users/me`;
1516
+ const res = await authedFetch4(url2, { method: "GET" }, profile);
1517
+ if (!res.ok) return handleError4(res);
1518
+ const data = await res.json();
1519
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1520
+ console.error(`[nworks] Resolved "me" \u2192 ${data.userId}`);
1521
+ }
1522
+ return data.userId;
1523
+ }
1524
+ async function listTasks(categoryId = "default", userId = "me", count = 50, cursor, status = "ALL", profile = "default") {
1525
+ const params = new URLSearchParams();
1526
+ params.set("categoryId", categoryId);
1527
+ params.set("count", String(count));
1528
+ params.set("status", status);
1529
+ if (cursor) params.set("cursor", cursor);
1530
+ const url2 = `${BASE_URL5}/users/${userId}/tasks?${params.toString()}`;
1531
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1532
+ console.error(`[nworks] GET ${url2}`);
1533
+ }
1534
+ const res = await authedFetch4(url2, { method: "GET" }, profile);
1535
+ if (!res.ok) return handleError4(res);
1536
+ const data = await res.json();
1537
+ return { tasks: data.tasks ?? [], responseMetaData: data.responseMetaData };
1538
+ }
1539
+ async function createTask(opts) {
1540
+ const userId = opts.userId ?? "me";
1541
+ const profile = opts.profile ?? "default";
1542
+ const resolvedUserId = await resolveUserId(userId, profile);
1543
+ const assignorId = opts.assignorId ?? resolvedUserId;
1544
+ const assigneeIds = opts.assigneeIds ?? [resolvedUserId];
1545
+ const body = {
1546
+ assignorId,
1547
+ assignees: assigneeIds.map((id) => ({ assigneeId: id, status: "TODO" })),
1548
+ title: opts.title,
1549
+ content: opts.content ?? "",
1550
+ completionCondition: "ANY_ONE"
1551
+ };
1552
+ if (opts.dueDate) body.dueDate = opts.dueDate;
1553
+ if (opts.categoryId) body.categoryId = opts.categoryId;
1554
+ const url2 = `${BASE_URL5}/users/${userId}/tasks`;
1555
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1556
+ console.error(`[nworks] POST ${url2}`);
1557
+ console.error(`[nworks] Body: ${JSON.stringify(body, null, 2)}`);
1558
+ }
1559
+ const res = await authedFetch4(
1560
+ url2,
1561
+ {
1562
+ method: "POST",
1563
+ headers: { "Content-Type": "application/json" },
1564
+ body: JSON.stringify(body)
1565
+ },
1566
+ profile
1567
+ );
1568
+ if (res.status === 201) {
1569
+ return await res.json();
1570
+ }
1571
+ if (!res.ok) return handleError4(res);
1572
+ return await res.json();
1573
+ }
1574
+ async function updateTask(opts) {
1575
+ const profile = opts.profile ?? "default";
1576
+ const body = {};
1577
+ if (opts.title !== void 0) body.title = opts.title;
1578
+ if (opts.content !== void 0) body.content = opts.content;
1579
+ if (opts.dueDate !== void 0) body.dueDate = opts.dueDate;
1580
+ const url2 = `${BASE_URL5}/tasks/${opts.taskId}`;
1581
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1582
+ console.error(`[nworks] PATCH ${url2}`);
1583
+ }
1584
+ const res = await authedFetch4(
1585
+ url2,
1586
+ {
1587
+ method: "PATCH",
1588
+ headers: { "Content-Type": "application/json" },
1589
+ body: JSON.stringify(body)
1590
+ },
1591
+ profile
1592
+ );
1593
+ if (!res.ok) return handleError4(res);
1594
+ return await res.json();
1595
+ }
1596
+ async function completeTask(taskId, profile = "default") {
1597
+ const url2 = `${BASE_URL5}/tasks/${taskId}/complete`;
1598
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1599
+ console.error(`[nworks] POST ${url2}`);
1600
+ }
1601
+ const res = await authedFetch4(
1602
+ url2,
1603
+ { method: "POST" },
1604
+ profile
1605
+ );
1606
+ if (res.status === 204) return;
1607
+ if (!res.ok) return handleError4(res);
1608
+ }
1609
+ async function incompleteTask(taskId, profile = "default") {
1610
+ const url2 = `${BASE_URL5}/tasks/${taskId}/incomplete`;
1611
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1612
+ console.error(`[nworks] POST ${url2}`);
1613
+ }
1614
+ const res = await authedFetch4(
1615
+ url2,
1616
+ { method: "POST" },
1617
+ profile
1618
+ );
1619
+ if (res.status === 204) return;
1620
+ if (!res.ok) return handleError4(res);
1621
+ }
1622
+ async function deleteTask(taskId, profile = "default") {
1623
+ const url2 = `${BASE_URL5}/tasks/${taskId}`;
1624
+ if (process.env["NWORKS_VERBOSE"] === "1") {
1625
+ console.error(`[nworks] DELETE ${url2}`);
1626
+ }
1627
+ const res = await authedFetch4(
1628
+ url2,
1629
+ { method: "DELETE" },
1630
+ profile
1631
+ );
1632
+ if (res.status === 204) return;
1633
+ if (!res.ok) return handleError4(res);
1634
+ }
1635
+
1636
+ // src/commands/task.ts
1637
+ var listCommand4 = new Command9("list").description("List tasks (requires User OAuth with task or task.read scope)").option("--category <categoryId>", "Category ID (default: default)", "default").option("--status <status>", "Filter: TODO or ALL (default: ALL)", "ALL").option("--count <n>", "Items per page (default: 50)", "50").option("--cursor <cursor>", "Pagination cursor").option("--user <userId>", "Target user ID (default: me)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
1638
+ try {
1639
+ const result = await listTasks(
1640
+ opts.category,
1641
+ opts.user ?? "me",
1642
+ parseInt(opts.count, 10),
1643
+ opts.cursor,
1644
+ opts.status,
1645
+ opts.profile
1646
+ );
1647
+ const tasks = result.tasks.map((t) => ({
1648
+ taskId: t.taskId,
1649
+ title: t.title,
1650
+ status: t.status,
1651
+ dueDate: t.dueDate ?? "",
1652
+ assignor: t.assignorName ?? t.assignorId,
1653
+ created: t.createdTime
1654
+ }));
1655
+ output(
1656
+ {
1657
+ tasks,
1658
+ count: tasks.length,
1659
+ nextCursor: result.responseMetaData?.nextCursor ?? null
1660
+ },
1661
+ opts
1662
+ );
1663
+ } catch (err) {
1664
+ const error48 = err;
1665
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1666
+ process.exitCode = 1;
1667
+ }
1668
+ });
1669
+ var createCommand2 = new Command9("create").description("Create a task (requires User OAuth with task scope)").requiredOption("--title <title>", "Task title").option("--body <content>", "Task content/description").option("--due <date>", "Due date (YYYY-MM-DD)").option("--category <categoryId>", "Category ID").option("--assignee <userIds>", "Assignee user IDs (comma-separated)").option("--user <userId>", "Creator user ID (default: me)").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
1670
+ try {
1671
+ const assigneeIds = opts.assignee ? opts.assignee.split(",").map((s) => s.trim()) : void 0;
1672
+ const result = await createTask({
1673
+ title: opts.title,
1674
+ content: opts.body,
1675
+ dueDate: opts.due,
1676
+ categoryId: opts.category,
1677
+ assigneeIds,
1678
+ userId: opts.user ?? "me",
1679
+ profile: opts.profile
1680
+ });
1681
+ output(
1682
+ {
1683
+ success: true,
1684
+ taskId: result.taskId,
1685
+ title: result.title,
1686
+ status: result.status,
1687
+ dueDate: result.dueDate
1688
+ },
1689
+ opts
1690
+ );
1691
+ } catch (err) {
1692
+ const error48 = err;
1693
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1694
+ process.exitCode = 1;
1695
+ }
1696
+ });
1697
+ var updateCommand2 = new Command9("update").description("Update a task (requires User OAuth with task scope)").requiredOption("--id <taskId>", "Task ID").option("--title <title>", "New title").option("--body <content>", "New content").option("--due <date>", "New due date (YYYY-MM-DD)").option("--status <status>", "Set status: done or todo").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
1698
+ try {
1699
+ const profile = opts.profile;
1700
+ const taskId = opts.id;
1701
+ const status = opts.status;
1702
+ if (status) {
1703
+ if (status.toLowerCase() === "done") {
1704
+ await completeTask(taskId, profile);
1705
+ } else if (status.toLowerCase() === "todo") {
1706
+ await incompleteTask(taskId, profile);
1707
+ } else {
1708
+ throw new Error("Invalid status. Use 'done' or 'todo'.");
1709
+ }
1710
+ }
1711
+ const hasFieldUpdate = opts.title || opts.body || opts.due;
1712
+ if (hasFieldUpdate) {
1713
+ const result = await updateTask({
1714
+ taskId,
1715
+ title: opts.title,
1716
+ content: opts.body,
1717
+ dueDate: opts.due,
1718
+ profile
1719
+ });
1720
+ output(
1721
+ {
1722
+ success: true,
1723
+ taskId: result.taskId,
1724
+ title: result.title,
1725
+ status: result.status,
1726
+ dueDate: result.dueDate
1727
+ },
1728
+ opts
1729
+ );
1730
+ } else if (status) {
1731
+ output(
1732
+ { success: true, taskId, status: status.toLowerCase() === "done" ? "DONE" : "TODO" },
1733
+ opts
1734
+ );
1735
+ } else {
1736
+ throw new Error("Specify at least one of: --title, --body, --due, --status");
1737
+ }
1738
+ } catch (err) {
1739
+ const error48 = err;
1740
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1741
+ process.exitCode = 1;
1742
+ }
1743
+ });
1744
+ var deleteCommand2 = new Command9("delete").description("Delete a task (requires User OAuth with task scope)").requiredOption("--id <taskId>", "Task ID").option("--profile <name>", "Profile name", "default").option("--json", "JSON output").action(async (opts) => {
1745
+ try {
1746
+ await deleteTask(
1747
+ opts.id,
1748
+ opts.profile
1749
+ );
1750
+ output({ success: true, taskId: opts.id, message: "Task deleted" }, opts);
1751
+ } catch (err) {
1752
+ const error48 = err;
1753
+ errorOutput({ code: error48.code, message: error48.message }, opts);
1754
+ process.exitCode = 1;
1755
+ }
1756
+ });
1757
+ var taskCommand = new Command9("task").description("Task operations (requires User OAuth with task scope)").addCommand(listCommand4).addCommand(createCommand2).addCommand(updateCommand2).addCommand(deleteCommand2);
1758
+
1759
+ // src/commands/mcp-cmd.ts
1760
+ import { Command as Command10 } from "commander";
1761
+
1282
1762
  // src/mcp/server.ts
1283
1763
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1284
1764
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -15161,6 +15641,112 @@ function registerTools(server) {
15161
15641
  }
15162
15642
  }
15163
15643
  );
15644
+ server.tool(
15645
+ "nworks_calendar_create",
15646
+ "\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
15647
+ {
15648
+ summary: external_exports.string().describe("\uC77C\uC815 \uC81C\uBAA9"),
15649
+ start: external_exports.string().describe("\uC2DC\uC791 \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
15650
+ end: external_exports.string().describe("\uC885\uB8CC \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
15651
+ timeZone: external_exports.string().optional().describe("\uD0C0\uC784\uC874 (\uAE30\uBCF8: Asia/Seoul)"),
15652
+ description: external_exports.string().optional().describe("\uC77C\uC815 \uC124\uBA85"),
15653
+ location: external_exports.string().optional().describe("\uC7A5\uC18C"),
15654
+ attendees: external_exports.array(external_exports.object({ email: external_exports.string(), displayName: external_exports.string().optional() })).optional().describe("\uCC38\uC11D\uC790 \uBAA9\uB85D"),
15655
+ sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
15656
+ userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
15657
+ },
15658
+ async ({ summary, start, end, timeZone, description, location, attendees, sendNotification, userId }) => {
15659
+ try {
15660
+ const result = await createEvent({
15661
+ summary,
15662
+ start,
15663
+ end,
15664
+ timeZone,
15665
+ description,
15666
+ location,
15667
+ attendees,
15668
+ sendNotification,
15669
+ userId: userId ?? "me"
15670
+ });
15671
+ const event = result.eventComponents?.[0];
15672
+ return {
15673
+ content: [{ type: "text", text: JSON.stringify({ success: true, eventId: event?.eventId, summary: event?.summary, start: event?.start, end: event?.end }) }]
15674
+ };
15675
+ } catch (err) {
15676
+ const error48 = err;
15677
+ return {
15678
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
15679
+ isError: true
15680
+ };
15681
+ }
15682
+ }
15683
+ );
15684
+ server.tool(
15685
+ "nworks_calendar_update",
15686
+ "\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC218\uC815\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
15687
+ {
15688
+ eventId: external_exports.string().describe("\uC77C\uC815 ID"),
15689
+ summary: external_exports.string().optional().describe("\uC0C8 \uC81C\uBAA9"),
15690
+ start: external_exports.string().optional().describe("\uC0C8 \uC2DC\uC791 \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
15691
+ end: external_exports.string().optional().describe("\uC0C8 \uC885\uB8CC \uC77C\uC2DC (YYYY-MM-DDThh:mm:ss)"),
15692
+ timeZone: external_exports.string().optional().describe("\uD0C0\uC784\uC874 (\uAE30\uBCF8: Asia/Seoul)"),
15693
+ description: external_exports.string().optional().describe("\uC0C8 \uC124\uBA85"),
15694
+ location: external_exports.string().optional().describe("\uC0C8 \uC7A5\uC18C"),
15695
+ sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
15696
+ userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
15697
+ },
15698
+ async ({ eventId, summary, start, end, timeZone, description, location, sendNotification, userId }) => {
15699
+ try {
15700
+ await updateEvent({
15701
+ eventId,
15702
+ summary,
15703
+ start,
15704
+ end,
15705
+ timeZone,
15706
+ description,
15707
+ location,
15708
+ sendNotification,
15709
+ userId: userId ?? "me"
15710
+ });
15711
+ return {
15712
+ content: [{ type: "text", text: JSON.stringify({ success: true, eventId, message: "Event updated" }) }]
15713
+ };
15714
+ } catch (err) {
15715
+ const error48 = err;
15716
+ return {
15717
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
15718
+ isError: true
15719
+ };
15720
+ }
15721
+ }
15722
+ );
15723
+ server.tool(
15724
+ "nworks_calendar_delete",
15725
+ "\uCE98\uB9B0\uB354 \uC77C\uC815\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4 (User OAuth calendar scope \uD544\uC694)",
15726
+ {
15727
+ eventId: external_exports.string().describe("\uC0AD\uC81C\uD560 \uC77C\uC815 ID"),
15728
+ sendNotification: external_exports.boolean().optional().describe("\uCC38\uC11D\uC790\uC5D0\uAC8C \uC54C\uB9BC \uBC1C\uC1A1 (\uAE30\uBCF8: false)"),
15729
+ userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
15730
+ },
15731
+ async ({ eventId, sendNotification, userId }) => {
15732
+ try {
15733
+ await deleteEvent(
15734
+ eventId,
15735
+ userId ?? "me",
15736
+ sendNotification ?? false
15737
+ );
15738
+ return {
15739
+ content: [{ type: "text", text: JSON.stringify({ success: true, eventId, message: "Event deleted" }) }]
15740
+ };
15741
+ } catch (err) {
15742
+ const error48 = err;
15743
+ return {
15744
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
15745
+ isError: true
15746
+ };
15747
+ }
15748
+ }
15749
+ );
15164
15750
  server.tool(
15165
15751
  "nworks_drive_list",
15166
15752
  "\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)",
@@ -15413,6 +15999,142 @@ function registerTools(server) {
15413
15999
  }
15414
16000
  }
15415
16001
  );
16002
+ server.tool(
16003
+ "nworks_task_list",
16004
+ "\uD560 \uC77C \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4 (User OAuth task \uB610\uB294 task.read scope \uD544\uC694)",
16005
+ {
16006
+ categoryId: external_exports.string().optional().describe("\uCE74\uD14C\uACE0\uB9AC ID (\uAE30\uBCF8: default)"),
16007
+ status: external_exports.enum(["TODO", "ALL"]).optional().describe("\uD544\uD130: TODO \uB610\uB294 ALL (\uAE30\uBCF8: ALL)"),
16008
+ count: external_exports.number().optional().describe("\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218 (\uAE30\uBCF8: 50, \uCD5C\uB300: 100)"),
16009
+ cursor: external_exports.string().optional().describe("\uD398\uC774\uC9C0\uB124\uC774\uC158 \uCEE4\uC11C"),
16010
+ userId: external_exports.string().optional().describe("\uB300\uC0C1 \uC0AC\uC6A9\uC790 ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
16011
+ },
16012
+ async ({ categoryId, status, count, cursor, userId }) => {
16013
+ try {
16014
+ const result = await listTasks(
16015
+ categoryId ?? "default",
16016
+ userId ?? "me",
16017
+ count ?? 50,
16018
+ cursor,
16019
+ status ?? "ALL"
16020
+ );
16021
+ const tasks = result.tasks.map((t) => ({
16022
+ taskId: t.taskId,
16023
+ title: t.title,
16024
+ status: t.status,
16025
+ dueDate: t.dueDate,
16026
+ assignor: t.assignorName ?? t.assignorId,
16027
+ created: t.createdTime
16028
+ }));
16029
+ return {
16030
+ content: [{ type: "text", text: JSON.stringify({ tasks, count: tasks.length, nextCursor: result.responseMetaData?.nextCursor ?? null }) }]
16031
+ };
16032
+ } catch (err) {
16033
+ const error48 = err;
16034
+ return {
16035
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
16036
+ isError: true
16037
+ };
16038
+ }
16039
+ }
16040
+ );
16041
+ server.tool(
16042
+ "nworks_task_create",
16043
+ "\uD560 \uC77C\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4 (User OAuth task scope \uD544\uC694). \uAE30\uBCF8\uC801\uC73C\uB85C \uC790\uAE30 \uC790\uC2E0\uC5D0\uAC8C \uD560\uB2F9\uB429\uB2C8\uB2E4.",
16044
+ {
16045
+ title: external_exports.string().describe("\uD560 \uC77C \uC81C\uBAA9"),
16046
+ content: external_exports.string().optional().describe("\uD560 \uC77C \uB0B4\uC6A9"),
16047
+ dueDate: external_exports.string().optional().describe("\uB9C8\uAC10\uC77C (YYYY-MM-DD)"),
16048
+ categoryId: external_exports.string().optional().describe("\uCE74\uD14C\uACE0\uB9AC ID"),
16049
+ assigneeIds: external_exports.array(external_exports.string()).optional().describe("\uB2F4\uB2F9\uC790 user ID \uBAA9\uB85D (\uBBF8\uC9C0\uC815 \uC2DC \uC790\uAE30 \uC790\uC2E0)"),
16050
+ userId: external_exports.string().optional().describe("\uC0DD\uC131\uC790 user ID (\uBBF8\uC9C0\uC815 \uC2DC me)")
16051
+ },
16052
+ async ({ title, content, dueDate, categoryId, assigneeIds, userId }) => {
16053
+ try {
16054
+ const result = await createTask({
16055
+ title,
16056
+ content,
16057
+ dueDate,
16058
+ categoryId,
16059
+ assigneeIds,
16060
+ userId: userId ?? "me"
16061
+ });
16062
+ return {
16063
+ content: [{ type: "text", text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }]
16064
+ };
16065
+ } catch (err) {
16066
+ const error48 = err;
16067
+ return {
16068
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
16069
+ isError: true
16070
+ };
16071
+ }
16072
+ }
16073
+ );
16074
+ server.tool(
16075
+ "nworks_task_update",
16076
+ "\uD560 \uC77C\uC744 \uC218\uC815\uD569\uB2C8\uB2E4 (User OAuth task scope \uD544\uC694). \uC0C1\uD0DC \uBCC0\uACBD(done/todo)\uACFC \uD544\uB4DC \uC218\uC815\uC744 \uBAA8\uB450 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.",
16077
+ {
16078
+ taskId: external_exports.string().describe("\uD560 \uC77C ID"),
16079
+ status: external_exports.enum(["done", "todo"]).optional().describe("\uC0C1\uD0DC \uBCC0\uACBD: done \uB610\uB294 todo"),
16080
+ title: external_exports.string().optional().describe("\uC0C8 \uC81C\uBAA9"),
16081
+ content: external_exports.string().optional().describe("\uC0C8 \uB0B4\uC6A9"),
16082
+ dueDate: external_exports.string().optional().describe("\uC0C8 \uB9C8\uAC10\uC77C (YYYY-MM-DD)")
16083
+ },
16084
+ async ({ taskId, status, title, content, dueDate }) => {
16085
+ try {
16086
+ if (status) {
16087
+ if (status === "done") {
16088
+ await completeTask(taskId);
16089
+ } else {
16090
+ await incompleteTask(taskId);
16091
+ }
16092
+ }
16093
+ if (title !== void 0 || content !== void 0 || dueDate !== void 0) {
16094
+ const result = await updateTask({ taskId, title, content, dueDate });
16095
+ return {
16096
+ content: [{ type: "text", text: JSON.stringify({ success: true, taskId: result.taskId, title: result.title, status: result.status, dueDate: result.dueDate }) }]
16097
+ };
16098
+ }
16099
+ if (status) {
16100
+ return {
16101
+ content: [{ type: "text", text: JSON.stringify({ success: true, taskId, status: status === "done" ? "DONE" : "TODO" }) }]
16102
+ };
16103
+ }
16104
+ return {
16105
+ content: [{ type: "text", text: "Error: status, title, content, dueDate \uC911 \uD558\uB098 \uC774\uC0C1\uC744 \uC9C0\uC815\uD558\uC138\uC694." }],
16106
+ isError: true
16107
+ };
16108
+ } catch (err) {
16109
+ const error48 = err;
16110
+ return {
16111
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
16112
+ isError: true
16113
+ };
16114
+ }
16115
+ }
16116
+ );
16117
+ server.tool(
16118
+ "nworks_task_delete",
16119
+ "\uD560 \uC77C\uC744 \uC0AD\uC81C\uD569\uB2C8\uB2E4 (User OAuth task scope \uD544\uC694)",
16120
+ {
16121
+ taskId: external_exports.string().describe("\uC0AD\uC81C\uD560 \uD560 \uC77C ID")
16122
+ },
16123
+ async ({ taskId }) => {
16124
+ try {
16125
+ await deleteTask(taskId);
16126
+ return {
16127
+ content: [{ type: "text", text: JSON.stringify({ success: true, taskId, message: "Task deleted" }) }]
16128
+ };
16129
+ } catch (err) {
16130
+ const error48 = err;
16131
+ return {
16132
+ content: [{ type: "text", text: `Error: ${error48.message}` }],
16133
+ isError: true
16134
+ };
16135
+ }
16136
+ }
16137
+ );
15416
16138
  server.tool(
15417
16139
  "nworks_whoami",
15418
16140
  "\uD604\uC7AC \uC778\uC99D\uB41C NAVER WORKS \uACC4\uC815 \uC815\uBCF4\uB97C \uD655\uC778\uD569\uB2C8\uB2E4",
@@ -15454,7 +16176,7 @@ async function startMcpServer() {
15454
16176
  }
15455
16177
 
15456
16178
  // src/commands/mcp-cmd.ts
15457
- var mcpCommand = new Command9("mcp").description("Start MCP server (stdio transport)").option("--list-tools", "List available MCP tools").action(async (opts) => {
16179
+ var mcpCommand = new Command10("mcp").description("Start MCP server (stdio transport)").option("--list-tools", "List available MCP tools").action(async (opts) => {
15458
16180
  if (opts.listTools) {
15459
16181
  console.log("nworks_message_send \u2014 Send message to user or channel");
15460
16182
  console.log("nworks_message_members \u2014 List channel members");
@@ -15469,7 +16191,7 @@ var mcpCommand = new Command9("mcp").description("Start MCP server (stdio transp
15469
16191
  // src/index.ts
15470
16192
  var require2 = createRequire(import.meta.url);
15471
16193
  var { version: version2 } = require2("../package.json");
15472
- var program = new Command10().name("nworks").description("NAVER WORKS CLI \u2014 built for humans and AI agents").version(version2).option("--json", "Always output JSON").option("-v, --verbose", "Debug logging").option("--dry-run", "Print request without calling API").option("-p, --profile <name>", "Profile name", "default");
16194
+ var program = new Command11().name("nworks").description("NAVER WORKS CLI \u2014 built for humans and AI agents").version(version2).option("--json", "Always output JSON").option("-v, --verbose", "Debug logging").option("--dry-run", "Print request without calling API").option("-p, --profile <name>", "Profile name", "default");
15473
16195
  program.addCommand(loginCommand);
15474
16196
  program.addCommand(logoutCommand);
15475
16197
  program.addCommand(whoamiCommand);
@@ -15478,6 +16200,7 @@ program.addCommand(directoryCommand);
15478
16200
  program.addCommand(calendarCommand);
15479
16201
  program.addCommand(driveCommand);
15480
16202
  program.addCommand(mailCommand);
16203
+ program.addCommand(taskCommand);
15481
16204
  program.addCommand(mcpCommand);
15482
16205
  program.parse();
15483
16206
  //# sourceMappingURL=index.js.map