@bifos/dooray-cli 0.12.0 → 0.13.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/README.md CHANGED
@@ -383,8 +383,12 @@ dooray wiki page create <project> --title "..." [--parent <page-id>] [--body "..
383
383
  dooray wiki page edit <project> <page-id> --title "새 제목" # 제목만 (비대화형)
384
384
  dooray wiki page edit <project> <page-id> --body "..." | --body-file <path> # 본문만 (비대화형)
385
385
  dooray wiki page edit <project> <page-id> # $EDITOR (플래그 없을 때)
386
+ dooray wiki page delete <project> <page-id> # 삭제 (y/N 확인)
387
+ dooray wiki page delete <project> <page-id> --yes # 확인 없이 삭제 (자동화용)
386
388
  ```
387
389
 
390
+ 하위 페이지가 있는 페이지를 삭제하면 하위 페이지는 상위 페이지로 재부착된다 (사라지지 않음).
391
+
388
392
  #### 위키 페이지 첨부파일
389
393
 
390
394
  post 의 `post file` 명령군과 동일 패턴 — `<project> <page-id>` 외에도 `--id`/`--url`/positional URL 지원.
@@ -515,6 +519,28 @@ dooray mail send --to "a@b.com" --subject "HTML 메일" --body "<h1>Hello</h1>"
515
519
  dooray mail reply <uid> --body "답장 내용"
516
520
  ```
517
521
 
522
+ ### 메신저
523
+
524
+ Dooray 메신저로 1:1 다이렉트 메시지 또는 대화방 메시지를 보낼 수 있습니다.
525
+ 전송은 API 토큰 소유자 명의로 나갑니다.
526
+
527
+ ```bash
528
+ # 1:1 다이렉트 메시지 (받는 사람은 organizationMemberId 또는 이메일)
529
+ dooray messenger send --to "user@example.com" --body "배포 완료했습니다."
530
+ dooray messenger send --to <memberId> --body-file ./message.md
531
+
532
+ # 대화방 메시지 (channelId 또는 대화방 이름)
533
+ dooray messenger channel-send --channel "배포 알림방" --body "빌드 성공"
534
+ dooray messenger channel-send --channel <channelId> --body-file - # stdin
535
+
536
+ # --body 없이 실행하면 $EDITOR 로 본문을 작성
537
+ dooray messenger send --to "user@example.com"
538
+ ```
539
+
540
+ - `--to`는 이름 검색을 지원하지 않습니다. organizationMemberId 또는 이메일만 입력하세요.
541
+ - `--channel`은 채널 ID 또는 자신이 속한 대화방 이름(부분일치)으로 지정할 수 있습니다.
542
+ 이름이 겹치는 대화방이 여러 개면 후보 목록이 함께 출력됩니다.
543
+
518
544
  ### 첨부파일
519
545
 
520
546
  업무에 파일을 첨부하거나, 첨부된 파일을 다운로드할 수 있습니다.
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_commander61 = require("commander");
27
+ var import_commander65 = require("commander");
28
28
  var import_chalk7 = __toESM(require("chalk"));
29
29
 
30
30
  // src/commands/config.ts
@@ -61,7 +61,7 @@ var API_ENDPOINTS = {
61
61
  };
62
62
  var DEFAULTS = {
63
63
  baseUrl: "https://api.dooray.com",
64
- tenantName: "nhnent",
64
+ tenantName: "example",
65
65
  imapHost: "imap.dooray.com",
66
66
  imapPort: 993,
67
67
  smtpHost: "smtp.dooray.com",
@@ -218,7 +218,7 @@ async function readJson(path3) {
218
218
  }
219
219
  }
220
220
  async function writeJson(path3, data) {
221
- const dir = path3.substring(0, path3.lastIndexOf("/"));
221
+ const dir = (0, import_node_path2.dirname)(path3);
222
222
  await ensureDir2(dir);
223
223
  await (0, import_promises2.writeFile)(path3, JSON.stringify(data, null, 2) + "\n");
224
224
  }
@@ -413,7 +413,7 @@ var DoorayApiClient = class {
413
413
  this.authHeader = `dooray-api ${apiKey}`;
414
414
  this.baseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
415
415
  this.api = import_ky.default.create({
416
- prefixUrl: baseUrl,
416
+ prefix: baseUrl,
417
417
  headers: {
418
418
  Authorization: this.authHeader
419
419
  }
@@ -710,6 +710,14 @@ var DoorayApiClient = class {
710
710
  throw await toDoorayCliError(e);
711
711
  }
712
712
  }
713
+ // 비공식(미문서화) endpoint — Dooray 공식 API 문서에 없으나 실측 확인 (ADR-032)
714
+ async deleteWikiPage(wikiId, pageId) {
715
+ try {
716
+ return await this.api.delete(`wiki/v1/wikis/${wikiId}/pages/${pageId}`).json();
717
+ } catch (e) {
718
+ throw await toDoorayCliError(e);
719
+ }
720
+ }
713
721
  // ─── Post Files ─────────────────────────────────────
714
722
  async getPostFiles(projectId, postId) {
715
723
  try {
@@ -948,6 +956,32 @@ var DoorayApiClient = class {
948
956
  throw await toDoorayCliError(e);
949
957
  }
950
958
  }
959
+ // ─── Messenger (ADR-033) ────────────────────────────
960
+ async sendDirectMessage(organizationMemberId, text) {
961
+ try {
962
+ return await this.api.post("messenger/v1/channels/direct-send", {
963
+ json: { text, organizationMemberId }
964
+ }).json();
965
+ } catch (e) {
966
+ throw await toDoorayCliError(e);
967
+ }
968
+ }
969
+ async sendChannelMessage(channelId, text) {
970
+ try {
971
+ return await this.api.post(`messenger/v1/channels/${channelId}/logs`, {
972
+ json: { text }
973
+ }).json();
974
+ } catch (e) {
975
+ throw await toDoorayCliError(e);
976
+ }
977
+ }
978
+ async getMessengerChannels() {
979
+ try {
980
+ return await this.api.get("messenger/v1/channels").json();
981
+ } catch (e) {
982
+ throw await toDoorayCliError(e);
983
+ }
984
+ }
951
985
  };
952
986
 
953
987
  // src/cache/types.ts
@@ -1432,7 +1466,7 @@ async function buildMemberNameMap(client, projectId) {
1432
1466
  }
1433
1467
  return map;
1434
1468
  }
1435
- async function resolveMember(client, projectId, input2) {
1469
+ async function resolveMemberByIdOrEmail(client, input2) {
1436
1470
  if (MEMBER_ID_RE.test(input2)) {
1437
1471
  try {
1438
1472
  await client.getMemberDetail(input2);
@@ -1465,6 +1499,11 @@ async function resolveMember(client, projectId, input2) {
1465
1499
  }
1466
1500
  return hits[0].id;
1467
1501
  }
1502
+ return null;
1503
+ }
1504
+ async function resolveMember(client, projectId, input2) {
1505
+ const byIdOrEmail = await resolveMemberByIdOrEmail(client, input2);
1506
+ if (byIdOrEmail !== null) return byIdOrEmail;
1468
1507
  const members = await ensureMembers(client, projectId);
1469
1508
  const match = matchByName(
1470
1509
  members,
@@ -2300,7 +2339,7 @@ async function resolvePostRef(client, ref) {
2300
2339
  var import_node_child_process = require("child_process");
2301
2340
  var import_promises6 = __toESM(require("fs/promises"));
2302
2341
  var import_tmp = __toESM(require("tmp"));
2303
- var import_js_yaml = __toESM(require("js-yaml"));
2342
+ var import_js_yaml = require("js-yaml");
2304
2343
  function openInEditor(content) {
2305
2344
  const editor2 = process.env.EDITOR;
2306
2345
  if (!editor2) {
@@ -2364,8 +2403,8 @@ function serializePostFrontmatter(post, members) {
2364
2403
  return "";
2365
2404
  }).filter(Boolean)
2366
2405
  };
2367
- const yamlStr = import_js_yaml.default.dump(frontmatter, {
2368
- quotingType: '"',
2406
+ const yamlStr = (0, import_js_yaml.dump)(frontmatter, {
2407
+ quoteStyle: "double",
2369
2408
  forceQuotes: false,
2370
2409
  lineWidth: -1
2371
2410
  });
@@ -2381,7 +2420,7 @@ function parsePostFrontmatter(content) {
2381
2420
  EXIT_PARAM_ERROR
2382
2421
  );
2383
2422
  }
2384
- const frontmatter = import_js_yaml.default.load(match[1]);
2423
+ const frontmatter = (0, import_js_yaml.load)(match[1]);
2385
2424
  const body = match[2];
2386
2425
  return {
2387
2426
  subject: frontmatter.subject ?? "",
@@ -2396,8 +2435,8 @@ function serializeWikiFrontmatter(page) {
2396
2435
  const frontmatter = {
2397
2436
  title: page.subject
2398
2437
  };
2399
- const yamlStr = import_js_yaml.default.dump(frontmatter, {
2400
- quotingType: '"',
2438
+ const yamlStr = (0, import_js_yaml.dump)(frontmatter, {
2439
+ quoteStyle: "double",
2401
2440
  forceQuotes: false,
2402
2441
  lineWidth: -1
2403
2442
  });
@@ -2413,7 +2452,7 @@ function parseWikiFrontmatter(content) {
2413
2452
  EXIT_PARAM_ERROR
2414
2453
  );
2415
2454
  }
2416
- const frontmatter = import_js_yaml.default.load(match[1]);
2455
+ const frontmatter = (0, import_js_yaml.load)(match[1]);
2417
2456
  const body = match[2];
2418
2457
  return {
2419
2458
  title: frontmatter.title ?? "",
@@ -3845,13 +3884,15 @@ function emitDownloadAllResult(globalOpts, data) {
3845
3884
  }
3846
3885
  }
3847
3886
  function emitDeleteResult(globalOpts, result) {
3887
+ const jsonKey = result.jsonKey ?? "fileId";
3888
+ const message = result.message ?? `\uD30C\uC77C(${result.id})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`;
3848
3889
  if (globalOpts.json) {
3849
- printJson({ fileId: result.fileId, status: "deleted" });
3890
+ printJson({ [jsonKey]: result.id, status: "deleted" });
3850
3891
  } else if (globalOpts.quiet) {
3851
- process.stdout.write(`${result.fileId}
3892
+ process.stdout.write(`${result.id}
3852
3893
  `);
3853
3894
  } else {
3854
- process.stdout.write(`\uD30C\uC77C(${result.fileId})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
3895
+ process.stdout.write(`${message}
3855
3896
  `);
3856
3897
  }
3857
3898
  }
@@ -4078,7 +4119,7 @@ var fileDeleteCommand = new import_commander33.Command("delete").description("\u
4078
4119
  });
4079
4120
  await client.deletePostFile(projectId, postId, fileId);
4080
4121
  stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
4081
- emitDeleteResult(globalOpts, { fileId });
4122
+ emitDeleteResult(globalOpts, { id: fileId });
4082
4123
  });
4083
4124
 
4084
4125
  // src/commands/wiki/list.ts
@@ -4287,10 +4328,7 @@ var wikiPageEditCommand = new import_commander38.Command("edit").description("\u
4287
4328
  `);
4288
4329
  });
4289
4330
 
4290
- // src/commands/wiki/page-file/index.ts
4291
- var import_commander44 = require("commander");
4292
-
4293
- // src/commands/wiki/page-file/list.ts
4331
+ // src/commands/wiki/page-delete.ts
4294
4332
  var import_commander39 = require("commander");
4295
4333
 
4296
4334
  // src/resolvers/wiki-page-input.ts
@@ -4347,13 +4385,63 @@ async function resolveWikiPageInput(client, args) {
4347
4385
  throw new DoorayCliError(INPUT_HELP2, EXIT_PARAM_ERROR);
4348
4386
  }
4349
4387
 
4388
+ // src/commands/wiki/page-delete.ts
4389
+ var wikiPageDeleteCommand = new import_commander39.Command("delete").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0AD\uC81C (\uBE44\uACF5\uC2DD endpoint)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray Wiki URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uBBF8\uC0AC\uC6A9").argument("[arg2]", "page-id (positional 2\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("-y, --yes", "\uD655\uC778 \uC5C6\uC774 \uC0AD\uC81C (\uC790\uB3D9\uD654\uC6A9)").action(async (arg1, arg2, opts) => {
4390
+ const globalOpts = wikiPageDeleteCommand.optsWithGlobals();
4391
+ const config = await getConfigOrThrow();
4392
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4393
+ const { wikiId, pageId } = await resolveWikiPageInput(client, {
4394
+ projectArg: arg1,
4395
+ pageIdArg: arg2,
4396
+ idOpt: opts.id,
4397
+ urlOpt: opts.url,
4398
+ project: opts.project
4399
+ });
4400
+ if (!opts.yes) {
4401
+ if (!process.stdin.isTTY) {
4402
+ throw new DoorayCliError(
4403
+ "non-TTY \uD658\uACBD\uC5D0\uC11C\uB294 \uD655\uC778 \uC5C6\uC774 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. --yes(-y) \uD50C\uB798\uADF8\uB85C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
4404
+ EXIT_PARAM_ERROR
4405
+ );
4406
+ }
4407
+ const { confirm: confirm2 } = await import("@inquirer/prompts");
4408
+ const ok = await confirm2({
4409
+ message: `\uD398\uC774\uC9C0(${pageId})\uB97C \uC0AD\uC81C\uD560\uAE4C\uC694? \uD558\uC704 \uD398\uC774\uC9C0\uAC00 \uC788\uC73C\uBA74 \uC0C1\uC704 \uD398\uC774\uC9C0\uB85C \uC7AC\uBD80\uCC29\uB429\uB2C8\uB2E4.`,
4410
+ default: false
4411
+ });
4412
+ if (!ok) {
4413
+ if (!globalOpts.json && !globalOpts.quiet) {
4414
+ process.stdout.write("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\n");
4415
+ }
4416
+ return;
4417
+ }
4418
+ }
4419
+ startSpinner("\uD398\uC774\uC9C0 \uC0AD\uC81C \uC911...");
4420
+ try {
4421
+ await client.deleteWikiPage(wikiId, pageId);
4422
+ stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
4423
+ emitDeleteResult(globalOpts, {
4424
+ id: pageId,
4425
+ jsonKey: "pageId",
4426
+ message: `\uD398\uC774\uC9C0(${pageId})\uAC00 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`
4427
+ });
4428
+ } catch (e) {
4429
+ stopSpinner(false);
4430
+ throw e;
4431
+ }
4432
+ });
4433
+
4434
+ // src/commands/wiki/page-file/index.ts
4435
+ var import_commander45 = require("commander");
4436
+
4350
4437
  // src/commands/wiki/page-file/list.ts
4438
+ var import_commander40 = require("commander");
4351
4439
  function formatSize3(bytes) {
4352
4440
  if (bytes < 1024) return `${bytes}B`;
4353
4441
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
4354
4442
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
4355
4443
  }
4356
- 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) => {
4444
+ var wikiPageFileListCommand = new import_commander40.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) => {
4357
4445
  const globalOpts = wikiPageFileListCommand.optsWithGlobals();
4358
4446
  const config = await getConfigOrThrow();
4359
4447
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4384,7 +4472,7 @@ var wikiPageFileListCommand = new import_commander39.Command("list").description
4384
4472
  });
4385
4473
 
4386
4474
  // src/commands/wiki/page-file/upload.ts
4387
- var import_commander40 = require("commander");
4475
+ var import_commander41 = require("commander");
4388
4476
 
4389
4477
  // src/utils/wiki-snippet.ts
4390
4478
  function wikiInlineImageSnippet(wikiId, attachFileId, name) {
@@ -4392,7 +4480,7 @@ function wikiInlineImageSnippet(wikiId, attachFileId, name) {
4392
4480
  }
4393
4481
 
4394
4482
  // src/commands/wiki/page-file/upload.ts
4395
- 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) => {
4483
+ var wikiPageFileUploadCommand = new import_commander41.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) => {
4396
4484
  const globalOpts = wikiPageFileUploadCommand.optsWithGlobals();
4397
4485
  const config = await getConfigOrThrow();
4398
4486
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4487,10 +4575,10 @@ var wikiPageFileUploadCommand = new import_commander40.Command("upload").descrip
4487
4575
  });
4488
4576
 
4489
4577
  // src/commands/wiki/page-file/download.ts
4490
- var import_commander41 = require("commander");
4578
+ var import_commander42 = require("commander");
4491
4579
  var import_promises11 = require("fs/promises");
4492
4580
  var import_node_path9 = require("path");
4493
- 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) => {
4581
+ var wikiPageFileDownloadCommand = new import_commander42.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) => {
4494
4582
  const globalOpts = wikiPageFileDownloadCommand.optsWithGlobals();
4495
4583
  const config = await getConfigOrThrow();
4496
4584
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4552,10 +4640,10 @@ var wikiPageFileDownloadCommand = new import_commander41.Command("download").des
4552
4640
  });
4553
4641
 
4554
4642
  // src/commands/wiki/page-file/download-all.ts
4555
- var import_commander42 = require("commander");
4643
+ var import_commander43 = require("commander");
4556
4644
  var import_promises12 = require("fs/promises");
4557
4645
  var import_node_path10 = require("path");
4558
- 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) => {
4646
+ var wikiPageFileDownloadAllCommand = new import_commander43.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) => {
4559
4647
  const globalOpts = wikiPageFileDownloadAllCommand.optsWithGlobals();
4560
4648
  const config = await getConfigOrThrow();
4561
4649
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4612,8 +4700,8 @@ var wikiPageFileDownloadAllCommand = new import_commander42.Command("download-al
4612
4700
  });
4613
4701
 
4614
4702
  // src/commands/wiki/page-file/delete.ts
4615
- var import_commander43 = require("commander");
4616
- 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) => {
4703
+ var import_commander44 = require("commander");
4704
+ var wikiPageFileDeleteCommand = new import_commander44.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) => {
4617
4705
  const globalOpts = wikiPageFileDeleteCommand.optsWithGlobals();
4618
4706
  const config = await getConfigOrThrow();
4619
4707
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4664,7 +4752,7 @@ var wikiPageFileDeleteCommand = new import_commander43.Command("delete").descrip
4664
4752
  try {
4665
4753
  await client.deleteWikiPageFile(wikiId, pageId, fileId);
4666
4754
  stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
4667
- emitDeleteResult(globalOpts, { fileId });
4755
+ emitDeleteResult(globalOpts, { id: fileId });
4668
4756
  } catch (e) {
4669
4757
  stopSpinner(false);
4670
4758
  throw e;
@@ -4672,7 +4760,7 @@ var wikiPageFileDeleteCommand = new import_commander43.Command("delete").descrip
4672
4760
  });
4673
4761
 
4674
4762
  // src/commands/wiki/page-file/index.ts
4675
- 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)");
4763
+ var wikiPageFileCommand = new import_commander45.Command("file").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839 (Issue #70, ADR-029)");
4676
4764
  wikiPageFileCommand.addCommand(wikiPageFileListCommand);
4677
4765
  wikiPageFileCommand.addCommand(wikiPageFileUploadCommand);
4678
4766
  wikiPageFileCommand.addCommand(wikiPageFileDownloadCommand);
@@ -4680,10 +4768,10 @@ wikiPageFileCommand.addCommand(wikiPageFileDownloadAllCommand);
4680
4768
  wikiPageFileCommand.addCommand(wikiPageFileDeleteCommand);
4681
4769
 
4682
4770
  // src/commands/wiki/page-comment/index.ts
4683
- var import_commander51 = require("commander");
4771
+ var import_commander52 = require("commander");
4684
4772
 
4685
4773
  // src/commands/wiki/page-comment/list.ts
4686
- var import_commander45 = require("commander");
4774
+ var import_commander46 = require("commander");
4687
4775
 
4688
4776
  // src/formatters/wiki-comment.ts
4689
4777
  function formatWikiCommentList(comments, opts) {
@@ -4730,7 +4818,7 @@ function truncate(s, n) {
4730
4818
  }
4731
4819
 
4732
4820
  // src/commands/wiki/page-comment/list.ts
4733
- 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) => {
4821
+ var wikiPageCommentListCommand = new import_commander46.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) => {
4734
4822
  const globalOpts = wikiPageCommentListCommand.optsWithGlobals();
4735
4823
  const config = await getConfigOrThrow();
4736
4824
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4755,8 +4843,8 @@ var wikiPageCommentListCommand = new import_commander45.Command("list").descript
4755
4843
  });
4756
4844
 
4757
4845
  // src/commands/wiki/page-comment/latest.ts
4758
- var import_commander46 = require("commander");
4759
- 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) => {
4846
+ var import_commander47 = require("commander");
4847
+ var wikiPageCommentLatestCommand = new import_commander47.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) => {
4760
4848
  const globalOpts = wikiPageCommentLatestCommand.optsWithGlobals();
4761
4849
  const config = await getConfigOrThrow();
4762
4850
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4783,7 +4871,7 @@ var wikiPageCommentLatestCommand = new import_commander46.Command("latest").desc
4783
4871
  });
4784
4872
 
4785
4873
  // src/commands/wiki/page-comment/get.ts
4786
- var import_commander47 = require("commander");
4874
+ var import_commander48 = require("commander");
4787
4875
 
4788
4876
  // src/commands/wiki/page-comment/parse-args.ts
4789
4877
  function parseWikiCommentArgs(arg1, arg2, arg3, opts) {
@@ -4836,7 +4924,7 @@ function parseWikiCommentArgs(arg1, arg2, arg3, opts) {
4836
4924
  }
4837
4925
 
4838
4926
  // src/commands/wiki/page-comment/get.ts
4839
- 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) => {
4927
+ var wikiPageCommentGetCommand = new import_commander48.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) => {
4840
4928
  const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4841
4929
  const config = await getConfigOrThrow();
4842
4930
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4860,8 +4948,8 @@ var wikiPageCommentGetCommand = new import_commander47.Command("get").descriptio
4860
4948
  });
4861
4949
 
4862
4950
  // src/commands/wiki/page-comment/add.ts
4863
- var import_commander48 = require("commander");
4864
- 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) => {
4951
+ var import_commander49 = require("commander");
4952
+ var wikiPageCommentAddCommand = new import_commander49.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) => {
4865
4953
  if ((opts.id || opts.url) && (project || pageIdArg)) {
4866
4954
  throw new DoorayCliError(
4867
4955
  "positional \uC778\uC790\uC640 --id/--url \uC635\uC158\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
@@ -4907,8 +4995,8 @@ var wikiPageCommentAddCommand = new import_commander48.Command("add").descriptio
4907
4995
  });
4908
4996
 
4909
4997
  // src/commands/wiki/page-comment/edit.ts
4910
- var import_commander49 = require("commander");
4911
- 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) => {
4998
+ var import_commander50 = require("commander");
4999
+ var wikiPageCommentEditCommand = new import_commander50.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) => {
4912
5000
  const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4913
5001
  const config = await getConfigOrThrow();
4914
5002
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4952,8 +5040,8 @@ var wikiPageCommentEditCommand = new import_commander49.Command("edit").descript
4952
5040
  });
4953
5041
 
4954
5042
  // src/commands/wiki/page-comment/delete.ts
4955
- var import_commander50 = require("commander");
4956
- 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) => {
5043
+ var import_commander51 = require("commander");
5044
+ var wikiPageCommentDeleteCommand = new import_commander51.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) => {
4957
5045
  const parsed = parseWikiCommentArgs(arg1, arg2, arg3, opts);
4958
5046
  const config = await getConfigOrThrow();
4959
5047
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -4977,7 +5065,7 @@ var wikiPageCommentDeleteCommand = new import_commander50.Command("delete").desc
4977
5065
  });
4978
5066
 
4979
5067
  // src/commands/wiki/page-comment/index.ts
4980
- var wikiPageCommentCommand = new import_commander51.Command("comment").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
5068
+ var wikiPageCommentCommand = new import_commander52.Command("comment").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
4981
5069
  wikiPageCommentCommand.addCommand(wikiPageCommentListCommand);
4982
5070
  wikiPageCommentCommand.addCommand(wikiPageCommentLatestCommand);
4983
5071
  wikiPageCommentCommand.addCommand(wikiPageCommentGetCommand);
@@ -4986,10 +5074,10 @@ wikiPageCommentCommand.addCommand(wikiPageCommentEditCommand);
4986
5074
  wikiPageCommentCommand.addCommand(wikiPageCommentDeleteCommand);
4987
5075
 
4988
5076
  // src/commands/member/index.ts
4989
- var import_commander55 = require("commander");
5077
+ var import_commander56 = require("commander");
4990
5078
 
4991
5079
  // src/commands/member/get.ts
4992
- var import_commander52 = require("commander");
5080
+ var import_commander53 = require("commander");
4993
5081
 
4994
5082
  // src/formatters/member.ts
4995
5083
  function formatMemberDetail(member, opts) {
@@ -5035,7 +5123,7 @@ function formatMemberSearchResults(members, opts) {
5035
5123
  }
5036
5124
 
5037
5125
  // src/commands/member/get.ts
5038
- 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) => {
5126
+ var memberGetCommand = new import_commander53.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
5039
5127
  const globalOpts = memberGetCommand.optsWithGlobals();
5040
5128
  const config = await getConfigOrThrow();
5041
5129
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -5044,8 +5132,8 @@ var memberGetCommand = new import_commander52.Command("get").description("\uBA64
5044
5132
  });
5045
5133
 
5046
5134
  // src/commands/member/list.ts
5047
- var import_commander53 = require("commander");
5048
- 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) => {
5135
+ var import_commander54 = require("commander");
5136
+ var memberListCommand = new import_commander54.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) => {
5049
5137
  const globalOpts = memberListCommand.optsWithGlobals();
5050
5138
  const config = await getConfigOrThrow();
5051
5139
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -5060,8 +5148,8 @@ var memberListCommand = new import_commander53.Command("list").description("\uD5
5060
5148
  });
5061
5149
 
5062
5150
  // src/commands/member/search.ts
5063
- var import_commander54 = require("commander");
5064
- 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) => {
5151
+ var import_commander55 = require("commander");
5152
+ var memberSearchCommand = new import_commander55.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) => {
5065
5153
  const globalOpts = memberSearchCommand.optsWithGlobals();
5066
5154
  const filterCount = [keyword, opts.email, opts.userCode, opts.userCodeExact].filter(Boolean).length;
5067
5155
  if (filterCount === 0) {
@@ -5094,13 +5182,13 @@ var memberSearchCommand = new import_commander54.Command("search").description("
5094
5182
  });
5095
5183
 
5096
5184
  // src/commands/member/index.ts
5097
- var memberCommand = new import_commander55.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
5185
+ var memberCommand = new import_commander56.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
5098
5186
  memberCommand.addCommand(memberGetCommand);
5099
5187
  memberCommand.addCommand(memberListCommand);
5100
5188
  memberCommand.addCommand(memberSearchCommand);
5101
5189
 
5102
5190
  // src/commands/mail/list.ts
5103
- var import_commander56 = require("commander");
5191
+ var import_commander57 = require("commander");
5104
5192
 
5105
5193
  // src/api/imapClient.ts
5106
5194
  var import_imapflow = require("imapflow");
@@ -5217,7 +5305,7 @@ async function getMail(config, uid) {
5217
5305
 
5218
5306
  // src/commands/mail/list.ts
5219
5307
  var import_chalk5 = __toESM(require("chalk"));
5220
- 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) => {
5308
+ var mailListCommand = new import_commander57.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) => {
5221
5309
  const globalOpts = mailListCommand.optsWithGlobals();
5222
5310
  const config = await getConfigOrThrow();
5223
5311
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -5249,9 +5337,9 @@ var mailListCommand = new import_commander56.Command("list").description("\uBA54
5249
5337
  });
5250
5338
 
5251
5339
  // src/commands/mail/get.ts
5252
- var import_commander57 = require("commander");
5340
+ var import_commander58 = require("commander");
5253
5341
  var import_chalk6 = __toESM(require("chalk"));
5254
- var mailGetCommand = new import_commander57.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
5342
+ var mailGetCommand = new import_commander58.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
5255
5343
  const globalOpts = mailGetCommand.optsWithGlobals();
5256
5344
  const config = await getConfigOrThrow();
5257
5345
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -5282,7 +5370,7 @@ ${mail.body}
5282
5370
  });
5283
5371
 
5284
5372
  // src/commands/mail/send.ts
5285
- var import_commander58 = require("commander");
5373
+ var import_commander59 = require("commander");
5286
5374
  var import_promises13 = require("fs/promises");
5287
5375
 
5288
5376
  // src/api/smtpClient.ts
@@ -5332,7 +5420,7 @@ async function sendMail(config, opts) {
5332
5420
  }
5333
5421
 
5334
5422
  // src/commands/mail/send.ts
5335
- 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) => {
5423
+ var mailSendCommand = new import_commander59.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) => {
5336
5424
  const globalOpts = mailSendCommand.optsWithGlobals();
5337
5425
  const config = await getConfigOrThrow();
5338
5426
  let body = opts.body ?? "";
@@ -5367,7 +5455,7 @@ var mailSendCommand = new import_commander58.Command("send").description("\uBA54
5367
5455
  });
5368
5456
 
5369
5457
  // src/commands/mail/reply.ts
5370
- var import_commander59 = require("commander");
5458
+ var import_commander60 = require("commander");
5371
5459
  var import_promises14 = require("fs/promises");
5372
5460
  var import_imapflow2 = require("imapflow");
5373
5461
  async function getMessageId(config, uid) {
@@ -5396,7 +5484,7 @@ async function getMessageId(config, uid) {
5396
5484
  await client.logout();
5397
5485
  }
5398
5486
  }
5399
- 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) => {
5487
+ var mailReplyCommand = new import_commander60.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) => {
5400
5488
  const globalOpts = mailReplyCommand.optsWithGlobals();
5401
5489
  const config = await getConfigOrThrow();
5402
5490
  let body = opts.body ?? "";
@@ -5436,8 +5524,109 @@ var mailReplyCommand = new import_commander59.Command("reply").description("\uBA
5436
5524
  }
5437
5525
  });
5438
5526
 
5527
+ // src/commands/messenger/index.ts
5528
+ var import_commander63 = require("commander");
5529
+
5530
+ // src/commands/messenger/send.ts
5531
+ var import_commander61 = require("commander");
5532
+ var messengerSendCommand = new import_commander61.Command("send").description("\uBA54\uC2E0\uC800 1:1 \uB2E4\uC774\uB809\uD2B8 \uBA54\uC2DC\uC9C0 \uC804\uC1A1 (--body \uC5C6\uC73C\uBA74 $EDITOR)").option("--to <id|email>", "\uBC1B\uB294 \uC0AC\uB78C (organizationMemberId \uB610\uB294 \uC774\uBA54\uC77C \u2014 \uC774\uB984 \uBBF8\uC9C0\uC6D0)").option("--body <text>", "\uBA54\uC2DC\uC9C0 \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 (opts) => {
5533
+ if (!opts.to) {
5534
+ throw new DoorayCliError("--to \uC635\uC158\uC740 \uD544\uC218\uC785\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
5535
+ }
5536
+ const globalOpts = messengerSendCommand.optsWithGlobals();
5537
+ const config = await getConfigOrThrow();
5538
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
5539
+ const memberId = await resolveMemberByIdOrEmail(client, opts.to);
5540
+ if (memberId == null) {
5541
+ throw new DoorayCliError(
5542
+ `--to \uB294 organizationMemberId \uB610\uB294 \uC774\uBA54\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uC774\uB984 \uBBF8\uC9C0\uC6D0): "${opts.to}"`,
5543
+ EXIT_PARAM_ERROR
5544
+ );
5545
+ }
5546
+ let bodyContent = await readBodyInputOrNull(opts);
5547
+ if (bodyContent == null) {
5548
+ bodyContent = await openInEditor("");
5549
+ }
5550
+ if (!bodyContent.trim()) {
5551
+ throw new DoorayCliError("\uBE48 \uBA54\uC2DC\uC9C0\uB294 \uC804\uC1A1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
5552
+ }
5553
+ startSpinner("\uBA54\uC2DC\uC9C0 \uC804\uC1A1 \uC911...");
5554
+ try {
5555
+ const res = await client.sendDirectMessage(memberId, bodyContent);
5556
+ stopSpinner(true, `\uBA54\uC2DC\uC9C0\uB97C \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4 (log-id: ${res.result.id})`);
5557
+ if (globalOpts.json) {
5558
+ printJson(res.result);
5559
+ } else if (globalOpts.quiet) {
5560
+ printQuiet([res.result.id]);
5561
+ } else {
5562
+ process.stdout.write(`\uBA54\uC2DC\uC9C0\uB97C \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4 (log-id: ${res.result.id})
5563
+ `);
5564
+ }
5565
+ } catch (e) {
5566
+ stopSpinner(false);
5567
+ throw e;
5568
+ }
5569
+ });
5570
+
5571
+ // src/commands/messenger/channel-send.ts
5572
+ var import_commander62 = require("commander");
5573
+
5574
+ // src/resolvers/messenger-channel.ts
5575
+ var CHANNEL_ID_RE = /^\d{15,}$/;
5576
+ async function resolveMessengerChannel(client, input2) {
5577
+ if (CHANNEL_ID_RE.test(input2)) {
5578
+ return input2;
5579
+ }
5580
+ const res = await client.getMessengerChannels();
5581
+ const named = res.result.filter((ch) => !!ch.title);
5582
+ const adapter = named.map((ch) => ({ name: ch.title, id: ch.id }));
5583
+ const match = matchByName(adapter, input2, "\uB300\uD654\uBC29", (ch) => `${ch.name} (${ch.id})`, {
5584
+ helpHint: "channelId \uC9C1\uC811 \uC785\uB825 (15+\uC790\uB9AC numeric) \uB610\uB294 Dooray \uBA54\uC2E0\uC800\uC5D0\uC11C \uBC29 \uD655\uC778"
5585
+ });
5586
+ return match.id;
5587
+ }
5588
+
5589
+ // src/commands/messenger/channel-send.ts
5590
+ var messengerChannelSendCommand = new import_commander62.Command("channel-send").description("\uBA54\uC2E0\uC800 \uB300\uD654\uBC29 \uBA54\uC2DC\uC9C0 \uC804\uC1A1 (--body \uC5C6\uC73C\uBA74 $EDITOR)").option("--channel <channelId|\uC774\uB984>", "\uB300\uD654\uBC29 channelId \uB610\uB294 \uC774\uB984 (\uBD80\uBD84\uC77C\uCE58)").option("--body <text>", "\uBA54\uC2DC\uC9C0 \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 (opts) => {
5591
+ if (!opts.channel) {
5592
+ throw new DoorayCliError("--channel \uC635\uC158\uC740 \uD544\uC218\uC785\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
5593
+ }
5594
+ const globalOpts = messengerChannelSendCommand.optsWithGlobals();
5595
+ const config = await getConfigOrThrow();
5596
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
5597
+ const channelId = await resolveMessengerChannel(client, opts.channel);
5598
+ let bodyContent = await readBodyInputOrNull(opts);
5599
+ if (bodyContent == null) {
5600
+ bodyContent = await openInEditor("");
5601
+ }
5602
+ if (!bodyContent.trim()) {
5603
+ throw new DoorayCliError("\uBE48 \uBA54\uC2DC\uC9C0\uB294 \uC804\uC1A1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
5604
+ }
5605
+ startSpinner("\uBA54\uC2DC\uC9C0 \uC804\uC1A1 \uC911...");
5606
+ try {
5607
+ const res = await client.sendChannelMessage(channelId, bodyContent);
5608
+ stopSpinner(true, `\uBA54\uC2DC\uC9C0\uB97C \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4 (log-id: ${res.result.id})`);
5609
+ if (globalOpts.json) {
5610
+ printJson(res.result);
5611
+ } else if (globalOpts.quiet) {
5612
+ printQuiet([res.result.id]);
5613
+ } else {
5614
+ process.stdout.write(`\uBA54\uC2DC\uC9C0\uB97C \uC804\uC1A1\uD588\uC2B5\uB2C8\uB2E4 (log-id: ${res.result.id})
5615
+ `);
5616
+ }
5617
+ } catch (e) {
5618
+ stopSpinner(false);
5619
+ throw e;
5620
+ }
5621
+ });
5622
+
5623
+ // src/commands/messenger/index.ts
5624
+ var messengerCommand = new import_commander63.Command("messenger").description("\uBA54\uC2E0\uC800 \uAD00\uB828 \uBA85\uB839");
5625
+ messengerCommand.addCommand(messengerSendCommand);
5626
+ messengerCommand.addCommand(messengerChannelSendCommand);
5627
+
5439
5628
  // src/commands/feedback.ts
5440
- var import_commander60 = require("commander");
5629
+ var import_commander64 = require("commander");
5441
5630
  var import_node_child_process2 = require("child_process");
5442
5631
  var import_node_util = require("util");
5443
5632
  var import_promises17 = require("fs/promises");
@@ -5548,7 +5737,7 @@ async function readBody(opts) {
5548
5737
  if (opts.bodyFile) return await (0, import_promises17.readFile)(opts.bodyFile, "utf-8");
5549
5738
  return void 0;
5550
5739
  }
5551
- 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(
5740
+ var feedbackCommand = new import_commander64.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(
5552
5741
  "--label <name>",
5553
5742
  "\uB77C\uBCA8 (\uBC18\uBCF5 \uAC00\uB2A5)",
5554
5743
  (value, prev) => [...prev, value],
@@ -5711,8 +5900,8 @@ function sanitizeArgv(argv) {
5711
5900
  }
5712
5901
 
5713
5902
  // src/index.ts
5714
- var program = new import_commander61.Command();
5715
- program.name("dooray").description("Dooray REST API CLI").version("0.12.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");
5903
+ var program = new import_commander65.Command();
5904
+ program.name("dooray").description("Dooray REST API CLI").version("0.13.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");
5716
5905
  program.hook("preAction", () => {
5717
5906
  const opts = program.opts();
5718
5907
  if (opts.color === false || process.env.NO_COLOR) {
@@ -5722,14 +5911,14 @@ program.hook("preAction", () => {
5722
5911
  setQuiet(true);
5723
5912
  }
5724
5913
  });
5725
- var projectCommand = new import_commander61.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
5914
+ var projectCommand = new import_commander65.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
5726
5915
  projectCommand.addCommand(projectListCommand);
5727
5916
  projectCommand.addCommand(projectMembersCommand);
5728
5917
  projectCommand.addCommand(projectWorkflowsCommand);
5729
5918
  projectCommand.addCommand(projectGroupsCommand);
5730
5919
  projectCommand.addCommand(projectTagsCommand);
5731
5920
  projectCommand.addCommand(projectTemplatesCommand);
5732
- var postCommand = new import_commander61.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
5921
+ var postCommand = new import_commander65.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
5733
5922
  postCommand.addCommand(postListCommand);
5734
5923
  postCommand.addCommand(postSearchCommand);
5735
5924
  postCommand.addCommand(postGetCommand);
@@ -5737,7 +5926,7 @@ postCommand.addCommand(postEditCommand);
5737
5926
  postCommand.addCommand(postCreateCommand);
5738
5927
  postCommand.addCommand(postDoneCommand);
5739
5928
  postCommand.addCommand(postWorkflowCommand);
5740
- var commentCommand = new import_commander61.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
5929
+ var commentCommand = new import_commander65.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
5741
5930
  commentCommand.addCommand(commentListCommand);
5742
5931
  commentCommand.addCommand(commentLatestCommand);
5743
5932
  commentCommand.addCommand(commentGetCommand);
@@ -5746,24 +5935,25 @@ commentCommand.addCommand(commentEditCommand);
5746
5935
  commentCommand.addCommand(commentDeleteCommand);
5747
5936
  commentCommand.addCommand(commentFileCommand);
5748
5937
  postCommand.addCommand(commentCommand);
5749
- var fileCommand = new import_commander61.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
5938
+ var fileCommand = new import_commander65.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
5750
5939
  fileCommand.addCommand(fileListCommand);
5751
5940
  fileCommand.addCommand(fileDownloadCommand);
5752
5941
  fileCommand.addCommand(fileDownloadAllCommand);
5753
5942
  fileCommand.addCommand(fileUploadCommand);
5754
5943
  fileCommand.addCommand(fileDeleteCommand);
5755
5944
  postCommand.addCommand(fileCommand);
5756
- var wikiCommand = new import_commander61.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
5945
+ var wikiCommand = new import_commander65.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
5757
5946
  wikiCommand.addCommand(wikiListCommand);
5758
5947
  wikiCommand.addCommand(wikiPagesCommand);
5759
- var wikiPageCommand = new import_commander61.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
5948
+ var wikiPageCommand = new import_commander65.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
5760
5949
  wikiPageCommand.addCommand(wikiPageGetCommand);
5761
5950
  wikiPageCommand.addCommand(wikiPageCreateCommand);
5762
5951
  wikiPageCommand.addCommand(wikiPageEditCommand);
5952
+ wikiPageCommand.addCommand(wikiPageDeleteCommand);
5763
5953
  wikiPageCommand.addCommand(wikiPageFileCommand);
5764
5954
  wikiPageCommand.addCommand(wikiPageCommentCommand);
5765
5955
  wikiCommand.addCommand(wikiPageCommand);
5766
- var mailCommand = new import_commander61.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
5956
+ var mailCommand = new import_commander65.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
5767
5957
  mailCommand.addCommand(mailListCommand);
5768
5958
  mailCommand.addCommand(mailGetCommand);
5769
5959
  mailCommand.addCommand(mailSendCommand);
@@ -5777,6 +5967,7 @@ program.addCommand(projectCommand);
5777
5967
  program.addCommand(postCommand);
5778
5968
  program.addCommand(wikiCommand);
5779
5969
  program.addCommand(mailCommand);
5970
+ program.addCommand(messengerCommand);
5780
5971
  program.addCommand(feedbackCommand);
5781
5972
  program.parseAsync().catch(async (err) => {
5782
5973
  const errorMessage = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bifos/dooray-cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "CLI tool for Dooray project management — AI agent & terminal friendly",
5
5
  "keywords": [
6
6
  "dooray",
@@ -28,6 +28,7 @@
28
28
  "engines": {
29
29
  "node": ">=20"
30
30
  },
31
+ "packageManager": "pnpm@11.11.0",
31
32
  "scripts": {
32
33
  "build": "tsup",
33
34
  "dev": "tsup --watch",
@@ -36,26 +37,25 @@
36
37
  },
37
38
  "license": "MIT",
38
39
  "dependencies": {
39
- "@inquirer/prompts": "^8.3.2",
40
+ "@inquirer/prompts": "^8.5.2",
40
41
  "chalk": "^5.6.2",
41
42
  "cli-table3": "^0.6.5",
42
- "commander": "^14.0.3",
43
- "imapflow": "^1.2.18",
44
- "js-yaml": "^4.1.1",
45
- "ky": "^1.14.3",
46
- "mailparser": "^3.9.6",
47
- "nodemailer": "^8.0.4",
48
- "ora": "^9.3.0",
49
- "tmp": "^0.2.5"
43
+ "commander": "^15.0.0",
44
+ "imapflow": "^1.4.6",
45
+ "js-yaml": "^5.2.1",
46
+ "ky": "^2.0.2",
47
+ "mailparser": "^3.9.14",
48
+ "nodemailer": "^9.0.3",
49
+ "ora": "^9.4.1",
50
+ "tmp": "^0.2.7"
50
51
  },
51
52
  "devDependencies": {
52
- "@types/js-yaml": "^4.0.9",
53
53
  "@types/mailparser": "^3.4.6",
54
- "@types/node": "^25.5.0",
55
- "@types/nodemailer": "^7.0.11",
54
+ "@types/node": "^26.1.1",
55
+ "@types/nodemailer": "^8.0.1",
56
56
  "@types/tmp": "^0.2.6",
57
57
  "tsup": "^8.5.1",
58
- "typescript": "^6.0.2",
59
- "vitest": "^4.1.5"
58
+ "typescript": "^7.0.2",
59
+ "vitest": "^4.1.10"
60
60
  }
61
61
  }
@@ -87,6 +87,7 @@ dooray doctor # 설정 검증
87
87
  | 위키 페이지 수정 (제목) | `dooray wiki page edit <project> <page-id> --title "..."` |
88
88
  | 위키 페이지 수정 (본문) | `dooray wiki page edit <project> <page-id> --body "..."` 또는 `--body-file ./new.md` |
89
89
  | 위키 페이지 수정 (에디터) | `dooray wiki page edit <project> <page-id>` (플래그 없으면 $EDITOR 열림) |
90
+ | 위키 페이지 삭제 | `dooray wiki page delete <project> <page-id>` (y/N 확인 기본, `--yes`로 자동화 시 생략. 하위 페이지는 상위 페이지로 재부착) |
90
91
  | 위키 페이지 첨부 목록 | `dooray wiki page file list <project> <page-id>` (general + inline 합산, type 컬럼) |
91
92
  | 위키 페이지 첨부 업로드 | `dooray wiki page file upload <project> <page-id> --file <path> [--type inline_image]` (multipart `type` 필드를 `file` 앞에 전송) |
92
93
  | 위키 페이지 첨부 다운로드 | `dooray wiki page file download <project> <page-id> --file-id <id> -o <dir>` |
@@ -104,6 +105,8 @@ dooray doctor # 설정 검증
104
105
  | 메일 상세 | `dooray mail get <uid>` |
105
106
  | 메일 발송 | `dooray mail send --to "..." --subject "..." --body "..."` |
106
107
  | 메일 답장 | `dooray mail reply <uid> --body "..."` |
108
+ | 메신저 1:1 다이렉트 메시지 | `dooray messenger send --to "<id\|email>" --body "..."` (`--to`는 id/이메일만, 이름 미지원) |
109
+ | 메신저 대화방 메시지 | `dooray messenger channel-send --channel "<channelId\|이름>" --body "..."` (이름은 자신이 속한 방만 검색) |
107
110
  | 첨부파일 목록 | `dooray post file list <project> <number>` |
108
111
  | 첨부파일 다운로드 | `dooray post file download <project> <number> <file-id>` |
109
112
  | 전체 첨부파일 다운로드 | `dooray post file download-all <project> <number>` |
@@ -133,10 +136,11 @@ CLI로 처리 **불가능한** 작업. 아래 항목을 요청받으면 웹 UI
133
136
 
134
137
  | 작업 | 대체 경로 | 근거 |
135
138
  |---|---|---|
136
- | 위키 페이지 **삭제** | 웹 UI (`https://{tenant}.dooray.com/wiki/...`) | Dooray REST API 미제공 (댓글·첨부파일 삭제는 있지만 페이지 삭제 endpoint 없음) |
139
+ | 위키 페이지 이동 (상위 페이지 변경) | 웹 UI (`https://{tenant}.dooray.com/wiki/...`) | Dooray REST API 미지원 |
137
140
  | 프로젝트 삭제 | 웹 UI (admin 페이지) | API 미지원 |
138
141
 
139
- 위키 페이지를 잘못 만든 경우(테스트/중복) **soft delete(빈 제목·본문) 우회 금지** 페이지가 트리에 남아 사용자 혼란 유발.
142
+ 위키 페이지를 잘못 만든 경우(테스트/중복) `dooray wiki page delete <project> <page-id>` 정리한다.
143
+ 공식 문서화된 endpoint 가 아니라 서버 정책이 바뀌면 동작이 달라질 수 있음에 유의한다.
140
144
 
141
145
  ---
142
146
 
@@ -202,6 +206,22 @@ COMMENT_ID=$(dooray post comment add <project> <post-num> --body "스크린샷
202
206
  dooray post comment file upload <project> <post-num> "$COMMENT_ID" ./screenshot.png
203
207
  ```
204
208
 
209
+ ### 시나리오 — 배포 알림 메신저 자동 전송
210
+
211
+ CI/배포 스크립트가 완료 알림을 담당자 DM 또는 팀 대화방에 자동으로 보낼 때 사용.
212
+ 전송은 API 토큰 소유자 명의로 나가며, 본문은 plain text 만 지원한다.
213
+
214
+ ```bash
215
+ # 담당자 DM (id 또는 이메일만 가능 — 이름 검색 미지원)
216
+ dooray messenger send --to "user@example.com" --body "배포가 완료되었습니다 (v1.2.3)."
217
+
218
+ # 팀 대화방 (channelId 또는 자신이 속한 대화방 이름)
219
+ dooray messenger channel-send --channel "배포 알림방" --body-file ./release-note.md
220
+
221
+ # --json 으로 log-id 확인 (자동화 파이프라인에서 후속 처리 시)
222
+ dooray messenger send --to <memberId> --body "..." --json
223
+ ```
224
+
205
225
  ### 위키 페이지 조회
206
226
 
207
227
  ```bash