@bifos/dooray-cli 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/index.ts
27
- var import_commander48 = require("commander");
27
+ var import_commander61 = require("commander");
28
28
  var import_chalk7 = __toESM(require("chalk"));
29
29
 
30
30
  // src/commands/config.ts
@@ -801,6 +801,131 @@ var DoorayApiClient = class {
801
801
  throw await toDoorayCliError(e);
802
802
  }
803
803
  }
804
+ // ─── Wiki Page Files (ADR-029) ──────────────────────
805
+ async uploadWikiPageFile(wikiId, pageId, filePath, type) {
806
+ try {
807
+ const fileName = (0, import_node_path3.basename)(filePath);
808
+ const fileBuffer = await (0, import_promises3.readFile)(filePath);
809
+ const buildFormData = () => {
810
+ const fd = new FormData();
811
+ fd.append("type", type);
812
+ fd.append("file", new Blob([fileBuffer]), fileName);
813
+ return fd;
814
+ };
815
+ const url = `${this.baseUrl}wiki/v1/wikis/${wikiId}/pages/${pageId}/files`;
816
+ const res = await fetch(url, {
817
+ method: "POST",
818
+ headers: { Authorization: this.authHeader },
819
+ body: buildFormData(),
820
+ redirect: "manual"
821
+ });
822
+ if (res.status === 307) {
823
+ const location = res.headers.get("location");
824
+ if (!location) {
825
+ throw new DoorayCliError("\uC704\uD0A4 \uD30C\uC77C \uC5C5\uB85C\uB4DC \uB9AC\uB2E4\uC774\uB809\uD2B8 URL\uC744 \uBC1B\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.", EXIT_API_ERROR);
826
+ }
827
+ const uploadRes = await fetch(location, {
828
+ method: "POST",
829
+ headers: { Authorization: this.authHeader },
830
+ body: buildFormData()
831
+ });
832
+ if (!uploadRes.ok) {
833
+ throw new DoorayCliError(`\uC704\uD0A4 \uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${uploadRes.status})`, EXIT_API_ERROR);
834
+ }
835
+ return await uploadRes.json();
836
+ }
837
+ if (!res.ok) {
838
+ throw new DoorayCliError(`\uC704\uD0A4 \uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${res.status})`, EXIT_API_ERROR);
839
+ }
840
+ return await res.json();
841
+ } catch (e) {
842
+ if (e instanceof DoorayCliError) throw e;
843
+ throw await toDoorayCliError(e);
844
+ }
845
+ }
846
+ async downloadWikiPageFile(wikiId, pageId, fileId) {
847
+ try {
848
+ const res = await this.api.get(`wiki/v1/wikis/${wikiId}/pages/${pageId}/files/${fileId}`, {
849
+ redirect: "manual",
850
+ throwHttpErrors: false
851
+ });
852
+ if (res.status !== 307) {
853
+ throw new DoorayCliError(
854
+ `\uC704\uD0A4 \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328 (\uC608\uC0C1 status 307, \uC2E4\uC81C ${res.status})`,
855
+ EXIT_API_ERROR
856
+ );
857
+ }
858
+ const location = res.headers.get("location");
859
+ if (!location) {
860
+ throw new DoorayCliError("\uC704\uD0A4 \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uB9AC\uB2E4\uC774\uB809\uD2B8 URL\uC744 \uBC1B\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.", EXIT_API_ERROR);
861
+ }
862
+ const fileRes = await fetch(location, {
863
+ headers: { Authorization: this.authHeader }
864
+ });
865
+ if (!fileRes.ok) {
866
+ throw new DoorayCliError(`\uC704\uD0A4 \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328 (${fileRes.status})`, EXIT_API_ERROR);
867
+ }
868
+ const disposition = fileRes.headers.get("content-disposition");
869
+ let fileName = `file-${fileId}`;
870
+ if (disposition) {
871
+ const match = disposition.match(/filename\*?=(?:UTF-8''|"?)([^";]+)/i);
872
+ if (match) fileName = (0, import_node_path3.basename)(decodeURIComponent(match[1].replace(/"/g, "")));
873
+ }
874
+ const buffer = await fileRes.arrayBuffer();
875
+ return { buffer, fileName };
876
+ } catch (e) {
877
+ if (e instanceof DoorayCliError) throw e;
878
+ throw await toDoorayCliError(e);
879
+ }
880
+ }
881
+ async deleteWikiPageFile(wikiId, pageId, fileId) {
882
+ try {
883
+ return await this.api.delete(`wiki/v1/wikis/${wikiId}/pages/${pageId}/files/${fileId}`).json();
884
+ } catch (e) {
885
+ throw await toDoorayCliError(e);
886
+ }
887
+ }
888
+ // ─── Wiki Page Comments ─────────────────────────────
889
+ async getWikiPageComments(wikiId, pageId, params) {
890
+ try {
891
+ return await this.api.get(`wiki/v1/wikis/${wikiId}/pages/${pageId}/comments`, {
892
+ searchParams: {
893
+ ...params?.page !== void 0 && { page: params.page },
894
+ ...params?.size !== void 0 && { size: params.size }
895
+ }
896
+ }).json();
897
+ } catch (e) {
898
+ throw await toDoorayCliError(e);
899
+ }
900
+ }
901
+ async getWikiPageComment(wikiId, pageId, commentId) {
902
+ try {
903
+ return await this.api.get(`wiki/v1/wikis/${wikiId}/pages/${pageId}/comments/${commentId}`).json();
904
+ } catch (e) {
905
+ throw await toDoorayCliError(e);
906
+ }
907
+ }
908
+ async addWikiPageComment(wikiId, pageId, body) {
909
+ try {
910
+ return await this.api.post(`wiki/v1/wikis/${wikiId}/pages/${pageId}/comments`, { json: body }).json();
911
+ } catch (e) {
912
+ throw await toDoorayCliError(e);
913
+ }
914
+ }
915
+ async updateWikiPageComment(wikiId, pageId, commentId, body) {
916
+ try {
917
+ return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}/comments/${commentId}`, { json: body }).json();
918
+ } catch (e) {
919
+ throw await toDoorayCliError(e);
920
+ }
921
+ }
922
+ async deleteWikiPageComment(wikiId, pageId, commentId) {
923
+ try {
924
+ return await this.api.delete(`wiki/v1/wikis/${wikiId}/pages/${pageId}/comments/${commentId}`).json();
925
+ } catch (e) {
926
+ throw await toDoorayCliError(e);
927
+ }
928
+ }
804
929
  // ─── Templates ──────────────────────────────────────
805
930
  async getProjectTemplates(projectId, params) {
806
931
  try {
@@ -1854,6 +1979,7 @@ async function resolvePost(client, projectId, postNumber) {
1854
1979
  // src/utils/dooray-url.ts
1855
1980
  var TASK_URL_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/task\/to\/(\d+)(?:[/?#].*)?$/;
1856
1981
  var TASK_URL_ALT_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/task\/(?:\d+)\/(\d+)(?:[/?#].*)?$/;
1982
+ var WIKI_URL_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/wiki\/(\d+)\/(\d+)(?:[/?#].*)?$/;
1857
1983
  function parseDoorayTaskUrl(input2) {
1858
1984
  const m1 = TASK_URL_RE.exec(input2);
1859
1985
  if (m1) return m1[1];
@@ -1861,6 +1987,11 @@ function parseDoorayTaskUrl(input2) {
1861
1987
  if (m2) return m2[1];
1862
1988
  return null;
1863
1989
  }
1990
+ function parseDoorayWikiUrl(input2) {
1991
+ const m = WIKI_URL_RE.exec(input2);
1992
+ if (!m) return null;
1993
+ return { wikiId: m[1], pageId: m[2] };
1994
+ }
1864
1995
  function isLikelyDoorayUrl(input2) {
1865
1996
  return /^https?:\/\//.test(input2);
1866
1997
  }
@@ -4034,102 +4165,770 @@ var wikiPageEditCommand = new import_commander38.Command("edit").description("\u
4034
4165
  `);
4035
4166
  });
4036
4167
 
4037
- // src/commands/member/index.ts
4038
- var import_commander42 = require("commander");
4168
+ // src/commands/wiki/page-file/index.ts
4169
+ var import_commander44 = require("commander");
4039
4170
 
4040
- // src/commands/member/get.ts
4171
+ // src/commands/wiki/page-file/list.ts
4041
4172
  var import_commander39 = require("commander");
4042
4173
 
4043
- // src/formatters/member.ts
4044
- function formatMemberDetail(member, opts) {
4045
- if (opts.json) {
4046
- printJson(member);
4047
- return;
4174
+ // src/resolvers/wiki-page-input.ts
4175
+ var INPUT_HELP2 = "\uC704\uD0A4 \uD398\uC774\uC9C0\uB97C \uC2DD\uBCC4\uD560 \uC815\uBCF4\uAC00 \uBD80\uC871\uD569\uB2C8\uB2E4. \uB2E4\uC74C \uC911 \uD558\uB098\uB97C \uC785\uB825\uD558\uC138\uC694:\n - <project> <page-id> \uC608: my-project 4071828729722696495\n - --id <page-id> --project <project> (\uB610\uB294 --url)\n - <Dooray URL> \uC608: https://x.dooray.com/wiki/<wikiId>/<pageId>";
4176
+ async function resolveWikiPageInput(client, args) {
4177
+ const { projectArg, pageIdArg, idOpt, urlOpt, project } = args;
4178
+ const hasPositional = !!projectArg || !!pageIdArg;
4179
+ if (idOpt && urlOpt) {
4180
+ throw new DoorayCliError("--id\uC640 --url\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
4048
4181
  }
4049
- if (opts.quiet) {
4050
- process.stdout.write(member.id + "\n");
4051
- return;
4182
+ if ((idOpt || urlOpt) && hasPositional) {
4183
+ throw new DoorayCliError(
4184
+ "--id/--url\uACFC positional \uC778\uC790(<project> <page-id>)\uB294 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
4185
+ EXIT_PARAM_ERROR
4186
+ );
4052
4187
  }
4053
- const lines = [
4054
- `\uC774\uB984: ${member.name}`,
4055
- ...member.englishName ? [`\uC601\uBB38\uBA85: ${member.englishName}`] : [],
4056
- ...member.nickname ? [`\uBCC4\uBA85: ${member.nickname}`] : [],
4057
- ...member.userCode ? [`\uC0AC\uBC88/ID: ${member.userCode}`] : [],
4058
- ...member.externalEmailAddress ? [`\uC678\uBD80 \uC774\uBA54\uC77C: ${member.externalEmailAddress}`] : [],
4059
- `member-id: ${member.id}`
4060
- ];
4061
- process.stdout.write(lines.join("\n") + "\n");
4062
- }
4063
- function formatMemberList(rows, opts) {
4064
- output(opts, {
4065
- headers: ["ID", "Name", "Role"],
4066
- rows: rows.map((r) => [r.id, r.name, r.role ?? ""]),
4067
- raw: rows,
4068
- ids: rows.map((r) => r.id)
4069
- });
4070
- }
4071
- function formatMemberSearchResults(members, opts) {
4072
- output(opts, {
4073
- headers: ["ID", "Name", "UserCode", "Nickname", "Email"],
4074
- rows: members.map((m) => [
4075
- m.id,
4076
- m.name,
4077
- m.userCode ?? "",
4078
- m.nickname ?? "",
4079
- m.externalEmailAddress ?? ""
4080
- ]),
4081
- raw: members,
4082
- ids: members.map((m) => m.id)
4083
- });
4188
+ if (urlOpt) {
4189
+ const parsed = parseDoorayWikiUrl(urlOpt);
4190
+ if (!parsed) {
4191
+ throw new DoorayCliError(
4192
+ `--url \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${urlOpt}"
4193
+ \uC608: https://x.dooray.com/wiki/<wikiId>/<pageId>`,
4194
+ EXIT_PARAM_ERROR
4195
+ );
4196
+ }
4197
+ return parsed;
4198
+ }
4199
+ if (projectArg && !pageIdArg && isLikelyDoorayUrl(projectArg)) {
4200
+ const parsed = parseDoorayWikiUrl(projectArg);
4201
+ if (!parsed) {
4202
+ throw new DoorayCliError(
4203
+ `Dooray Wiki URL \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${projectArg}"
4204
+ \uC608: https://x.dooray.com/wiki/<wikiId>/<pageId>`,
4205
+ EXIT_PARAM_ERROR
4206
+ );
4207
+ }
4208
+ return parsed;
4209
+ }
4210
+ if (idOpt) {
4211
+ const projectCode = project ?? projectArg;
4212
+ if (!projectCode) {
4213
+ throw new DoorayCliError(
4214
+ "--id \uBAA8\uB4DC\uB294 --project <code> \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uB610\uB294 \uCCAB positional \uC5D0 project code).",
4215
+ EXIT_PARAM_ERROR
4216
+ );
4217
+ }
4218
+ const wikiId = await resolveWiki(client, projectCode);
4219
+ return { wikiId, pageId: idOpt };
4220
+ }
4221
+ if (projectArg && pageIdArg) {
4222
+ const wikiId = await resolveWiki(client, projectArg);
4223
+ return { wikiId, pageId: pageIdArg };
4224
+ }
4225
+ throw new DoorayCliError(INPUT_HELP2, EXIT_PARAM_ERROR);
4084
4226
  }
4085
4227
 
4086
- // src/commands/member/get.ts
4087
- var memberGetCommand = new import_commander39.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
4088
- const globalOpts = memberGetCommand.optsWithGlobals();
4228
+ // src/commands/wiki/page-file/list.ts
4229
+ function formatSize3(bytes) {
4230
+ if (bytes < 1024) return `${bytes}B`;
4231
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
4232
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
4233
+ }
4234
+ var wikiPageFileListCommand = new import_commander39.Command("list").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C (general + inline image)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray Wiki URL)").argument("[page-id]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (--project \uB3D9\uBC18 \uD544\uC694)").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC5D0\uC11C wikiId \uD574\uC11D\uC6A9)").action(async (project, pageIdArg, opts) => {
4235
+ const globalOpts = wikiPageFileListCommand.optsWithGlobals();
4089
4236
  const config = await getConfigOrThrow();
4090
4237
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4091
- const res = await client.getMemberDetail(memberId);
4092
- formatMemberDetail(res.result, globalOpts);
4238
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4239
+ projectArg: project,
4240
+ pageIdArg,
4241
+ idOpt: opts.id,
4242
+ urlOpt: opts.url,
4243
+ project: opts.project
4244
+ });
4245
+ startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
4246
+ try {
4247
+ const res = await client.getWikiPage(wikiId, pageId);
4248
+ const files = (res.result.files ?? []).map((f) => ({ ...f, type: "general" }));
4249
+ const images = (res.result.images ?? []).map((f) => ({ ...f, type: "inline_image" }));
4250
+ const merged = [...files, ...images];
4251
+ stopSpinner(true, `\uCCA8\uBD80\uD30C\uC77C ${merged.length}\uAC1C (general ${files.length} + inline ${images.length})`);
4252
+ output(globalOpts, {
4253
+ headers: ["ID", "Type", "\uD30C\uC77C\uBA85", "\uD06C\uAE30"],
4254
+ rows: merged.map((f) => [f.id, f.type, f.name, formatSize3(f.size)]),
4255
+ raw: merged,
4256
+ ids: merged.map((f) => f.id)
4257
+ });
4258
+ } catch (e) {
4259
+ stopSpinner(false);
4260
+ throw e;
4261
+ }
4093
4262
  });
4094
4263
 
4095
- // src/commands/member/list.ts
4264
+ // src/commands/wiki/page-file/upload.ts
4096
4265
  var import_commander40 = require("commander");
4097
- var memberListCommand = new import_commander40.Command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBA64\uBC84 \uBAA9\uB85D").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
4098
- const globalOpts = memberListCommand.optsWithGlobals();
4266
+ var wikiPageFileUploadCommand = new import_commander40.Command("upload").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uC5C5\uB85C\uB4DC (multipart type \uC21C\uC11C \uAC15\uC81C, ADR-029)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray Wiki URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg2]", "page-id \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg3]", "\uD30C\uC77C \uACBD\uB85C (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC5D0\uC11C wikiId \uD574\uC11D\uC6A9)").option("--file <path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C (positional \uB300\uCCB4)").option("--type <type>", "\uD30C\uC77C \uD0C0\uC785: general | inline_image (\uAE30\uBCF8 general)", "general").action(async (arg1, arg2, arg3, opts) => {
4099
4267
  const config = await getConfigOrThrow();
4100
4268
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4101
- startSpinner("\uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C \uC911...");
4102
- const projectId = await resolveProject(client, project);
4103
- const members = await ensureMembers(client, projectId);
4104
- stopSpinner(true, `${members.length}\uBA85`);
4105
- formatMemberList(
4106
- members.map((m) => ({ id: m.organizationMemberId, name: m.name })),
4107
- globalOpts
4108
- );
4109
- });
4110
-
4111
- // src/commands/member/search.ts
4112
- var import_commander41 = require("commander");
4113
- var memberSearchCommand = new import_commander41.Command("search").description("organization \uC804\uCCB4\uC5D0\uC11C \uBA64\uBC84 \uAC80\uC0C9").argument("[keyword]", "\uC774\uB984 \uAC80\uC0C9\uC5B4 (--email/--user-code \uBBF8\uC9C0\uC815 \uC2DC name\uC73C\uB85C \uAC80\uC0C9)").option("--email <email>", "\uC678\uBD80 \uC774\uBA54\uC77C (\uCF64\uB9C8 \uAD6C\uBD84 \uAC00\uB2A5, exact match)").option("--user-code <code>", "\uC0AC\uBC88 like \uAC80\uC0C9").option("--user-code-exact <code>", "\uC0AC\uBC88 exact match").option("--page <n>", "\uD398\uC774\uC9C0 (\uAE30\uBCF8 0)", "0").option("--size <n>", "\uD398\uC774\uC9C0 \uD06C\uAE30 (\uAE30\uBCF8 20, max 100)", "20").action(async (keyword, opts) => {
4114
- const globalOpts = memberSearchCommand.optsWithGlobals();
4115
- const filterCount = [keyword, opts.email, opts.userCode, opts.userCodeExact].filter(Boolean).length;
4116
- if (filterCount === 0) {
4269
+ const fileType = opts.type;
4270
+ if (fileType !== "general" && fileType !== "inline_image") {
4117
4271
  throw new DoorayCliError(
4118
- "\uAC80\uC0C9 \uC870\uAC74\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. positional <keyword>(=name) \uB610\uB294 --email/--user-code/--user-code-exact \uC911 \uD558\uB098 \uC774\uC0C1.",
4272
+ `--type \uC740 general \uB610\uB294 inline_image \uC5EC\uC57C \uD569\uB2C8\uB2E4 (\uC785\uB825: ${opts.type})`,
4119
4273
  EXIT_PARAM_ERROR
4120
4274
  );
4121
4275
  }
4122
- if (keyword && (opts.email || opts.userCode || opts.userCodeExact)) {
4123
- throw new DoorayCliError(
4124
- "positional <keyword>(name)\uC640 --email/--user-code/--user-code-exact \uC635\uC158\uC740 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00.",
4125
- EXIT_PARAM_ERROR
4126
- );
4276
+ let projectArg;
4277
+ let pageIdArg;
4278
+ let filePath = opts.file;
4279
+ if (opts.id || opts.url) {
4280
+ if (arg2 || arg3) {
4281
+ throw new DoorayCliError(
4282
+ "--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C \uACBD\uB85C \uC678 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
4283
+ EXIT_PARAM_ERROR
4284
+ );
4285
+ }
4286
+ filePath = filePath ?? arg1;
4287
+ } else if (arg3) {
4288
+ projectArg = arg1;
4289
+ pageIdArg = arg2;
4290
+ filePath = filePath ?? arg3;
4291
+ } else if (arg1 && !arg2) {
4292
+ projectArg = arg1;
4293
+ if (!filePath) {
4294
+ throw new DoorayCliError(
4295
+ "URL/--id \uBAA8\uB4DC \uC678\uC5D0\uC11C\uB294 <project> <page-id> \uB458 \uB2E4 \uB610\uB294 --file \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
4296
+ EXIT_PARAM_ERROR
4297
+ );
4298
+ }
4299
+ } else {
4300
+ projectArg = arg1;
4301
+ pageIdArg = arg2;
4302
+ if (!filePath) {
4303
+ throw new DoorayCliError(
4304
+ "<file> \uC774 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
4305
+ EXIT_PARAM_ERROR
4306
+ );
4307
+ }
4308
+ }
4309
+ if (!filePath) {
4310
+ throw new DoorayCliError("\uD30C\uC77C \uACBD\uB85C\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
4311
+ }
4312
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4313
+ projectArg,
4314
+ pageIdArg,
4315
+ idOpt: opts.id,
4316
+ urlOpt: opts.url,
4317
+ project: opts.project
4318
+ });
4319
+ startSpinner(`\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC911... (${fileType})`);
4320
+ try {
4321
+ const res = await client.uploadWikiPageFile(wikiId, pageId, filePath, fileType);
4322
+ stopSpinner(true, "\uC5C5\uB85C\uB4DC \uC644\uB8CC");
4323
+ process.stdout.write(`attachFileId: ${res.result.attachFileId}
4324
+ `);
4325
+ process.stdout.write(`name: ${res.result.name}
4326
+ `);
4327
+ process.stdout.write(`size: ${res.result.size}
4328
+ `);
4329
+ process.stdout.write(`type: ${res.result.type}
4330
+ `);
4331
+ if (fileType === "inline_image") {
4332
+ process.stdout.write("\n\uBCF8\uBB38 \uC0BD\uC785\uC6A9 markdown snippet (\uC9C1\uC811 wiki page edit \uC73C\uB85C \uBCF8\uBB38\uC5D0 \uBC15\uC73C\uC138\uC694):\n");
4333
+ process.stdout.write(` ![${res.result.name}](/wikis/${wikiId}/files/${res.result.attachFileId})
4334
+ `);
4335
+ }
4336
+ } catch (e) {
4337
+ stopSpinner(false);
4338
+ throw e;
4127
4339
  }
4340
+ });
4341
+
4342
+ // src/commands/wiki/page-file/download.ts
4343
+ var import_commander41 = require("commander");
4344
+ var import_promises11 = require("fs/promises");
4345
+ var import_node_path9 = require("path");
4346
+ var wikiPageFileDownloadCommand = new import_commander41.Command("download").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray Wiki URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "page-id \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC5D0\uC11C wikiId \uD574\uC11D\uC6A9)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (arg1, arg2, arg3, opts) => {
4128
4347
  const config = await getConfigOrThrow();
4129
4348
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4130
- const size = Math.min(Math.max(1, Number(opts.size) || 20), 100);
4131
- const page = Math.max(0, Number(opts.page) || 0);
4132
- startSpinner("\uBA64\uBC84 \uAC80\uC0C9 \uC911...");
4349
+ let projectArg;
4350
+ let pageIdArg;
4351
+ let fileId = opts.fileId;
4352
+ if (opts.id || opts.url) {
4353
+ if (arg2 || arg3) {
4354
+ throw new DoorayCliError(
4355
+ "--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
4356
+ EXIT_PARAM_ERROR
4357
+ );
4358
+ }
4359
+ fileId = fileId ?? arg1;
4360
+ } else if (arg3) {
4361
+ projectArg = arg1;
4362
+ pageIdArg = arg2;
4363
+ fileId = fileId ?? arg3;
4364
+ } else if (arg1 && !arg2) {
4365
+ projectArg = arg1;
4366
+ if (!fileId) {
4367
+ throw new DoorayCliError(
4368
+ "URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --file-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
4369
+ EXIT_PARAM_ERROR
4370
+ );
4371
+ }
4372
+ } else {
4373
+ projectArg = arg1;
4374
+ pageIdArg = arg2;
4375
+ if (!fileId) {
4376
+ throw new DoorayCliError(
4377
+ "<file-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
4378
+ EXIT_PARAM_ERROR
4379
+ );
4380
+ }
4381
+ }
4382
+ if (!fileId) {
4383
+ throw new DoorayCliError("\uD30C\uC77C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
4384
+ }
4385
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4386
+ projectArg,
4387
+ pageIdArg,
4388
+ idOpt: opts.id,
4389
+ urlOpt: opts.url,
4390
+ project: opts.project
4391
+ });
4392
+ startSpinner("\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
4393
+ try {
4394
+ const { buffer, fileName } = await client.downloadWikiPageFile(wikiId, pageId, fileId);
4395
+ const outputPath = (0, import_node_path9.join)(opts.output, (0, import_node_path9.basename)(fileName));
4396
+ await (0, import_promises11.writeFile)(outputPath, Buffer.from(buffer));
4397
+ stopSpinner(true, `\uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC: ${outputPath}`);
4398
+ process.stdout.write(`${outputPath}
4399
+ `);
4400
+ } catch (e) {
4401
+ stopSpinner(false);
4402
+ throw e;
4403
+ }
4404
+ });
4405
+
4406
+ // src/commands/wiki/page-file/download-all.ts
4407
+ var import_commander42 = require("commander");
4408
+ var import_promises12 = require("fs/promises");
4409
+ var import_node_path10 = require("path");
4410
+ var wikiPageFileDownloadAllCommand = new import_commander42.Command("download-all").description("\uC704\uD0A4 \uD398\uC774\uC9C0\uC758 \uBAA8\uB4E0 \uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC (general + inline image)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray Wiki URL)").argument("[page-id]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (--project \uB3D9\uBC18 \uD544\uC694)").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC5D0\uC11C wikiId \uD574\uC11D\uC6A9)").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (project, pageIdArg, opts) => {
4411
+ const config = await getConfigOrThrow();
4412
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4413
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4414
+ projectArg: project,
4415
+ pageIdArg,
4416
+ idOpt: opts.id,
4417
+ urlOpt: opts.url,
4418
+ project: opts.project
4419
+ });
4420
+ startSpinner("\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
4421
+ let allFiles;
4422
+ try {
4423
+ const pageRes = await client.getWikiPage(wikiId, pageId);
4424
+ allFiles = [...pageRes.result.files ?? [], ...pageRes.result.images ?? []];
4425
+ } catch (e) {
4426
+ stopSpinner(false);
4427
+ throw e;
4428
+ }
4429
+ if (allFiles.length === 0) {
4430
+ stopSpinner(true, "\uCCA8\uBD80\uD30C\uC77C \uC5C6\uC74C");
4431
+ process.stdout.write("\uCCA8\uBD80\uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
4432
+ return;
4433
+ }
4434
+ stopSpinner(true, `${allFiles.length}\uAC1C \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2DC\uC791`);
4435
+ await (0, import_promises12.mkdir)(opts.output, { recursive: true });
4436
+ let successCount = 0;
4437
+ const failures = [];
4438
+ for (const f of allFiles) {
4439
+ try {
4440
+ const { buffer, fileName } = await client.downloadWikiPageFile(wikiId, pageId, f.id);
4441
+ await (0, import_promises12.writeFile)((0, import_node_path10.join)(opts.output, fileName), Buffer.from(buffer));
4442
+ process.stdout.write(`\u2713 ${fileName}
4443
+ `);
4444
+ successCount++;
4445
+ } catch (e) {
4446
+ failures.push({ fileId: f.id, error: e instanceof Error ? e.message : String(e) });
4447
+ process.stderr.write(`\u2717 ${f.name} (${f.id}): ${e instanceof Error ? e.message : String(e)}
4448
+ `);
4449
+ }
4450
+ }
4451
+ process.stdout.write(`
4452
+ \uC644\uB8CC: ${successCount}/${allFiles.length}
4453
+ `);
4454
+ if (failures.length > 0) {
4455
+ throw new DoorayCliError(
4456
+ `${failures.length}\uAC1C \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328 (\uC131\uACF5: ${successCount}/${allFiles.length})`,
4457
+ EXIT_API_ERROR
4458
+ );
4459
+ }
4460
+ });
4461
+
4462
+ // src/commands/wiki/page-file/delete.ts
4463
+ var import_commander43 = require("commander");
4464
+ var wikiPageFileDeleteCommand = new import_commander43.Command("delete").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uC0AD\uC81C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray Wiki URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "page-id \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC5D0\uC11C wikiId \uD574\uC11D\uC6A9)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
4465
+ const config = await getConfigOrThrow();
4466
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4467
+ let projectArg;
4468
+ let pageIdArg;
4469
+ let fileId = opts.fileId;
4470
+ if (opts.id || opts.url) {
4471
+ if (arg2 || arg3) {
4472
+ throw new DoorayCliError(
4473
+ "--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
4474
+ EXIT_PARAM_ERROR
4475
+ );
4476
+ }
4477
+ fileId = fileId ?? arg1;
4478
+ } else if (arg3) {
4479
+ projectArg = arg1;
4480
+ pageIdArg = arg2;
4481
+ fileId = fileId ?? arg3;
4482
+ } else if (arg1 && !arg2) {
4483
+ projectArg = arg1;
4484
+ if (!fileId) {
4485
+ throw new DoorayCliError(
4486
+ "URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --file-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
4487
+ EXIT_PARAM_ERROR
4488
+ );
4489
+ }
4490
+ } else {
4491
+ projectArg = arg1;
4492
+ pageIdArg = arg2;
4493
+ if (!fileId) {
4494
+ throw new DoorayCliError(
4495
+ "<file-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
4496
+ EXIT_PARAM_ERROR
4497
+ );
4498
+ }
4499
+ }
4500
+ if (!fileId) {
4501
+ throw new DoorayCliError("\uD30C\uC77C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
4502
+ }
4503
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4504
+ projectArg,
4505
+ pageIdArg,
4506
+ idOpt: opts.id,
4507
+ urlOpt: opts.url,
4508
+ project: opts.project
4509
+ });
4510
+ startSpinner("\uD30C\uC77C \uC0AD\uC81C \uC911...");
4511
+ try {
4512
+ await client.deleteWikiPageFile(wikiId, pageId, fileId);
4513
+ stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
4514
+ process.stdout.write(`\uD30C\uC77C(${fileId})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
4515
+ `);
4516
+ } catch (e) {
4517
+ stopSpinner(false);
4518
+ throw e;
4519
+ }
4520
+ });
4521
+
4522
+ // src/commands/wiki/page-file/index.ts
4523
+ var wikiPageFileCommand = new import_commander44.Command("file").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839 (Issue #70, ADR-029)");
4524
+ wikiPageFileCommand.addCommand(wikiPageFileListCommand);
4525
+ wikiPageFileCommand.addCommand(wikiPageFileUploadCommand);
4526
+ wikiPageFileCommand.addCommand(wikiPageFileDownloadCommand);
4527
+ wikiPageFileCommand.addCommand(wikiPageFileDownloadAllCommand);
4528
+ wikiPageFileCommand.addCommand(wikiPageFileDeleteCommand);
4529
+
4530
+ // src/commands/wiki/page-comment/index.ts
4531
+ var import_commander51 = require("commander");
4532
+
4533
+ // src/commands/wiki/page-comment/list.ts
4534
+ var import_commander45 = require("commander");
4535
+
4536
+ // src/formatters/wiki-comment.ts
4537
+ function formatWikiCommentList(comments, opts) {
4538
+ output(opts.globalOpts, {
4539
+ headers: ["ID", "\uC791\uC131\uC790", "\uC0DD\uC131\uC77C", "\uBCF8\uBB38 (\uC694\uC57D)"],
4540
+ rows: comments.map((c) => [
4541
+ c.id,
4542
+ c.creator.member.name,
4543
+ c.createdAt,
4544
+ truncate(c.body.content, 60)
4545
+ ]),
4546
+ raw: comments,
4547
+ ids: comments.map((c) => c.id)
4548
+ });
4549
+ }
4550
+ function formatWikiCommentDetail(comment, globalOpts) {
4551
+ if (globalOpts.json) {
4552
+ printJson(comment);
4553
+ return;
4554
+ }
4555
+ if (globalOpts.quiet) {
4556
+ printQuiet([comment.id]);
4557
+ return;
4558
+ }
4559
+ process.stdout.write(`ID: ${comment.id}
4560
+ `);
4561
+ process.stdout.write(`Page ID: ${comment.page.id}
4562
+ `);
4563
+ process.stdout.write(`\uC791\uC131\uC790: ${comment.creator.member.name}
4564
+ `);
4565
+ process.stdout.write(`\uC0DD\uC131\uC77C: ${comment.createdAt}
4566
+ `);
4567
+ if (comment.modifiedAt && comment.modifiedAt !== comment.createdAt) {
4568
+ process.stdout.write(`\uC218\uC815\uC77C: ${comment.modifiedAt}
4569
+ `);
4570
+ }
4571
+ process.stdout.write(`
4572
+ ${comment.body.content}
4573
+ `);
4574
+ }
4575
+ function truncate(s, n) {
4576
+ const oneLine = s.replace(/\s+/g, " ").trim();
4577
+ return oneLine.length <= n ? oneLine : oneLine.slice(0, n - 1) + "\u2026";
4578
+ }
4579
+
4580
+ // src/commands/wiki/page-comment/list.ts
4581
+ var wikiPageCommentListCommand = new import_commander45.Command("list").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uBAA9\uB85D \uC870\uD68C (\uCD5C\uC2E0\uC21C)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray Wiki URL)").argument("[page-id]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (--project \uB3D9\uBC18)").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").option("--size <n>", "\uD398\uC774\uC9C0 \uD06C\uAE30 (\uAE30\uBCF8 20, \uCD5C\uB300 100)", (v) => parseInt(v, 10)).option("--page <n>", "\uD398\uC774\uC9C0 \uBC88\uD638 (0\uBD80\uD130)", (v) => parseInt(v, 10)).option("--latest <n>", "\uCD5C\uC2E0 N\uAC1C\uB9CC (size \uB300\uC2E0 \uC0AC\uC6A9)", (v) => parseInt(v, 10)).action(async (project, pageIdArg, opts) => {
4582
+ const globalOpts = wikiPageCommentListCommand.optsWithGlobals();
4583
+ const config = await getConfigOrThrow();
4584
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4585
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4586
+ projectArg: project,
4587
+ pageIdArg,
4588
+ idOpt: opts.id,
4589
+ urlOpt: opts.url,
4590
+ project: opts.project
4591
+ });
4592
+ const size = opts.latest ?? opts.size ?? 20;
4593
+ const page = opts.page ?? 0;
4594
+ startSpinner("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC911...");
4595
+ try {
4596
+ const res = await client.getWikiPageComments(wikiId, pageId, { size, page });
4597
+ stopSpinner(true, `\uB313\uAE00 ${res.result.length}\uAC74 (\uCD1D ${res.totalCount})`);
4598
+ formatWikiCommentList(res.result, { globalOpts, totalCount: res.totalCount });
4599
+ } catch (e) {
4600
+ stopSpinner(false);
4601
+ throw e;
4602
+ }
4603
+ });
4604
+
4605
+ // src/commands/wiki/page-comment/latest.ts
4606
+ var import_commander46 = require("commander");
4607
+ var wikiPageCommentLatestCommand = new import_commander46.Command("latest").description("\uCD5C\uC2E0 \uB313\uAE00 1\uAC74 \uC870\uD68C (= comment list --latest 1)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray Wiki URL)").argument("[page-id]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (--project \uB3D9\uBC18)").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").action(async (project, pageIdArg, opts) => {
4608
+ const globalOpts = wikiPageCommentLatestCommand.optsWithGlobals();
4609
+ const config = await getConfigOrThrow();
4610
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4611
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4612
+ projectArg: project,
4613
+ pageIdArg,
4614
+ idOpt: opts.id,
4615
+ urlOpt: opts.url,
4616
+ project: opts.project
4617
+ });
4618
+ startSpinner("\uCD5C\uC2E0 \uB313\uAE00 \uC870\uD68C \uC911...");
4619
+ try {
4620
+ const res = await client.getWikiPageComments(wikiId, pageId, { size: 1, page: 0 });
4621
+ stopSpinner(true, res.result.length > 0 ? "\uCD5C\uC2E0 \uB313\uAE00" : "\uB313\uAE00 \uC5C6\uC74C");
4622
+ if (res.result.length === 0) {
4623
+ process.stdout.write("\uB313\uAE00\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
4624
+ return;
4625
+ }
4626
+ formatWikiCommentDetail(res.result[0], globalOpts);
4627
+ } catch (e) {
4628
+ stopSpinner(false);
4629
+ throw e;
4630
+ }
4631
+ });
4632
+
4633
+ // src/commands/wiki/page-comment/get.ts
4634
+ var import_commander47 = require("commander");
4635
+
4636
+ // src/commands/wiki/page-comment/parse-args.ts
4637
+ function parseWikiCommentArgs(arg1, arg2, arg3, opts) {
4638
+ const hasPositional = arg1 !== void 0 || arg2 !== void 0 || arg3 !== void 0;
4639
+ const hasIdUrl = !!(opts.id || opts.url);
4640
+ if (hasPositional && hasIdUrl) {
4641
+ throw new DoorayCliError(
4642
+ "positional \uC778\uC790\uC640 --id/--url \uC635\uC158\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
4643
+ EXIT_PARAM_ERROR
4644
+ );
4645
+ }
4646
+ if (hasIdUrl) {
4647
+ if (!opts.commentId) {
4648
+ throw new DoorayCliError(
4649
+ "--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 --comment-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
4650
+ EXIT_PARAM_ERROR
4651
+ );
4652
+ }
4653
+ return {
4654
+ commentId: opts.commentId,
4655
+ idOpt: opts.id,
4656
+ urlOpt: opts.url,
4657
+ projectOpt: opts.project
4658
+ };
4659
+ }
4660
+ if (arg3) {
4661
+ if (opts.commentId) {
4662
+ throw new DoorayCliError(
4663
+ "positional \uB313\uAE00 ID \uC640 --comment-id \uC635\uC158\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
4664
+ EXIT_PARAM_ERROR
4665
+ );
4666
+ }
4667
+ return {
4668
+ projectArg: arg1,
4669
+ pageIdArg: arg2,
4670
+ commentId: arg3
4671
+ };
4672
+ }
4673
+ if (arg1 && arg2 && opts.commentId) {
4674
+ return {
4675
+ projectArg: arg1,
4676
+ pageIdArg: arg2,
4677
+ commentId: opts.commentId
4678
+ };
4679
+ }
4680
+ throw new DoorayCliError(
4681
+ "<comment-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --comment-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
4682
+ EXIT_PARAM_ERROR
4683
+ );
4684
+ }
4685
+
4686
+ // src/commands/wiki/page-comment/get.ts
4687
+ var wikiPageCommentGetCommand = new import_commander47.Command("get").description("\uB2E8\uC77C \uB313\uAE00 \uC870\uD68C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray Wiki URL (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (positional \uB300\uC2E0)").option("--url <url>", "Dooray Wiki URL (positional \uB300\uC2E0)").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").option("--comment-id <id>", "\uB313\uAE00 ID (arg3 \uB300\uC2E0)").action(async (arg1, arg2, arg3, opts) => {
4688
+ const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4689
+ const config = await getConfigOrThrow();
4690
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4691
+ const globalOpts = wikiPageCommentGetCommand.optsWithGlobals();
4692
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4693
+ projectArg: parsed.projectArg,
4694
+ pageIdArg: parsed.pageIdArg,
4695
+ idOpt: parsed.idOpt,
4696
+ urlOpt: parsed.urlOpt,
4697
+ project: parsed.projectOpt
4698
+ });
4699
+ startSpinner("\uB313\uAE00 \uC870\uD68C \uC911...");
4700
+ try {
4701
+ const detail = await client.getWikiPageComment(wikiId, pageId, parsed.commentId);
4702
+ stopSpinner(true, "\uB313\uAE00 \uC870\uD68C \uC644\uB8CC");
4703
+ formatWikiCommentDetail(detail.result, globalOpts);
4704
+ } catch (e) {
4705
+ stopSpinner(false);
4706
+ throw e;
4707
+ }
4708
+ });
4709
+
4710
+ // src/commands/wiki/page-comment/add.ts
4711
+ var import_commander48 = require("commander");
4712
+ var wikiPageCommentAddCommand = new import_commander48.Command("add").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uCD94\uAC00 (--body \uC5C6\uC73C\uBA74 $EDITOR)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray Wiki URL)").argument("[page-id]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (--project \uB3D9\uBC18)").option("--url <url>", "Dooray Wiki URL").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").option("--body <text>", "\uB313\uAE00 \uBCF8\uBB38 (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin\uC5D0\uC11C \uC77D\uAE30)").action(async (project, pageIdArg, opts) => {
4713
+ if ((opts.id || opts.url) && (project || pageIdArg)) {
4714
+ throw new DoorayCliError(
4715
+ "positional \uC778\uC790\uC640 --id/--url \uC635\uC158\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
4716
+ EXIT_PARAM_ERROR
4717
+ );
4718
+ }
4719
+ const globalOpts = wikiPageCommentAddCommand.optsWithGlobals();
4720
+ const config = await getConfigOrThrow();
4721
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4722
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4723
+ projectArg: project,
4724
+ pageIdArg,
4725
+ idOpt: opts.id,
4726
+ urlOpt: opts.url,
4727
+ project: opts.project
4728
+ });
4729
+ let bodyContent = await readBodyInputOrNull(opts);
4730
+ if (bodyContent == null) {
4731
+ bodyContent = await openInEditor("");
4732
+ if (!bodyContent.trim()) {
4733
+ process.stdout.write("\uBE48 \uB313\uAE00\uC740 \uC791\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
4734
+ return;
4735
+ }
4736
+ }
4737
+ startSpinner("\uB313\uAE00 \uCD94\uAC00 \uC911...");
4738
+ try {
4739
+ const res = await client.addWikiPageComment(wikiId, pageId, {
4740
+ body: { content: bodyContent }
4741
+ });
4742
+ stopSpinner(true, `\uB313\uAE00 \uCD94\uAC00 \uC644\uB8CC (id: ${res.result.id})`);
4743
+ if (globalOpts.json) {
4744
+ printJson({ id: res.result.id });
4745
+ } else if (globalOpts.quiet) {
4746
+ printQuiet([res.result.id]);
4747
+ } else {
4748
+ process.stdout.write(`\uB313\uAE00\uC774 \uCD94\uAC00\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${res.result.id}
4749
+ `);
4750
+ }
4751
+ } catch (e) {
4752
+ stopSpinner(false);
4753
+ throw e;
4754
+ }
4755
+ });
4756
+
4757
+ // src/commands/wiki/page-comment/edit.ts
4758
+ var import_commander49 = require("commander");
4759
+ var wikiPageCommentEditCommand = new import_commander49.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uC218\uC815 ($EDITOR \uB610\uB294 --body \uC635\uC158)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray Wiki URL (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (positional \uB300\uC2E0)").option("--url <url>", "Dooray Wiki URL (positional \uB300\uC2E0)").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").option("--comment-id <commentId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--body <text>", "\uB313\uAE00 \uBCF8\uBB38 \uBCC0\uACBD (- \uC785\uB825 \uC2DC stdin, non-interactive)").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C (- \uC785\uB825 \uC2DC stdin, non-interactive)").action(async (arg1, arg2, arg3, opts) => {
4760
+ const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4761
+ const config = await getConfigOrThrow();
4762
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4763
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4764
+ projectArg: parsed.projectArg,
4765
+ pageIdArg: parsed.pageIdArg,
4766
+ idOpt: parsed.idOpt,
4767
+ urlOpt: parsed.urlOpt,
4768
+ project: parsed.projectOpt
4769
+ });
4770
+ startSpinner("\uB313\uAE00 \uC870\uD68C \uC911...");
4771
+ let existing;
4772
+ try {
4773
+ const detail = await client.getWikiPageComment(wikiId, pageId, parsed.commentId);
4774
+ existing = detail.result;
4775
+ stopSpinner(true, "\uB313\uAE00 \uC870\uD68C \uC644\uB8CC");
4776
+ } catch (e) {
4777
+ stopSpinner(false);
4778
+ throw e;
4779
+ }
4780
+ let newBody = await readBodyInputOrNull(opts);
4781
+ if (newBody == null) {
4782
+ newBody = await openInEditor(existing.body.content);
4783
+ if (!newBody.trim() || newBody === existing.body.content) {
4784
+ process.stdout.write("\uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
4785
+ return;
4786
+ }
4787
+ }
4788
+ startSpinner("\uB313\uAE00 \uC218\uC815 \uC911...");
4789
+ try {
4790
+ await client.updateWikiPageComment(wikiId, pageId, parsed.commentId, {
4791
+ body: { content: newBody }
4792
+ });
4793
+ stopSpinner(true, "\uB313\uAE00 \uC218\uC815 \uC644\uB8CC");
4794
+ process.stdout.write(`\uB313\uAE00\uC774 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${parsed.commentId}
4795
+ `);
4796
+ } catch (e) {
4797
+ stopSpinner(false);
4798
+ throw e;
4799
+ }
4800
+ });
4801
+
4802
+ // src/commands/wiki/page-comment/delete.ts
4803
+ var import_commander50 = require("commander");
4804
+ var wikiPageCommentDeleteCommand = new import_commander50.Command("delete").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uC0AD\uC81C (confirm \uC5C6\uC774 \uC989\uC2DC)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray Wiki URL (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <pageId>", "\uC704\uD0A4 \uD398\uC774\uC9C0 ID (positional \uB300\uC2E0)").option("--url <url>", "Dooray Wiki URL (positional \uB300\uC2E0)").option("--project <code>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (--id \uBAA8\uB4DC\uC6A9)").option("--comment-id <commentId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
4805
+ const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4806
+ const config = await getConfigOrThrow();
4807
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4808
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4809
+ projectArg: parsed.projectArg,
4810
+ pageIdArg: parsed.pageIdArg,
4811
+ idOpt: parsed.idOpt,
4812
+ urlOpt: parsed.urlOpt,
4813
+ project: parsed.projectOpt
4814
+ });
4815
+ startSpinner("\uB313\uAE00 \uC0AD\uC81C \uC911...");
4816
+ try {
4817
+ await client.deleteWikiPageComment(wikiId, pageId, parsed.commentId);
4818
+ stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
4819
+ process.stdout.write(`\uB313\uAE00(${parsed.commentId})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
4820
+ `);
4821
+ } catch (e) {
4822
+ stopSpinner(false);
4823
+ throw e;
4824
+ }
4825
+ });
4826
+
4827
+ // src/commands/wiki/page-comment/index.ts
4828
+ var wikiPageCommentCommand = new import_commander51.Command("comment").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
4829
+ wikiPageCommentCommand.addCommand(wikiPageCommentListCommand);
4830
+ wikiPageCommentCommand.addCommand(wikiPageCommentLatestCommand);
4831
+ wikiPageCommentCommand.addCommand(wikiPageCommentGetCommand);
4832
+ wikiPageCommentCommand.addCommand(wikiPageCommentAddCommand);
4833
+ wikiPageCommentCommand.addCommand(wikiPageCommentEditCommand);
4834
+ wikiPageCommentCommand.addCommand(wikiPageCommentDeleteCommand);
4835
+
4836
+ // src/commands/member/index.ts
4837
+ var import_commander55 = require("commander");
4838
+
4839
+ // src/commands/member/get.ts
4840
+ var import_commander52 = require("commander");
4841
+
4842
+ // src/formatters/member.ts
4843
+ function formatMemberDetail(member, opts) {
4844
+ if (opts.json) {
4845
+ printJson(member);
4846
+ return;
4847
+ }
4848
+ if (opts.quiet) {
4849
+ process.stdout.write(member.id + "\n");
4850
+ return;
4851
+ }
4852
+ const lines = [
4853
+ `\uC774\uB984: ${member.name}`,
4854
+ ...member.englishName ? [`\uC601\uBB38\uBA85: ${member.englishName}`] : [],
4855
+ ...member.nickname ? [`\uBCC4\uBA85: ${member.nickname}`] : [],
4856
+ ...member.userCode ? [`\uC0AC\uBC88/ID: ${member.userCode}`] : [],
4857
+ ...member.externalEmailAddress ? [`\uC678\uBD80 \uC774\uBA54\uC77C: ${member.externalEmailAddress}`] : [],
4858
+ `member-id: ${member.id}`
4859
+ ];
4860
+ process.stdout.write(lines.join("\n") + "\n");
4861
+ }
4862
+ function formatMemberList(rows, opts) {
4863
+ output(opts, {
4864
+ headers: ["ID", "Name", "Role"],
4865
+ rows: rows.map((r) => [r.id, r.name, r.role ?? ""]),
4866
+ raw: rows,
4867
+ ids: rows.map((r) => r.id)
4868
+ });
4869
+ }
4870
+ function formatMemberSearchResults(members, opts) {
4871
+ output(opts, {
4872
+ headers: ["ID", "Name", "UserCode", "Nickname", "Email"],
4873
+ rows: members.map((m) => [
4874
+ m.id,
4875
+ m.name,
4876
+ m.userCode ?? "",
4877
+ m.nickname ?? "",
4878
+ m.externalEmailAddress ?? ""
4879
+ ]),
4880
+ raw: members,
4881
+ ids: members.map((m) => m.id)
4882
+ });
4883
+ }
4884
+
4885
+ // src/commands/member/get.ts
4886
+ var memberGetCommand = new import_commander52.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
4887
+ const globalOpts = memberGetCommand.optsWithGlobals();
4888
+ const config = await getConfigOrThrow();
4889
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4890
+ const res = await client.getMemberDetail(memberId);
4891
+ formatMemberDetail(res.result, globalOpts);
4892
+ });
4893
+
4894
+ // src/commands/member/list.ts
4895
+ var import_commander53 = require("commander");
4896
+ var memberListCommand = new import_commander53.Command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBA64\uBC84 \uBAA9\uB85D").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
4897
+ const globalOpts = memberListCommand.optsWithGlobals();
4898
+ const config = await getConfigOrThrow();
4899
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4900
+ startSpinner("\uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C \uC911...");
4901
+ const projectId = await resolveProject(client, project);
4902
+ const members = await ensureMembers(client, projectId);
4903
+ stopSpinner(true, `${members.length}\uBA85`);
4904
+ formatMemberList(
4905
+ members.map((m) => ({ id: m.organizationMemberId, name: m.name })),
4906
+ globalOpts
4907
+ );
4908
+ });
4909
+
4910
+ // src/commands/member/search.ts
4911
+ var import_commander54 = require("commander");
4912
+ var memberSearchCommand = new import_commander54.Command("search").description("organization \uC804\uCCB4\uC5D0\uC11C \uBA64\uBC84 \uAC80\uC0C9").argument("[keyword]", "\uC774\uB984 \uAC80\uC0C9\uC5B4 (--email/--user-code \uBBF8\uC9C0\uC815 \uC2DC name\uC73C\uB85C \uAC80\uC0C9)").option("--email <email>", "\uC678\uBD80 \uC774\uBA54\uC77C (\uCF64\uB9C8 \uAD6C\uBD84 \uAC00\uB2A5, exact match)").option("--user-code <code>", "\uC0AC\uBC88 like \uAC80\uC0C9").option("--user-code-exact <code>", "\uC0AC\uBC88 exact match").option("--page <n>", "\uD398\uC774\uC9C0 (\uAE30\uBCF8 0)", "0").option("--size <n>", "\uD398\uC774\uC9C0 \uD06C\uAE30 (\uAE30\uBCF8 20, max 100)", "20").action(async (keyword, opts) => {
4913
+ const globalOpts = memberSearchCommand.optsWithGlobals();
4914
+ const filterCount = [keyword, opts.email, opts.userCode, opts.userCodeExact].filter(Boolean).length;
4915
+ if (filterCount === 0) {
4916
+ throw new DoorayCliError(
4917
+ "\uAC80\uC0C9 \uC870\uAC74\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. positional <keyword>(=name) \uB610\uB294 --email/--user-code/--user-code-exact \uC911 \uD558\uB098 \uC774\uC0C1.",
4918
+ EXIT_PARAM_ERROR
4919
+ );
4920
+ }
4921
+ if (keyword && (opts.email || opts.userCode || opts.userCodeExact)) {
4922
+ throw new DoorayCliError(
4923
+ "positional <keyword>(name)\uC640 --email/--user-code/--user-code-exact \uC635\uC158\uC740 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00.",
4924
+ EXIT_PARAM_ERROR
4925
+ );
4926
+ }
4927
+ const config = await getConfigOrThrow();
4928
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4929
+ const size = Math.min(Math.max(1, Number(opts.size) || 20), 100);
4930
+ const page = Math.max(0, Number(opts.page) || 0);
4931
+ startSpinner("\uBA64\uBC84 \uAC80\uC0C9 \uC911...");
4133
4932
  const res = await client.searchMembers({
4134
4933
  ...keyword && { name: keyword },
4135
4934
  ...opts.email && { externalEmailAddresses: opts.email },
@@ -4143,13 +4942,13 @@ var memberSearchCommand = new import_commander41.Command("search").description("
4143
4942
  });
4144
4943
 
4145
4944
  // src/commands/member/index.ts
4146
- var memberCommand = new import_commander42.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
4945
+ var memberCommand = new import_commander55.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
4147
4946
  memberCommand.addCommand(memberGetCommand);
4148
4947
  memberCommand.addCommand(memberListCommand);
4149
4948
  memberCommand.addCommand(memberSearchCommand);
4150
4949
 
4151
4950
  // src/commands/mail/list.ts
4152
- var import_commander43 = require("commander");
4951
+ var import_commander56 = require("commander");
4153
4952
 
4154
4953
  // src/api/imapClient.ts
4155
4954
  var import_imapflow = require("imapflow");
@@ -4266,7 +5065,7 @@ async function getMail(config, uid) {
4266
5065
 
4267
5066
  // src/commands/mail/list.ts
4268
5067
  var import_chalk5 = __toESM(require("chalk"));
4269
- var mailListCommand = new import_commander43.Command("list").description("\uBA54\uC77C \uBAA9\uB85D \uC870\uD68C").option("--unread", "\uC548\uC77D\uC740 \uBA54\uC77C\uB9CC").option("--search <keyword>", "\uC81C\uBAA9 \uAC80\uC0C9").option("--size <number>", "\uC870\uD68C \uAC1C\uC218", "20").action(async (opts) => {
5068
+ var mailListCommand = new import_commander56.Command("list").description("\uBA54\uC77C \uBAA9\uB85D \uC870\uD68C").option("--unread", "\uC548\uC77D\uC740 \uBA54\uC77C\uB9CC").option("--search <keyword>", "\uC81C\uBAA9 \uAC80\uC0C9").option("--size <number>", "\uC870\uD68C \uAC1C\uC218", "20").action(async (opts) => {
4270
5069
  const globalOpts = mailListCommand.optsWithGlobals();
4271
5070
  const config = await getConfigOrThrow();
4272
5071
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -4298,9 +5097,9 @@ var mailListCommand = new import_commander43.Command("list").description("\uBA54
4298
5097
  });
4299
5098
 
4300
5099
  // src/commands/mail/get.ts
4301
- var import_commander44 = require("commander");
5100
+ var import_commander57 = require("commander");
4302
5101
  var import_chalk6 = __toESM(require("chalk"));
4303
- var mailGetCommand = new import_commander44.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
5102
+ var mailGetCommand = new import_commander57.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
4304
5103
  const globalOpts = mailGetCommand.optsWithGlobals();
4305
5104
  const config = await getConfigOrThrow();
4306
5105
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -4331,8 +5130,8 @@ ${mail.body}
4331
5130
  });
4332
5131
 
4333
5132
  // src/commands/mail/send.ts
4334
- var import_commander45 = require("commander");
4335
- var import_promises11 = require("fs/promises");
5133
+ var import_commander58 = require("commander");
5134
+ var import_promises13 = require("fs/promises");
4336
5135
 
4337
5136
  // src/api/smtpClient.ts
4338
5137
  var import_nodemailer = __toESM(require("nodemailer"));
@@ -4381,12 +5180,12 @@ async function sendMail(config, opts) {
4381
5180
  }
4382
5181
 
4383
5182
  // src/commands/mail/send.ts
4384
- var mailSendCommand = new import_commander45.Command("send").description("\uBA54\uC77C \uBC1C\uC1A1").requiredOption("--to <addresses...>", "\uBC1B\uB294\uC0AC\uB78C \uC774\uBA54\uC77C (\uBCF5\uC218 \uAC00\uB2A5)").requiredOption("--subject <title>", "\uC81C\uBAA9").option("--body <text>", "\uBCF8\uBB38").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option("--cc <addresses...>", "\uCC38\uC870").option("--bcc <addresses...>", "\uC228\uC740\uCC38\uC870").option("--html", "\uBCF8\uBB38\uC744 HTML\uB85C \uC804\uC1A1").action(async (opts) => {
5183
+ var mailSendCommand = new import_commander58.Command("send").description("\uBA54\uC77C \uBC1C\uC1A1").requiredOption("--to <addresses...>", "\uBC1B\uB294\uC0AC\uB78C \uC774\uBA54\uC77C (\uBCF5\uC218 \uAC00\uB2A5)").requiredOption("--subject <title>", "\uC81C\uBAA9").option("--body <text>", "\uBCF8\uBB38").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option("--cc <addresses...>", "\uCC38\uC870").option("--bcc <addresses...>", "\uC228\uC740\uCC38\uC870").option("--html", "\uBCF8\uBB38\uC744 HTML\uB85C \uC804\uC1A1").action(async (opts) => {
4385
5184
  const globalOpts = mailSendCommand.optsWithGlobals();
4386
5185
  const config = await getConfigOrThrow();
4387
5186
  let body = opts.body ?? "";
4388
5187
  if (opts.bodyFile) {
4389
- body = await (0, import_promises11.readFile)(opts.bodyFile, "utf-8");
5188
+ body = await (0, import_promises13.readFile)(opts.bodyFile, "utf-8");
4390
5189
  }
4391
5190
  if (!body) {
4392
5191
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -4416,8 +5215,8 @@ var mailSendCommand = new import_commander45.Command("send").description("\uBA54
4416
5215
  });
4417
5216
 
4418
5217
  // src/commands/mail/reply.ts
4419
- var import_commander46 = require("commander");
4420
- var import_promises12 = require("fs/promises");
5218
+ var import_commander59 = require("commander");
5219
+ var import_promises14 = require("fs/promises");
4421
5220
  var import_imapflow2 = require("imapflow");
4422
5221
  async function getMessageId(config, uid) {
4423
5222
  const imap = getImapConfigOrThrow(config);
@@ -4445,12 +5244,12 @@ async function getMessageId(config, uid) {
4445
5244
  await client.logout();
4446
5245
  }
4447
5246
  }
4448
- var mailReplyCommand = new import_commander46.Command("reply").description("\uBA54\uC77C \uB2F5\uC7A5").argument("<uid>", "\uC6D0\uBCF8 \uBA54\uC77C UID").option("--body <text>", "\uB2F5\uC7A5 \uBCF8\uBB38").option("--body-file <path>", "\uB2F5\uC7A5 \uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option("--cc <addresses...>", "\uCC38\uC870").option("--html", "\uBCF8\uBB38\uC744 HTML\uB85C \uC804\uC1A1").action(async (uid, opts) => {
5247
+ var mailReplyCommand = new import_commander59.Command("reply").description("\uBA54\uC77C \uB2F5\uC7A5").argument("<uid>", "\uC6D0\uBCF8 \uBA54\uC77C UID").option("--body <text>", "\uB2F5\uC7A5 \uBCF8\uBB38").option("--body-file <path>", "\uB2F5\uC7A5 \uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option("--cc <addresses...>", "\uCC38\uC870").option("--html", "\uBCF8\uBB38\uC744 HTML\uB85C \uC804\uC1A1").action(async (uid, opts) => {
4449
5248
  const globalOpts = mailReplyCommand.optsWithGlobals();
4450
5249
  const config = await getConfigOrThrow();
4451
5250
  let body = opts.body ?? "";
4452
5251
  if (opts.bodyFile) {
4453
- body = await (0, import_promises12.readFile)(opts.bodyFile, "utf-8");
5252
+ body = await (0, import_promises14.readFile)(opts.bodyFile, "utf-8");
4454
5253
  }
4455
5254
  if (!body) {
4456
5255
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -4486,29 +5285,29 @@ var mailReplyCommand = new import_commander46.Command("reply").description("\uBA
4486
5285
  });
4487
5286
 
4488
5287
  // src/commands/feedback.ts
4489
- var import_commander47 = require("commander");
5288
+ var import_commander60 = require("commander");
4490
5289
  var import_node_child_process2 = require("child_process");
4491
5290
  var import_node_util = require("util");
4492
- var import_promises15 = require("fs/promises");
5291
+ var import_promises17 = require("fs/promises");
4493
5292
  var import_node_os4 = require("os");
4494
- var import_node_path11 = require("path");
5293
+ var import_node_path13 = require("path");
4495
5294
  var import_node_crypto = require("crypto");
4496
5295
  var import_prompts = require("@inquirer/prompts");
4497
5296
 
4498
5297
  // src/utils/feedback-meta.ts
4499
- var import_promises13 = require("fs/promises");
4500
- var import_node_path9 = require("path");
5298
+ var import_promises15 = require("fs/promises");
5299
+ var import_node_path11 = require("path");
4501
5300
  async function readCliVersion() {
4502
5301
  const entry = process.argv[1];
4503
- const here = entry ? (0, import_node_path9.dirname)(entry) : process.cwd();
5302
+ const here = entry ? (0, import_node_path11.dirname)(entry) : process.cwd();
4504
5303
  const candidates = [
4505
- (0, import_node_path9.join)(here, "package.json"),
4506
- (0, import_node_path9.join)(here, "..", "package.json"),
4507
- (0, import_node_path9.join)(here, "..", "..", "package.json")
5304
+ (0, import_node_path11.join)(here, "package.json"),
5305
+ (0, import_node_path11.join)(here, "..", "package.json"),
5306
+ (0, import_node_path11.join)(here, "..", "..", "package.json")
4508
5307
  ];
4509
5308
  for (const p of candidates) {
4510
5309
  try {
4511
- const raw = await (0, import_promises13.readFile)(p, "utf-8");
5310
+ const raw = await (0, import_promises15.readFile)(p, "utf-8");
4512
5311
  const pkg = JSON.parse(raw);
4513
5312
  if (pkg.name === "@bifos/dooray-cli" && typeof pkg.version === "string") {
4514
5313
  return pkg.version;
@@ -4554,10 +5353,10 @@ function buildIssueBody(userBody, meta) {
4554
5353
  }
4555
5354
 
4556
5355
  // src/cache/last-run.ts
4557
- var import_promises14 = require("fs/promises");
4558
- var import_node_path10 = require("path");
5356
+ var import_promises16 = require("fs/promises");
5357
+ var import_node_path12 = require("path");
4559
5358
  var import_node_os3 = require("os");
4560
- var LAST_RUN_PATH = (0, import_node_path10.join)((0, import_node_os3.homedir)(), ".dooray", "last-run.json");
5359
+ var LAST_RUN_PATH = (0, import_node_path12.join)((0, import_node_os3.homedir)(), ".dooray", "last-run.json");
4561
5360
  function isLastRun(obj) {
4562
5361
  if (typeof obj !== "object" || obj === null) return false;
4563
5362
  const o = obj;
@@ -4565,7 +5364,7 @@ function isLastRun(obj) {
4565
5364
  }
4566
5365
  async function readLastRun() {
4567
5366
  try {
4568
- const raw = await (0, import_promises14.readFile)(LAST_RUN_PATH, "utf-8");
5367
+ const raw = await (0, import_promises16.readFile)(LAST_RUN_PATH, "utf-8");
4569
5368
  const parsed = JSON.parse(raw);
4570
5369
  return isLastRun(parsed) ? parsed : null;
4571
5370
  } catch {
@@ -4573,10 +5372,10 @@ async function readLastRun() {
4573
5372
  }
4574
5373
  }
4575
5374
  async function writeLastRun(data) {
4576
- await (0, import_promises14.mkdir)((0, import_node_path10.join)((0, import_node_os3.homedir)(), ".dooray"), { recursive: true });
5375
+ await (0, import_promises16.mkdir)((0, import_node_path12.join)((0, import_node_os3.homedir)(), ".dooray"), { recursive: true });
4577
5376
  const tmp2 = LAST_RUN_PATH + ".tmp";
4578
- await (0, import_promises14.writeFile)(tmp2, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
4579
- await (0, import_promises14.rename)(tmp2, LAST_RUN_PATH);
5377
+ await (0, import_promises16.writeFile)(tmp2, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
5378
+ await (0, import_promises16.rename)(tmp2, LAST_RUN_PATH);
4580
5379
  }
4581
5380
 
4582
5381
  // src/commands/feedback.ts
@@ -4594,10 +5393,10 @@ async function ensureGhInstalled() {
4594
5393
  }
4595
5394
  async function readBody(opts) {
4596
5395
  if (opts.body) return opts.body;
4597
- if (opts.bodyFile) return await (0, import_promises15.readFile)(opts.bodyFile, "utf-8");
5396
+ if (opts.bodyFile) return await (0, import_promises17.readFile)(opts.bodyFile, "utf-8");
4598
5397
  return void 0;
4599
5398
  }
4600
- var feedbackCommand = new import_commander47.Command("feedback").description("dooray-cli\uC5D0 \uB300\uD55C GitHub issue \uB4F1\uB85D (gh CLI \uC704\uC784)").option("--title <text>", "\uC774\uC288 \uC81C\uBAA9 (\uC5C6\uC73C\uBA74 \uC778\uD130\uB799\uD2F0\uBE0C)").option("--body <text>", "\uC774\uC288 \uBCF8\uBB38").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option(
5399
+ var feedbackCommand = new import_commander60.Command("feedback").description("dooray-cli\uC5D0 \uB300\uD55C GitHub issue \uB4F1\uB85D (gh CLI \uC704\uC784)").option("--title <text>", "\uC774\uC288 \uC81C\uBAA9 (\uC5C6\uC73C\uBA74 \uC778\uD130\uB799\uD2F0\uBE0C)").option("--body <text>", "\uC774\uC288 \uBCF8\uBB38").option("--body-file <path>", "\uBCF8\uBB38 \uD30C\uC77C \uACBD\uB85C").option(
4601
5400
  "--label <name>",
4602
5401
  "\uB77C\uBCA8 (\uBC18\uBCF5 \uAC00\uB2A5)",
4603
5402
  (value, prev) => [...prev, value],
@@ -4688,8 +5487,8 @@ var feedbackCommand = new import_commander47.Command("feedback").description("do
4688
5487
  }
4689
5488
  }
4690
5489
  await ensureGhInstalled();
4691
- const bodyFile = (0, import_node_path11.join)((0, import_node_os4.tmpdir)(), `dooray-feedback-${(0, import_node_crypto.randomUUID)()}.md`);
4692
- await (0, import_promises15.writeFile)(bodyFile, issueBody);
5490
+ const bodyFile = (0, import_node_path13.join)((0, import_node_os4.tmpdir)(), `dooray-feedback-${(0, import_node_crypto.randomUUID)()}.md`);
5491
+ await (0, import_promises17.writeFile)(bodyFile, issueBody);
4693
5492
  try {
4694
5493
  const args = [
4695
5494
  "issue",
@@ -4716,7 +5515,7 @@ gh \uC778\uC99D \uC548 \uB418\uC5B4 \uC788\uC73C\uBA74: gh auth login`,
4716
5515
  EXIT_PARAM_ERROR
4717
5516
  );
4718
5517
  } finally {
4719
- await (0, import_promises15.unlink)(bodyFile).catch(() => {
5518
+ await (0, import_promises17.unlink)(bodyFile).catch(() => {
4720
5519
  });
4721
5520
  }
4722
5521
  });
@@ -4760,8 +5559,8 @@ function sanitizeArgv(argv) {
4760
5559
  }
4761
5560
 
4762
5561
  // src/index.ts
4763
- var program = new import_commander48.Command();
4764
- program.name("dooray").description("Dooray REST API CLI").version("0.9.0").option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "ID\uB9CC \uCD9C\uB825").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654");
5562
+ var program = new import_commander61.Command();
5563
+ program.name("dooray").description("Dooray REST API CLI").version("0.10.0").option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "ID\uB9CC \uCD9C\uB825").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654");
4765
5564
  program.hook("preAction", () => {
4766
5565
  const opts = program.opts();
4767
5566
  if (opts.color === false || process.env.NO_COLOR) {
@@ -4771,14 +5570,14 @@ program.hook("preAction", () => {
4771
5570
  setQuiet(true);
4772
5571
  }
4773
5572
  });
4774
- var projectCommand = new import_commander48.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
5573
+ var projectCommand = new import_commander61.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
4775
5574
  projectCommand.addCommand(projectListCommand);
4776
5575
  projectCommand.addCommand(projectMembersCommand);
4777
5576
  projectCommand.addCommand(projectWorkflowsCommand);
4778
5577
  projectCommand.addCommand(projectGroupsCommand);
4779
5578
  projectCommand.addCommand(projectTagsCommand);
4780
5579
  projectCommand.addCommand(projectTemplatesCommand);
4781
- var postCommand = new import_commander48.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
5580
+ var postCommand = new import_commander61.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
4782
5581
  postCommand.addCommand(postListCommand);
4783
5582
  postCommand.addCommand(postSearchCommand);
4784
5583
  postCommand.addCommand(postGetCommand);
@@ -4786,7 +5585,7 @@ postCommand.addCommand(postEditCommand);
4786
5585
  postCommand.addCommand(postCreateCommand);
4787
5586
  postCommand.addCommand(postDoneCommand);
4788
5587
  postCommand.addCommand(postWorkflowCommand);
4789
- var commentCommand = new import_commander48.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
5588
+ var commentCommand = new import_commander61.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
4790
5589
  commentCommand.addCommand(commentListCommand);
4791
5590
  commentCommand.addCommand(commentLatestCommand);
4792
5591
  commentCommand.addCommand(commentGetCommand);
@@ -4795,22 +5594,24 @@ commentCommand.addCommand(commentEditCommand);
4795
5594
  commentCommand.addCommand(commentDeleteCommand);
4796
5595
  commentCommand.addCommand(commentFileCommand);
4797
5596
  postCommand.addCommand(commentCommand);
4798
- var fileCommand = new import_commander48.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
5597
+ var fileCommand = new import_commander61.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
4799
5598
  fileCommand.addCommand(fileListCommand);
4800
5599
  fileCommand.addCommand(fileDownloadCommand);
4801
5600
  fileCommand.addCommand(fileDownloadAllCommand);
4802
5601
  fileCommand.addCommand(fileUploadCommand);
4803
5602
  fileCommand.addCommand(fileDeleteCommand);
4804
5603
  postCommand.addCommand(fileCommand);
4805
- var wikiCommand = new import_commander48.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
5604
+ var wikiCommand = new import_commander61.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
4806
5605
  wikiCommand.addCommand(wikiListCommand);
4807
5606
  wikiCommand.addCommand(wikiPagesCommand);
4808
- var wikiPageCommand = new import_commander48.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
5607
+ var wikiPageCommand = new import_commander61.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
4809
5608
  wikiPageCommand.addCommand(wikiPageGetCommand);
4810
5609
  wikiPageCommand.addCommand(wikiPageCreateCommand);
4811
5610
  wikiPageCommand.addCommand(wikiPageEditCommand);
5611
+ wikiPageCommand.addCommand(wikiPageFileCommand);
5612
+ wikiPageCommand.addCommand(wikiPageCommentCommand);
4812
5613
  wikiCommand.addCommand(wikiPageCommand);
4813
- var mailCommand = new import_commander48.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
5614
+ var mailCommand = new import_commander61.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
4814
5615
  mailCommand.addCommand(mailListCommand);
4815
5616
  mailCommand.addCommand(mailGetCommand);
4816
5617
  mailCommand.addCommand(mailSendCommand);