@bifos/dooray-cli 0.8.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_commander47 = require("commander");
27
+ var import_commander61 = require("commander");
28
28
  var import_chalk7 = __toESM(require("chalk"));
29
29
 
30
30
  // src/commands/config.ts
@@ -205,6 +205,7 @@ var TAGS_DIR = (0, import_node_path2.join)(CACHE_DIR, "tags");
205
205
  var MILESTONES_DIR = (0, import_node_path2.join)(CACHE_DIR, "milestones");
206
206
  var MEMBER_GROUPS_DIR = (0, import_node_path2.join)(CACHE_DIR, "member-groups");
207
207
  var WIKIS_PATH = (0, import_node_path2.join)(CACHE_DIR, "wikis.json");
208
+ var TEMPLATES_DIR = (0, import_node_path2.join)(CACHE_DIR, "templates");
208
209
  async function ensureDir2(dir) {
209
210
  await (0, import_promises2.mkdir)(dir, { recursive: true });
210
211
  }
@@ -291,6 +292,15 @@ async function getMemberGroups(projectId) {
291
292
  async function setMemberGroups(projectId, items) {
292
293
  await writeJson(memberGroupsPath(projectId), { updatedAt: now(), data: items });
293
294
  }
295
+ function templatesPath(projectId) {
296
+ return (0, import_node_path2.join)(TEMPLATES_DIR, `${projectId}.json`);
297
+ }
298
+ async function getTemplates(projectId) {
299
+ return readJson(templatesPath(projectId));
300
+ }
301
+ async function setTemplates(projectId, items) {
302
+ await writeJson(templatesPath(projectId), { updatedAt: now(), data: items });
303
+ }
294
304
  async function getWikis() {
295
305
  return readJson(WIKIS_PATH);
296
306
  }
@@ -414,7 +424,7 @@ var DoorayApiClient = class {
414
424
  try {
415
425
  return await this.api.get("common/v1/members/me").json();
416
426
  } catch (e) {
417
- return await toDoorayCliError(e);
427
+ throw await toDoorayCliError(e);
418
428
  }
419
429
  }
420
430
  // ─── Projects ───────────────────────────────────────
@@ -431,7 +441,7 @@ var DoorayApiClient = class {
431
441
  }
432
442
  }).json();
433
443
  } catch (e) {
434
- return await toDoorayCliError(e);
444
+ throw await toDoorayCliError(e);
435
445
  }
436
446
  }
437
447
  // ─── Posts ──────────────────────────────────────────
@@ -458,42 +468,42 @@ var DoorayApiClient = class {
458
468
  }
459
469
  }).json();
460
470
  } catch (e) {
461
- return await toDoorayCliError(e);
471
+ throw await toDoorayCliError(e);
462
472
  }
463
473
  }
464
474
  async getPost(projectId, postId) {
465
475
  try {
466
476
  return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}`).json();
467
477
  } catch (e) {
468
- return await toDoorayCliError(e);
478
+ throw await toDoorayCliError(e);
469
479
  }
470
480
  }
471
481
  async getPostStandalone(postId) {
472
482
  try {
473
483
  return await this.api.get(`project/v1/posts/${postId}`).json();
474
484
  } catch (e) {
475
- return await toDoorayCliError(e);
485
+ throw await toDoorayCliError(e);
476
486
  }
477
487
  }
478
488
  async createPost(projectId, body) {
479
489
  try {
480
490
  return await this.api.post(`project/v1/projects/${projectId}/posts`, { json: body }).json();
481
491
  } catch (e) {
482
- return await toDoorayCliError(e);
492
+ throw await toDoorayCliError(e);
483
493
  }
484
494
  }
485
495
  async updatePost(projectId, postId, body) {
486
496
  try {
487
497
  return await this.api.put(`project/v1/projects/${projectId}/posts/${postId}`, { json: body }).json();
488
498
  } catch (e) {
489
- return await toDoorayCliError(e);
499
+ throw await toDoorayCliError(e);
490
500
  }
491
501
  }
492
502
  async setPostDone(projectId, postId) {
493
503
  try {
494
504
  return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/set-done`).json();
495
505
  } catch (e) {
496
- return await toDoorayCliError(e);
506
+ throw await toDoorayCliError(e);
497
507
  }
498
508
  }
499
509
  async setPostWorkflow(projectId, postId, workflowId) {
@@ -502,7 +512,7 @@ var DoorayApiClient = class {
502
512
  json: { workflowId }
503
513
  }).json();
504
514
  } catch (e) {
505
- return await toDoorayCliError(e);
515
+ throw await toDoorayCliError(e);
506
516
  }
507
517
  }
508
518
  async setPostParent(projectId, postId, parentPostId) {
@@ -511,7 +521,7 @@ var DoorayApiClient = class {
511
521
  json: { parentPostId }
512
522
  }).json();
513
523
  } catch (e) {
514
- return await toDoorayCliError(e);
524
+ throw await toDoorayCliError(e);
515
525
  }
516
526
  }
517
527
  // ─── Post Comments ──────────────────────────────────
@@ -525,35 +535,35 @@ var DoorayApiClient = class {
525
535
  }
526
536
  }).json();
527
537
  } catch (e) {
528
- return await toDoorayCliError(e);
538
+ throw await toDoorayCliError(e);
529
539
  }
530
540
  }
531
541
  async getPostComment(projectId, postId, logId) {
532
542
  try {
533
543
  return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/logs/${logId}`).json();
534
544
  } catch (e) {
535
- return await toDoorayCliError(e);
545
+ throw await toDoorayCliError(e);
536
546
  }
537
547
  }
538
548
  async createPostComment(projectId, postId, body) {
539
549
  try {
540
550
  return await this.api.post(`project/v1/projects/${projectId}/posts/${postId}/logs`, { json: body }).json();
541
551
  } catch (e) {
542
- return await toDoorayCliError(e);
552
+ throw await toDoorayCliError(e);
543
553
  }
544
554
  }
545
555
  async updatePostComment(projectId, postId, logId, body) {
546
556
  try {
547
557
  return await this.api.put(`project/v1/projects/${projectId}/posts/${postId}/logs/${logId}`, { json: body }).json();
548
558
  } catch (e) {
549
- return await toDoorayCliError(e);
559
+ throw await toDoorayCliError(e);
550
560
  }
551
561
  }
552
562
  async deletePostComment(projectId, postId, logId) {
553
563
  try {
554
564
  return await this.api.delete(`project/v1/projects/${projectId}/posts/${postId}/logs/${logId}`).json();
555
565
  } catch (e) {
556
- return await toDoorayCliError(e);
566
+ throw await toDoorayCliError(e);
557
567
  }
558
568
  }
559
569
  // ─── Members ────────────────────────────────────────
@@ -567,14 +577,14 @@ var DoorayApiClient = class {
567
577
  }
568
578
  }).json();
569
579
  } catch (e) {
570
- return await toDoorayCliError(e);
580
+ throw await toDoorayCliError(e);
571
581
  }
572
582
  }
573
583
  async getMemberDetail(memberId) {
574
584
  try {
575
585
  return await this.api.get(`common/v1/members/${memberId}`).json();
576
586
  } catch (e) {
577
- return await toDoorayCliError(e);
587
+ throw await toDoorayCliError(e);
578
588
  }
579
589
  }
580
590
  async searchMembers(params) {
@@ -591,7 +601,7 @@ var DoorayApiClient = class {
591
601
  }
592
602
  }).json();
593
603
  } catch (e) {
594
- return await toDoorayCliError(e);
604
+ throw await toDoorayCliError(e);
595
605
  }
596
606
  }
597
607
  // ─── Workflows ──────────────────────────────────────
@@ -599,7 +609,7 @@ var DoorayApiClient = class {
599
609
  try {
600
610
  return await this.api.get(`project/v1/projects/${projectId}/workflows`).json();
601
611
  } catch (e) {
602
- return await toDoorayCliError(e);
612
+ throw await toDoorayCliError(e);
603
613
  }
604
614
  }
605
615
  // ─── Tags ───────────────────────────────────────────
@@ -612,7 +622,7 @@ var DoorayApiClient = class {
612
622
  }
613
623
  }).json();
614
624
  } catch (e) {
615
- return await toDoorayCliError(e);
625
+ throw await toDoorayCliError(e);
616
626
  }
617
627
  }
618
628
  // ─── Member Groups ──────────────────────────────────
@@ -625,7 +635,7 @@ var DoorayApiClient = class {
625
635
  }
626
636
  }).json();
627
637
  } catch (e) {
628
- return await toDoorayCliError(e);
638
+ throw await toDoorayCliError(e);
629
639
  }
630
640
  }
631
641
  // ─── Milestones ─────────────────────────────────────
@@ -638,7 +648,7 @@ var DoorayApiClient = class {
638
648
  }
639
649
  }).json();
640
650
  } catch (e) {
641
- return await toDoorayCliError(e);
651
+ throw await toDoorayCliError(e);
642
652
  }
643
653
  }
644
654
  // ─── Wiki ───────────────────────────────────────────
@@ -651,7 +661,7 @@ var DoorayApiClient = class {
651
661
  }
652
662
  }).json();
653
663
  } catch (e) {
654
- return await toDoorayCliError(e);
664
+ throw await toDoorayCliError(e);
655
665
  }
656
666
  }
657
667
  async getWikiPages(wikiId, parentPageId) {
@@ -662,42 +672,42 @@ var DoorayApiClient = class {
662
672
  }
663
673
  }).json();
664
674
  } catch (e) {
665
- return await toDoorayCliError(e);
675
+ throw await toDoorayCliError(e);
666
676
  }
667
677
  }
668
678
  async getWikiPage(wikiId, pageId) {
669
679
  try {
670
680
  return await this.api.get(`wiki/v1/wikis/${wikiId}/pages/${pageId}`).json();
671
681
  } catch (e) {
672
- return await toDoorayCliError(e);
682
+ throw await toDoorayCliError(e);
673
683
  }
674
684
  }
675
685
  async createWikiPage(wikiId, body) {
676
686
  try {
677
687
  return await this.api.post(`wiki/v1/wikis/${wikiId}/pages`, { json: body }).json();
678
688
  } catch (e) {
679
- return await toDoorayCliError(e);
689
+ throw await toDoorayCliError(e);
680
690
  }
681
691
  }
682
692
  async updateWikiPage(wikiId, pageId, body) {
683
693
  try {
684
694
  return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}`, { json: body }).json();
685
695
  } catch (e) {
686
- return await toDoorayCliError(e);
696
+ throw await toDoorayCliError(e);
687
697
  }
688
698
  }
689
699
  async updateWikiPageTitle(wikiId, pageId, body) {
690
700
  try {
691
701
  return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}/title`, { json: body }).json();
692
702
  } catch (e) {
693
- return await toDoorayCliError(e);
703
+ throw await toDoorayCliError(e);
694
704
  }
695
705
  }
696
706
  async updateWikiPageContent(wikiId, pageId, body) {
697
707
  try {
698
708
  return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}/content`, { json: body }).json();
699
709
  } catch (e) {
700
- return await toDoorayCliError(e);
710
+ throw await toDoorayCliError(e);
701
711
  }
702
712
  }
703
713
  // ─── Post Files ─────────────────────────────────────
@@ -705,7 +715,7 @@ var DoorayApiClient = class {
705
715
  try {
706
716
  return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/files`).json();
707
717
  } catch (e) {
708
- return await toDoorayCliError(e);
718
+ throw await toDoorayCliError(e);
709
719
  }
710
720
  }
711
721
  async getPostFileMeta(projectId, postId, fileId) {
@@ -714,7 +724,7 @@ var DoorayApiClient = class {
714
724
  searchParams: { media: "meta" }
715
725
  }).json();
716
726
  } catch (e) {
717
- return await toDoorayCliError(e);
727
+ throw await toDoorayCliError(e);
718
728
  }
719
729
  }
720
730
  async downloadPostFile(projectId, postId, fileId) {
@@ -744,7 +754,7 @@ var DoorayApiClient = class {
744
754
  return { buffer, fileName };
745
755
  } catch (e) {
746
756
  if (e instanceof DoorayCliError) throw e;
747
- return await toDoorayCliError(e);
757
+ throw await toDoorayCliError(e);
748
758
  }
749
759
  }
750
760
  async uploadPostFile(projectId, postId, filePath) {
@@ -781,14 +791,161 @@ var DoorayApiClient = class {
781
791
  return await res.json();
782
792
  } catch (e) {
783
793
  if (e instanceof DoorayCliError) throw e;
784
- return await toDoorayCliError(e);
794
+ throw await toDoorayCliError(e);
785
795
  }
786
796
  }
787
797
  async deletePostFile(projectId, postId, fileId) {
788
798
  try {
789
799
  return await this.api.delete(`project/v1/projects/${projectId}/posts/${postId}/files/${fileId}`).json();
790
800
  } catch (e) {
791
- return await toDoorayCliError(e);
801
+ throw await toDoorayCliError(e);
802
+ }
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
+ }
929
+ // ─── Templates ──────────────────────────────────────
930
+ async getProjectTemplates(projectId, params) {
931
+ try {
932
+ return await this.api.get(`project/v1/projects/${projectId}/templates`, {
933
+ searchParams: {
934
+ ...params?.page != null && { page: params.page },
935
+ ...params?.size != null && { size: params.size }
936
+ }
937
+ }).json();
938
+ } catch (e) {
939
+ throw await toDoorayCliError(e);
940
+ }
941
+ }
942
+ async getProjectTemplateDetail(projectId, templateId, interpolation = true) {
943
+ try {
944
+ return await this.api.get(`project/v1/projects/${projectId}/templates/${templateId}`, {
945
+ searchParams: { interpolation: String(interpolation) }
946
+ }).json();
947
+ } catch (e) {
948
+ throw await toDoorayCliError(e);
792
949
  }
793
950
  }
794
951
  };
@@ -803,6 +960,7 @@ var MILESTONES_TTL_MS = 864e5;
803
960
  var RESOLVER_FETCH_PAGE_SIZE = 100;
804
961
  var MEMBER_GROUPS_TTL_MS = 864e5;
805
962
  var WIKIS_TTL_MS = 864e5;
963
+ var TEMPLATES_TTL_MS = 864e5;
806
964
 
807
965
  // src/resolvers/me.ts
808
966
  async function ensureMe(client) {
@@ -1182,7 +1340,7 @@ var projectListCommand = new import_commander5.Command("list").description("\uD5
1182
1340
  var import_commander6 = require("commander");
1183
1341
 
1184
1342
  // src/resolvers/match.ts
1185
- function matchByName(items, input2, label, renderCandidate) {
1343
+ function matchByName(items, input2, label, renderCandidate, options) {
1186
1344
  const exact = items.filter((i) => i.name === input2);
1187
1345
  if (exact.length === 1) return exact[0];
1188
1346
  if (exact.length > 1) {
@@ -1192,7 +1350,7 @@ function matchByName(items, input2, label, renderCandidate) {
1192
1350
  EXIT_PARAM_ERROR
1193
1351
  );
1194
1352
  }
1195
- const partial = items.filter((i) => i.name.includes(input2));
1353
+ const partial = items.filter((i) => !!i.name && i.name.includes(input2));
1196
1354
  if (partial.length === 1) return partial[0];
1197
1355
  if (partial.length > 1) {
1198
1356
  throw new DoorayCliError(
@@ -1201,13 +1359,26 @@ function matchByName(items, input2, label, renderCandidate) {
1201
1359
  EXIT_PARAM_ERROR
1202
1360
  );
1203
1361
  }
1362
+ const SAMPLE_LIMIT = 5;
1363
+ let counter = "";
1364
+ let hint = "";
1365
+ if (items.length > 0) {
1366
+ const sampleLines = items.slice(0, SAMPLE_LIMIT).map((i) => ` - ${renderCandidate(i)}`).join("\n");
1367
+ counter = `
1368
+ \uC0AC\uC6A9 \uAC00\uB2A5\uD55C ${label} (${Math.min(SAMPLE_LIMIT, items.length)}/${items.length}):
1369
+ ${sampleLines}`;
1370
+ hint = options?.helpHint ? `
1371
+ \uC804\uCCB4 \uBAA9\uB85D: ${options.helpHint}` : "";
1372
+ }
1204
1373
  throw new DoorayCliError(
1205
- `${label}\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2}`,
1374
+ `${label}\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2}${counter}${hint}`,
1206
1375
  EXIT_PARAM_ERROR
1207
1376
  );
1208
1377
  }
1209
1378
 
1210
1379
  // src/resolvers/member.ts
1380
+ var MEMBER_ID_RE = /^\d{15,}$/;
1381
+ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1211
1382
  async function fetchAllMembers(client, projectId) {
1212
1383
  const memberIds = [];
1213
1384
  let page = 0;
@@ -1257,6 +1428,38 @@ async function buildMemberNameMap(client, projectId) {
1257
1428
  return map;
1258
1429
  }
1259
1430
  async function resolveMember(client, projectId, input2) {
1431
+ if (MEMBER_ID_RE.test(input2)) {
1432
+ try {
1433
+ await client.getMemberDetail(input2);
1434
+ return input2;
1435
+ } catch (err) {
1436
+ if (err instanceof DoorayCliError && err.exitCode === EXIT_API_ERROR) {
1437
+ throw new DoorayCliError(
1438
+ `organizationMemberId \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2} (\uC6D0\uC778: ${err.message})`,
1439
+ EXIT_PARAM_ERROR
1440
+ );
1441
+ }
1442
+ throw err;
1443
+ }
1444
+ }
1445
+ if (EMAIL_RE.test(input2)) {
1446
+ const res = await client.searchMembers({ externalEmailAddresses: input2 });
1447
+ const hits = res.result;
1448
+ if (hits.length === 0) {
1449
+ throw new DoorayCliError(
1450
+ `\uC774\uBA54\uC77C\uB85C \uBA64\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2}`,
1451
+ EXIT_PARAM_ERROR
1452
+ );
1453
+ }
1454
+ if (hits.length > 1) {
1455
+ throw new DoorayCliError(
1456
+ `\uBCF5\uC218\uC758 \uBA64\uBC84\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4(\uC774\uBA54\uC77C): "${input2}"
1457
+ ` + hits.map((m) => ` - ${m.name} (${m.id})`).join("\n"),
1458
+ EXIT_PARAM_ERROR
1459
+ );
1460
+ }
1461
+ return hits[0].id;
1462
+ }
1260
1463
  const members = await ensureMembers(client, projectId);
1261
1464
  const match = matchByName(
1262
1465
  members,
@@ -1368,10 +1571,23 @@ async function ensureMemberGroups(client, projectId) {
1368
1571
  await setMemberGroups(projectId, items);
1369
1572
  return items;
1370
1573
  }
1574
+ function hasValidCode(g) {
1575
+ return typeof g.code === "string" && g.code.length > 0;
1576
+ }
1371
1577
  async function resolveMemberGroup(client, projectId, input2) {
1372
1578
  const groups = await ensureMemberGroups(client, projectId);
1373
- const adapter = groups.map((g) => ({ name: g.code, id: g.id, code: g.code }));
1374
- const match = matchByName(adapter, input2, "\uADF8\uB8F9", (g) => `${g.code} (${g.id})`);
1579
+ const valid = groups.filter(hasValidCode);
1580
+ const skipped = groups.length - valid.length;
1581
+ if (skipped > 0) {
1582
+ process.stderr.write(
1583
+ `\u26A0 ${skipped}\uAC1C \uADF8\uB8F9\uC5D0 code \uAC00 \uC5C6\uC5B4 \uB9E4\uCE6D\uC5D0\uC11C \uC81C\uC678\uD588\uC2B5\uB2C8\uB2E4 (Dooray API \uC751\uB2F5 mismatch \u2014 ADR-026).
1584
+ `
1585
+ );
1586
+ }
1587
+ const adapter = valid.map((g) => ({ name: g.code, id: g.id, code: g.code }));
1588
+ const match = matchByName(adapter, input2, "\uADF8\uB8F9", (g) => `${g.code} (${g.id})`, {
1589
+ helpHint: "dooray project groups <project>"
1590
+ });
1375
1591
  return { id: match.id, code: match.code };
1376
1592
  }
1377
1593
 
@@ -1386,7 +1602,7 @@ var projectGroupsCommand = new import_commander8.Command("groups").description("
1386
1602
  stopSpinner(true, "\uBA64\uBC84 \uADF8\uB8F9 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
1387
1603
  output(globalOpts, {
1388
1604
  headers: ["ID", "Code"],
1389
- rows: groups.map((g) => [g.id, g.code]),
1605
+ rows: groups.map((g) => [g.id, g.code ?? "-"]),
1390
1606
  raw: groups,
1391
1607
  ids: groups.map((g) => g.id)
1392
1608
  });
@@ -1503,6 +1719,63 @@ async function resolveTags(client, projectId, inputs) {
1503
1719
  }
1504
1720
  return selected.map((t) => t.id);
1505
1721
  }
1722
+ async function lookupTagIds(client, projectId, names) {
1723
+ if (names.length === 0) return [];
1724
+ const tags = await ensureTags(client, projectId);
1725
+ return names.map(
1726
+ (n) => matchByName(
1727
+ tags,
1728
+ n,
1729
+ "\uD0DC\uADF8",
1730
+ (t) => t.groupName ? `${t.groupName} / ${t.name} (${t.id})` : `${t.name} (${t.id})`
1731
+ ).id
1732
+ );
1733
+ }
1734
+ async function validateMandatoryCoverage(client, projectId, selectedTagIds) {
1735
+ const tags = await ensureTags(client, projectId);
1736
+ const selectedSet = new Set(selectedTagIds);
1737
+ const mandatoryGroups = /* @__PURE__ */ new Map();
1738
+ for (const t of tags) {
1739
+ if (!t.groupMandatory || !t.groupId) continue;
1740
+ let group = mandatoryGroups.get(t.groupId);
1741
+ if (!group) {
1742
+ group = { groupName: t.groupName ?? `\uADF8\uB8F9 ${t.groupId}`, tagsInGroup: [] };
1743
+ mandatoryGroups.set(t.groupId, group);
1744
+ }
1745
+ group.tagsInGroup.push(t);
1746
+ }
1747
+ for (const [, info] of mandatoryGroups) {
1748
+ const covered = info.tagsInGroup.some((t) => selectedSet.has(t.id));
1749
+ if (!covered) {
1750
+ const candidates = info.tagsInGroup.map((t) => `${t.name} (${t.id})`).join(", ");
1751
+ throw new DoorayCliError(
1752
+ `\uD544\uC218 \uD0DC\uADF8 \uADF8\uB8F9 "${info.groupName}" \uC5D0\uC11C \uCD5C\uC18C 1\uAC1C \uC120\uD0DD \uD544\uC694
1753
+ \uD6C4\uBCF4: ${candidates}`,
1754
+ EXIT_PARAM_ERROR
1755
+ );
1756
+ }
1757
+ }
1758
+ const selectOneGroups = /* @__PURE__ */ new Map();
1759
+ for (const t of tags) {
1760
+ if (!t.groupSelectOne || !t.groupId || !selectedSet.has(t.id)) continue;
1761
+ const entry = selectOneGroups.get(t.groupId) ?? { name: t.groupName ?? `\uADF8\uB8F9 ${t.groupId}`, tags: [] };
1762
+ entry.tags.push(t.name);
1763
+ selectOneGroups.set(t.groupId, entry);
1764
+ }
1765
+ const violators = [];
1766
+ for (const [, info] of selectOneGroups) {
1767
+ if (info.tags.length > 1) {
1768
+ violators.push(`${info.name} (\uC120\uD0DD: ${info.tags.join(", ")})`);
1769
+ }
1770
+ }
1771
+ if (violators.length > 0) {
1772
+ throw new DoorayCliError(
1773
+ `\uB2E4\uC74C \uD0DC\uADF8 \uADF8\uB8F9\uC740 1\uAC1C\uB9CC \uC120\uD0DD \uAC00\uB2A5\uD569\uB2C8\uB2E4:
1774
+ ` + violators.map((v) => ` - ${v}`).join("\n"),
1775
+ EXIT_PARAM_ERROR
1776
+ );
1777
+ }
1778
+ }
1506
1779
 
1507
1780
  // src/commands/project/tags.ts
1508
1781
  var projectTagsCommand = new import_commander9.Command("tags").description("\uD504\uB85C\uC81D\uD2B8 \uD0DC\uADF8 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
@@ -1527,9 +1800,70 @@ var projectTagsCommand = new import_commander9.Command("tags").description("\uD5
1527
1800
  });
1528
1801
  });
1529
1802
 
1530
- // src/commands/post/list.ts
1803
+ // src/commands/project/templates.ts
1531
1804
  var import_commander10 = require("commander");
1532
1805
 
1806
+ // src/resolvers/template.ts
1807
+ var TEMPLATE_ID_RE = /^\d{15,}$/;
1808
+ async function fetchAllTemplates(client, projectId) {
1809
+ const all = [];
1810
+ let page = 0;
1811
+ const size = RESOLVER_FETCH_PAGE_SIZE;
1812
+ while (true) {
1813
+ const res = await client.getProjectTemplates(projectId, { page, size });
1814
+ for (const t of res.result) {
1815
+ all.push({ id: t.id, templateName: t.templateName });
1816
+ }
1817
+ const total = res.totalCount ?? all.length;
1818
+ if (all.length >= total) break;
1819
+ page++;
1820
+ }
1821
+ return all;
1822
+ }
1823
+ async function ensureTemplates(client, projectId) {
1824
+ const entry = await getTemplates(projectId);
1825
+ if (entry && !isExpired(entry.updatedAt, TEMPLATES_TTL_MS)) return entry.data;
1826
+ const items = await fetchAllTemplates(client, projectId);
1827
+ await setTemplates(projectId, items);
1828
+ return items;
1829
+ }
1830
+ async function resolveTemplate(client, projectId, input2) {
1831
+ if (TEMPLATE_ID_RE.test(input2)) return input2;
1832
+ const templates = await ensureTemplates(client, projectId);
1833
+ const match = matchByName(
1834
+ templates.map((t) => ({ name: t.templateName, id: t.id })),
1835
+ input2,
1836
+ "\uD15C\uD50C\uB9BF",
1837
+ (t) => `${t.name} (${t.id})`
1838
+ );
1839
+ return match.id;
1840
+ }
1841
+
1842
+ // src/commands/project/templates.ts
1843
+ var projectTemplatesCommand = new import_commander10.Command("templates").description("\uD504\uB85C\uC81D\uD2B8 \uD15C\uD50C\uB9BF \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
1844
+ const globalOpts = projectTemplatesCommand.optsWithGlobals();
1845
+ const config = await getConfigOrThrow();
1846
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1847
+ startSpinner("\uD15C\uD50C\uB9BF \uBAA9\uB85D \uC870\uD68C \uC911...");
1848
+ try {
1849
+ const projectId = await resolveProject(client, project);
1850
+ const templates = await ensureTemplates(client, projectId);
1851
+ stopSpinner(true, "\uD15C\uD50C\uB9BF \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
1852
+ output(globalOpts, {
1853
+ headers: ["ID", "Template Name"],
1854
+ rows: templates.map((t) => [t.id, t.templateName]),
1855
+ raw: templates,
1856
+ ids: templates.map((t) => t.id)
1857
+ });
1858
+ } catch (e) {
1859
+ stopSpinner(false);
1860
+ throw e;
1861
+ }
1862
+ });
1863
+
1864
+ // src/commands/post/list.ts
1865
+ var import_commander11 = require("commander");
1866
+
1533
1867
  // src/formatters/post.ts
1534
1868
  function formatPostList(posts, opts) {
1535
1869
  output(opts, {
@@ -1579,7 +1913,7 @@ function formatCommentList(comments, opts) {
1579
1913
  }
1580
1914
 
1581
1915
  // src/commands/post/list.ts
1582
- var postListCommand = new import_commander10.Command("list").description("\uC5C5\uBB34 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--subject <keyword>", "\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC \uD544\uD130\uB9C1").option("--all", "\uC804\uCCB4 \uD398\uC774\uC9C0\uB124\uC774\uC158 (\uBAA8\uB4E0 \uACB0\uACFC \uC870\uD68C)").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (project, opts) => {
1916
+ var postListCommand = new import_commander11.Command("list").description("\uC5C5\uBB34 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--subject <keyword>", "\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC \uD544\uD130\uB9C1").option("--all", "\uC804\uCCB4 \uD398\uC774\uC9C0\uB124\uC774\uC158 (\uBAA8\uB4E0 \uACB0\uACFC \uC870\uD68C)").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (project, opts) => {
1583
1917
  const globalOpts = postListCommand.optsWithGlobals();
1584
1918
  const config = await getConfigOrThrow();
1585
1919
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1613,8 +1947,8 @@ var postListCommand = new import_commander10.Command("list").description("\uC5C5
1613
1947
  });
1614
1948
 
1615
1949
  // src/commands/post/search.ts
1616
- var import_commander11 = require("commander");
1617
- var postSearchCommand = new import_commander11.Command("search").description("\uC5C5\uBB34 \uAC80\uC0C9 (\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<keyword>", "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC").action(async (project, keyword) => {
1950
+ var import_commander12 = require("commander");
1951
+ var postSearchCommand = new import_commander12.Command("search").description("\uC5C5\uBB34 \uAC80\uC0C9 (\uC81C\uBAA9 \uD0A4\uC6CC\uB4DC)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<keyword>", "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC").action(async (project, keyword) => {
1618
1952
  const globalOpts = postSearchCommand.optsWithGlobals();
1619
1953
  const config = await getConfigOrThrow();
1620
1954
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1626,7 +1960,7 @@ var postSearchCommand = new import_commander11.Command("search").description("\u
1626
1960
  });
1627
1961
 
1628
1962
  // src/commands/post/get.ts
1629
- var import_commander12 = require("commander");
1963
+ var import_commander13 = require("commander");
1630
1964
 
1631
1965
  // src/resolvers/post.ts
1632
1966
  async function resolvePost(client, projectId, postNumber) {
@@ -1645,6 +1979,7 @@ async function resolvePost(client, projectId, postNumber) {
1645
1979
  // src/utils/dooray-url.ts
1646
1980
  var TASK_URL_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/task\/to\/(\d+)(?:[/?#].*)?$/;
1647
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+)(?:[/?#].*)?$/;
1648
1983
  function parseDoorayTaskUrl(input2) {
1649
1984
  const m1 = TASK_URL_RE.exec(input2);
1650
1985
  if (m1) return m1[1];
@@ -1652,6 +1987,11 @@ function parseDoorayTaskUrl(input2) {
1652
1987
  if (m2) return m2[1];
1653
1988
  return null;
1654
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
+ }
1655
1995
  function isLikelyDoorayUrl(input2) {
1656
1996
  return /^https?:\/\//.test(input2);
1657
1997
  }
@@ -1724,7 +2064,7 @@ async function resolvePostInput(client, args) {
1724
2064
  }
1725
2065
 
1726
2066
  // src/commands/post/get.ts
1727
- var postGetCommand = new import_commander12.Command("get").description("\uC5C5\uBB34 \uC0C1\uC138 \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
2067
+ var postGetCommand = new import_commander13.Command("get").description("\uC5C5\uBB34 \uC0C1\uC138 \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
1728
2068
  const globalOpts = postGetCommand.optsWithGlobals();
1729
2069
  const config = await getConfigOrThrow();
1730
2070
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1741,7 +2081,7 @@ var postGetCommand = new import_commander12.Command("get").description("\uC5C5\u
1741
2081
  });
1742
2082
 
1743
2083
  // src/commands/post/edit.ts
1744
- var import_commander13 = require("commander");
2084
+ var import_commander14 = require("commander");
1745
2085
 
1746
2086
  // src/utils/mention.ts
1747
2087
  function buildMemberMention(m, me) {
@@ -1867,6 +2207,31 @@ async function resolveUserAdditions(client, projectId, names, groupCodes) {
1867
2207
  return parseUserSpec(memberIds, groupIds);
1868
2208
  }
1869
2209
 
2210
+ // src/resolvers/post-tags.ts
2211
+ function mergeTagIds(existing, additions, removals, clear) {
2212
+ const base = clear ? [] : existing;
2213
+ const afterRemove = removals.length > 0 ? base.filter((id) => !removals.includes(id)) : base;
2214
+ if (additions.length === 0) return afterRemove;
2215
+ return Array.from(/* @__PURE__ */ new Set([...afterRemove, ...additions]));
2216
+ }
2217
+
2218
+ // src/resolvers/postRef.ts
2219
+ async function resolvePostRef(client, ref) {
2220
+ if (ref.includes("/")) {
2221
+ const [code, numStr] = ref.split("/", 2);
2222
+ const num = Number(numStr);
2223
+ if (!code || !Number.isFinite(num) || num <= 0) {
2224
+ throw new DoorayCliError(
2225
+ `--parent \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${ref}" (\uC608: "my-project/337" \uB610\uB294 raw postId)`,
2226
+ EXIT_PARAM_ERROR
2227
+ );
2228
+ }
2229
+ const projectId = await resolveProject(client, code);
2230
+ return resolvePost(client, projectId, num);
2231
+ }
2232
+ return ref;
2233
+ }
2234
+
1870
2235
  // src/editor/index.ts
1871
2236
  var import_node_child_process = require("child_process");
1872
2237
  var import_promises6 = __toESM(require("fs/promises"));
@@ -2100,7 +2465,7 @@ async function resolveUsers(client, projectId, names) {
2100
2465
  }
2101
2466
  return users;
2102
2467
  }
2103
- var postEditCommand = new import_commander13.Command("edit").description("\uC5C5\uBB34 \uC218\uC815 ($EDITOR \uB610\uB294 --title/--body \uC635\uC158)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--title <title>", "\uC81C\uBAA9 \uBCC0\uACBD (non-interactive)").option("--subject <subject>", "--title\uC758 deprecated alias").option("--body <text>", "\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)").option("--mention <name>", "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--mention-group <code>", "\uADF8\uB8F9 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, code \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--link-task <ref>", "\uB2E4\uB978 \uC5C5\uBB34 \uB9C1\uD06C \uCD94\uAC00 (<project>/<number> \uB610\uB294 postId, \uBC18\uBCF5 \uAC00\uB2A5)", (v, prev) => [...prev, v], []).option("--cc <name>", "\uCC38\uC870\uC790(cc) \uBA64\uBC84 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc-group <code>", "\uCC38\uC870\uC790(cc) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc-clear", "\uAE30\uC874 \uCC38\uC870\uC790 \uC804\uBD80 \uC81C\uAC70 \uD6C4 \uC2E0\uADDC\uB9CC \uC801\uC6A9 (--cc/--cc-group \uC640 \uC870\uD569 \uAC00\uB2A5)").option("--to <name>", "\uB2F4\uB2F9\uC790(to) \uBA64\uBC84 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--to-group <code>", "\uB2F4\uB2F9\uC790(to) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--to-clear", "\uAE30\uC874 \uB2F4\uB2F9\uC790 \uC804\uBD80 \uC81C\uAC70 \uD6C4 \uC2E0\uADDC\uB9CC \uC801\uC6A9").option("--dry-run", "API \uD638\uCD9C \uC5C6\uC774 \uD569\uC131\uB41C \uBCF8\uBB38\uB9CC stdout \uCD9C\uB825 (mention/link-task \uC801\uC6A9 \uACB0\uACFC \uBBF8\uB9AC\uBCF4\uAE30)").option("--no-confirm", "\uB204\uB77D attachment \uACBD\uACE0 \uC2DC confirm \uC5C6\uC774 \uC9C4\uD589 (\uC790\uB3D9\uD654\uC6A9)").action(async (project, postNumberStr, opts) => {
2468
+ var postEditCommand = new import_commander14.Command("edit").description("\uC5C5\uBB34 \uC218\uC815 ($EDITOR \uB610\uB294 --title/--body \uC635\uC158)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--title <title>", "\uC81C\uBAA9 \uBCC0\uACBD (non-interactive)").option("--subject <subject>", "--title\uC758 deprecated alias").option("--body <text>", "\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)").option("--mention <name>", "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--mention-group <code>", "\uADF8\uB8F9 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, code \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--link-task <ref>", "\uB2E4\uB978 \uC5C5\uBB34 \uB9C1\uD06C \uCD94\uAC00 (<project>/<number> \uB610\uB294 postId, \uBC18\uBCF5 \uAC00\uB2A5)", (v, prev) => [...prev, v], []).option("--cc <name>", "\uCC38\uC870\uC790(cc) \uBA64\uBC84 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc-group <code>", "\uCC38\uC870\uC790(cc) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc-clear", "\uAE30\uC874 \uCC38\uC870\uC790 \uC804\uBD80 \uC81C\uAC70 \uD6C4 \uC2E0\uADDC\uB9CC \uC801\uC6A9 (--cc/--cc-group \uC640 \uC870\uD569 \uAC00\uB2A5)").option("--to <name>", "\uB2F4\uB2F9\uC790(to) \uBA64\uBC84 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--to-group <code>", "\uB2F4\uB2F9\uC790(to) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--to-clear", "\uAE30\uC874 \uB2F4\uB2F9\uC790 \uC804\uBD80 \uC81C\uAC70 \uD6C4 \uC2E0\uADDC\uB9CC \uC801\uC6A9").option("--parent <ref>", "\uC0C1\uC704 \uC5C5\uBB34 \uBCC0\uACBD \u2014 project/number \uB610\uB294 raw postId (post create \uC640 \uB3D9\uC77C \u2014 unset \uC740 \uBBF8\uC9C0\uC6D0, \uC6F9 UI \uC5D0\uC11C \uCC98\uB9AC)").option("--tag <name>", "\uD0DC\uADF8 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uAE30\uC874 \uD0DC\uADF8 \uC720\uC9C0 + \uC2E0\uADDC \uCD94\uAC00 + dedupe)", (v, prev) => [...prev, v], []).option("--tag-clear", "\uAE30\uC874 \uD0DC\uADF8 \uC804\uBD80 \uC81C\uAC70 \uD6C4 --tag \uB9CC \uC801\uC6A9").option("--tag-remove <name>", "\uD2B9\uC815 \uD0DC\uADF8 \uC81C\uAC70 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--dry-run", "API \uD638\uCD9C \uC5C6\uC774 \uD569\uC131\uB41C \uBCF8\uBB38\uB9CC stdout \uCD9C\uB825 (mention/link-task \uC801\uC6A9 \uACB0\uACFC \uBBF8\uB9AC\uBCF4\uAE30)").option("--no-confirm", "\uB204\uB77D attachment \uACBD\uACE0 \uC2DC confirm \uC5C6\uC774 \uC9C4\uD589 (\uC790\uB3D9\uD654\uC6A9)").action(async (project, postNumberStr, opts) => {
2104
2469
  const config = await getConfigOrThrow();
2105
2470
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2106
2471
  const mentionInputs = (opts.mention ?? []).filter((s) => s.length > 0);
@@ -2110,6 +2475,9 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2110
2475
  const ccGroups = (opts.ccGroup ?? []).filter((s) => s.length > 0);
2111
2476
  const toNames = (opts.to ?? []).filter((s) => s.length > 0);
2112
2477
  const toGroups = (opts.toGroup ?? []).filter((s) => s.length > 0);
2478
+ const tagAdditions = (opts.tag ?? []).filter((s) => s.length > 0);
2479
+ const tagRemovals = (opts.tagRemove ?? []).filter((s) => s.length > 0);
2480
+ const hasTagChange = tagAdditions.length > 0 || tagRemovals.length > 0 || !!opts.tagClear;
2113
2481
  startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
2114
2482
  const { projectId, postId, postNumber, projectCode } = await resolvePostInput(client, {
2115
2483
  projectArg: project,
@@ -2127,7 +2495,7 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2127
2495
  "\u26A0 --subject\uB294 deprecated\uC785\uB2C8\uB2E4. \uB300\uC2E0 --title\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.\n"
2128
2496
  );
2129
2497
  }
2130
- const nonInteractive = title || opts.body || opts.bodyFile;
2498
+ const nonInteractive = title || opts.body || opts.bodyFile || hasTagChange;
2131
2499
  if (nonInteractive) {
2132
2500
  let newBody = await readBodyInputOrNull(opts);
2133
2501
  if (newBody != null && !opts.dryRun) {
@@ -2179,12 +2547,25 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2179
2547
  const additions = await resolveUserAdditions(client, projectId, ccNames, ccGroups);
2180
2548
  ccUsers = mergeUsers(ccUsers, additions, !!opts.ccClear);
2181
2549
  }
2550
+ let finalTagIds;
2551
+ if (hasTagChange) {
2552
+ const existingTagIds = post.tags.map((t) => t.id);
2553
+ const additionIds = await lookupTagIds(client, projectId, tagAdditions);
2554
+ const removalIds = await lookupTagIds(client, projectId, tagRemovals);
2555
+ finalTagIds = mergeTagIds(existingTagIds, additionIds, removalIds, !!opts.tagClear);
2556
+ await validateMandatoryCoverage(client, projectId, finalTagIds);
2557
+ }
2182
2558
  if (opts.dryRun) {
2183
2559
  stopSpinner(false);
2184
2560
  const globalOpts = postEditCommand.optsWithGlobals();
2185
2561
  const previewBody = newBody ?? post.body.content;
2186
2562
  if (globalOpts.json) {
2187
- process.stdout.write(JSON.stringify({ body: previewBody, users: { to: toUsers, cc: ccUsers } }) + "\n");
2563
+ process.stdout.write(JSON.stringify({
2564
+ body: previewBody,
2565
+ users: { to: toUsers, cc: ccUsers },
2566
+ ...finalTagIds !== void 0 && { tagIds: finalTagIds },
2567
+ ...opts.parent && { parentChange: opts.parent }
2568
+ }) + "\n");
2188
2569
  } else {
2189
2570
  process.stdout.write(previewBody + "\n");
2190
2571
  }
@@ -2200,9 +2581,24 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2200
2581
  priority: post.priority,
2201
2582
  dueDate: post.dueDate,
2202
2583
  dueDateFlag: post.dueDateFlag,
2203
- users: { to: toUsers, cc: ccUsers }
2584
+ users: { to: toUsers, cc: ccUsers },
2585
+ ...finalTagIds !== void 0 && { tagIds: finalTagIds }
2204
2586
  });
2205
2587
  stopSpinner(true, "\uC5C5\uBB34 \uC218\uC815 \uC644\uB8CC");
2588
+ if (opts.parent) {
2589
+ startSpinner("\uC0C1\uC704 \uC5C5\uBB34 \uBCC0\uACBD \uC911...");
2590
+ try {
2591
+ const newParentPostId = await resolvePostRef(client, opts.parent);
2592
+ await client.setPostParent(projectId, postId, newParentPostId);
2593
+ stopSpinner(true, "\uC0C1\uC704 \uC5C5\uBB34 \uBCC0\uACBD \uC644\uB8CC");
2594
+ } catch (err) {
2595
+ stopSpinner(false, "\uC0C1\uC704 \uC5C5\uBB34 \uBCC0\uACBD \uC2E4\uD328");
2596
+ process.stderr.write(
2597
+ "\u26A0 \uBCF8\uBB38\uC740 \uC218\uC815\uB418\uC5C8\uC73C\uB098 \uC0C1\uC704 \uC5C5\uBB34 \uBCC0\uACBD\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uBCF8\uBB38 \uC7AC\uC2E4\uD589 \uAE08\uC9C0 \u2014 \uC6F9 UI \uB610\uB294 dooray post edit --parent \uB2E8\uB3C5 \uC7AC\uC2DC\uB3C4 \uAD8C\uC7A5.\n"
2598
+ );
2599
+ throw err;
2600
+ }
2601
+ }
2206
2602
  } else {
2207
2603
  if (mentionInputs.length > 0 || groupInputs.length > 0) {
2208
2604
  process.stderr.write(
@@ -2219,6 +2615,11 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2219
2615
  "\u26A0 --cc/--cc-group/--cc-clear/--to/--to-group/--to-clear \uB294 --title/--body \uC640 \uD568\uAED8 \uC0AC\uC6A9 \uC2DC\uC5D0\uB9CC \uC801\uC6A9\uB429\uB2C8\uB2E4.\n"
2220
2616
  );
2221
2617
  }
2618
+ if (opts.parent) {
2619
+ process.stderr.write(
2620
+ "\u26A0 --parent \uB294 --title/--body \uC640 \uD568\uAED8 \uC0AC\uC6A9 \uC2DC\uC5D0\uB9CC \uC801\uC6A9\uB429\uB2C8\uB2E4.\n"
2621
+ );
2622
+ }
2222
2623
  const original = serializePostFrontmatter(post, members);
2223
2624
  const edited = await openInEditor(original);
2224
2625
  if (original === edited) {
@@ -2246,7 +2647,7 @@ var postEditCommand = new import_commander13.Command("edit").description("\uC5C5
2246
2647
  });
2247
2648
 
2248
2649
  // src/commands/post/create.ts
2249
- var import_commander14 = require("commander");
2650
+ var import_commander15 = require("commander");
2250
2651
 
2251
2652
  // src/resolvers/milestone.ts
2252
2653
  async function fetchAllMilestones(client, projectId) {
@@ -2275,23 +2676,6 @@ async function resolveMilestone(client, projectId, input2) {
2275
2676
  return match.id;
2276
2677
  }
2277
2678
 
2278
- // src/resolvers/postRef.ts
2279
- async function resolvePostRef(client, ref) {
2280
- if (ref.includes("/")) {
2281
- const [code, numStr] = ref.split("/", 2);
2282
- const num = Number(numStr);
2283
- if (!code || !Number.isFinite(num) || num <= 0) {
2284
- throw new DoorayCliError(
2285
- `--parent \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${ref}" (\uC608: "tc-ocr/337" \uB610\uB294 raw postId)`,
2286
- EXIT_PARAM_ERROR
2287
- );
2288
- }
2289
- const projectId = await resolveProject(client, code);
2290
- return resolvePost(client, projectId, num);
2291
- }
2292
- return ref;
2293
- }
2294
-
2295
2679
  // src/commands/post/create.ts
2296
2680
  async function resolveUsers2(client, projectId, inputs) {
2297
2681
  const users = [];
@@ -2301,17 +2685,18 @@ async function resolveUsers2(client, projectId, inputs) {
2301
2685
  }
2302
2686
  return users;
2303
2687
  }
2304
- var postCreateCommand = new import_commander14.Command("create").description("\uC5C5\uBB34 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--title <title>", "\uC5C5\uBB34 \uC81C\uBAA9").option("--subject <subject>", "--title\uC758 deprecated alias").option("--to <members...>", "\uB2F4\uB2F9\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--to-group <code>", "\uB2F4\uB2F9\uC790(to) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc <members...>", "\uCC38\uC870\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--cc-group <code>", "\uCC38\uC870\uC790(cc) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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)").option("--priority <level>", "\uC6B0\uC120\uC21C\uC704 (highest, high, normal, low, lowest)", "normal").option("--due-date <date>", "\uB9C8\uAC10\uC77C (ISO 8601 \uD615\uC2DD)").option("--tag <name>", "\uD0DC\uADF8 \uC774\uB984 (\uBC18\uBCF5 \uAC00\uB2A5)", (value, prev) => [...prev, value], []).option("--mention <name>", "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--mention-group <code>", "\uADF8\uB8F9 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, code \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--link-task <ref>", "\uB2E4\uB978 \uC5C5\uBB34 \uB9C1\uD06C \uCD94\uAC00 (<project>/<number> \uB610\uB294 postId, \uBC18\uBCF5 \uAC00\uB2A5)", (v, prev) => [...prev, v], []).option("--parent <ref>", "\uBD80\uBAA8 \uC5C5\uBB34 (project/number \uB610\uB294 postId)").option("--workflow <name>", "\uCD08\uAE30 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 \uB610\uB294 class").option("--milestone <name>", "\uB9C8\uC77C\uC2A4\uD1A4 \uC774\uB984").option("--dry-run", "API \uD638\uCD9C \uC5C6\uC774 \uD569\uC131\uB41C \uBCF8\uBB38\uB9CC stdout \uCD9C\uB825 (mention/link-task \uC801\uC6A9 \uACB0\uACFC \uBBF8\uB9AC\uBCF4\uAE30)").action(async (project, opts) => {
2688
+ function postUserToCreate(u) {
2689
+ return {
2690
+ type: u.type,
2691
+ member: u.member,
2692
+ emailUser: u.emailUser,
2693
+ group: u.group
2694
+ };
2695
+ }
2696
+ var postCreateCommand = new import_commander15.Command("create").description("\uC5C5\uBB34 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--title <title>", "\uC5C5\uBB34 \uC81C\uBAA9").option("--subject <subject>", "--title\uC758 deprecated alias").option("--to <members...>", "\uB2F4\uB2F9\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--to-group <code>", "\uB2F4\uB2F9\uC790(to) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--cc <members...>", "\uCC38\uC870\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").option("--cc-group <code>", "\uCC38\uC870\uC790(cc) \uADF8\uB8F9 \uCD94\uAC00 (\uBC18\uBCF5 \uAC00\uB2A5, \uADF8\uB8F9 \uCF54\uB4DC \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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)").option("--priority <level>", "\uC6B0\uC120\uC21C\uC704 (highest, high, normal, low, lowest)", "normal").option("--due-date <date>", "\uB9C8\uAC10\uC77C (ISO 8601 \uD615\uC2DD)").option("--tag <name>", "\uD0DC\uADF8 \uC774\uB984 (\uBC18\uBCF5 \uAC00\uB2A5)", (value, prev) => [...prev, value], []).option("--mention <name>", "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--mention-group <code>", "\uADF8\uB8F9 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, code \uBD80\uBD84\uC77C\uCE58)", (v, prev) => [...prev, v], []).option("--link-task <ref>", "\uB2E4\uB978 \uC5C5\uBB34 \uB9C1\uD06C \uCD94\uAC00 (<project>/<number> \uB610\uB294 postId, \uBC18\uBCF5 \uAC00\uB2A5)", (v, prev) => [...prev, v], []).option("--parent <ref>", "\uBD80\uBAA8 \uC5C5\uBB34 (project/number \uB610\uB294 postId)").option("--template <ref>", "\uD15C\uD50C\uB9BF \uC774\uB984 \uB610\uB294 ID \u2014 body/users/tags \uC790\uB3D9 \uCC44\uC6C0 (\uC0AC\uC6A9\uC790 \uC635\uC158 \uC6B0\uC120 override, ADR-027)").option("--workflow <name>", "\uCD08\uAE30 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 \uB610\uB294 class").option("--milestone <name>", "\uB9C8\uC77C\uC2A4\uD1A4 \uC774\uB984").option("--dry-run", "API \uD638\uCD9C \uC5C6\uC774 \uD569\uC131\uB41C \uBCF8\uBB38\uB9CC stdout \uCD9C\uB825 (mention/link-task \uC801\uC6A9 \uACB0\uACFC \uBBF8\uB9AC\uBCF4\uAE30)").action(async (project, opts) => {
2305
2697
  const globalOpts = postCreateCommand.optsWithGlobals();
2306
2698
  const config = await getConfigOrThrow();
2307
2699
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2308
- const subject = opts.title ?? opts.subject;
2309
- if (!subject) {
2310
- throw new DoorayCliError(
2311
- "--title\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
2312
- EXIT_PARAM_ERROR
2313
- );
2314
- }
2315
2700
  if (opts.subject && !opts.title) {
2316
2701
  process.stderr.write(
2317
2702
  "\u26A0 --subject\uB294 deprecated\uC785\uB2C8\uB2E4. \uB300\uC2E0 --title\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.\n"
@@ -2320,16 +2705,42 @@ var postCreateCommand = new import_commander14.Command("create").description("\u
2320
2705
  const mentionInputs = (opts.mention ?? []).filter((s) => s.length > 0);
2321
2706
  const groupInputs = (opts.mentionGroup ?? []).filter((s) => s.length > 0);
2322
2707
  const linkInputs = (opts.linkTask ?? []).filter((s) => s.length > 0);
2323
- let bodyContent = await readBodyInput(opts);
2324
2708
  startSpinner("\uC5C5\uBB34 \uC0DD\uC131 \uC911...");
2325
2709
  const projectId = await resolveProject(client, project);
2326
- let projectCode;
2327
- if (groupInputs.length > 0) {
2328
- const projects = await ensureProjects(client);
2329
- projectCode = projects.find((p) => p.id === projectId)?.code;
2330
- if (!projectCode) {
2331
- throw new DoorayCliError(
2332
- `--mention-group \uC740 \uACF5\uAC1C \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C\uB9CC \uC9C0\uC6D0\uB429\uB2C8\uB2E4. dooray project list \uB85C \uCE90\uC2DC \uAC31\uC2E0 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694.`,
2710
+ let templateDetail = null;
2711
+ if (opts.template) {
2712
+ try {
2713
+ const templateId = await resolveTemplate(client, projectId, opts.template);
2714
+ const res2 = await client.getProjectTemplateDetail(projectId, templateId, true);
2715
+ templateDetail = res2.result;
2716
+ } catch (e) {
2717
+ stopSpinner(false);
2718
+ throw e;
2719
+ }
2720
+ }
2721
+ const subject = opts.title ?? opts.subject ?? templateDetail?.subject;
2722
+ if (!subject) {
2723
+ stopSpinner(false);
2724
+ const msg = opts.template ? `--template "${opts.template}" \uC5D0 \uC81C\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. --title \uB85C \uC9C0\uC815\uD558\uC138\uC694.` : "--title \uB610\uB294 --template \uB458 \uC911 \uD558\uB098 \uD544\uC694\uD569\uB2C8\uB2E4.";
2725
+ throw new DoorayCliError(msg, EXIT_PARAM_ERROR);
2726
+ }
2727
+ let bodyContent;
2728
+ try {
2729
+ bodyContent = await readBodyInput(opts);
2730
+ } catch (e) {
2731
+ stopSpinner(false);
2732
+ throw e;
2733
+ }
2734
+ if (!bodyContent && templateDetail?.body) {
2735
+ bodyContent = templateDetail.body.content;
2736
+ }
2737
+ let projectCode;
2738
+ if (groupInputs.length > 0) {
2739
+ const projects = await ensureProjects(client);
2740
+ projectCode = projects.find((p) => p.id === projectId)?.code;
2741
+ if (!projectCode) {
2742
+ throw new DoorayCliError(
2743
+ `--mention-group \uC740 \uACF5\uAC1C \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C\uB9CC \uC9C0\uC6D0\uB429\uB2C8\uB2E4. dooray project list \uB85C \uCE90\uC2DC \uAC31\uC2E0 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694.`,
2333
2744
  EXIT_PARAM_ERROR
2334
2745
  );
2335
2746
  }
@@ -2360,7 +2771,12 @@ var postCreateCommand = new import_commander14.Command("create").description("\u
2360
2771
  if (opts.dryRun) {
2361
2772
  stopSpinner(false);
2362
2773
  if (globalOpts.json) {
2363
- process.stdout.write(JSON.stringify({ body: bodyContent }) + "\n");
2774
+ process.stdout.write(
2775
+ JSON.stringify({
2776
+ body: bodyContent,
2777
+ ...opts.template && { templateUsed: opts.template }
2778
+ }) + "\n"
2779
+ );
2364
2780
  } else {
2365
2781
  process.stdout.write(bodyContent + "\n");
2366
2782
  }
@@ -2368,15 +2784,17 @@ var postCreateCommand = new import_commander14.Command("create").description("\u
2368
2784
  }
2369
2785
  const ccGroupCodes = (opts.ccGroup ?? []).filter((s) => s.length > 0);
2370
2786
  const toGroupCodes = (opts.toGroup ?? []).filter((s) => s.length > 0);
2371
- const toUsersMembers = opts.to ? await resolveUsers2(client, projectId, opts.to) : [];
2372
- const ccUsersMembers = opts.cc ? await resolveUsers2(client, projectId, opts.cc) : [];
2787
+ const toUsersMembers = opts.to ? await resolveUsers2(client, projectId, opts.to) : (templateDetail?.users?.to ?? []).map(postUserToCreate);
2788
+ const ccUsersMembers = opts.cc ? await resolveUsers2(client, projectId, opts.cc) : (templateDetail?.users?.cc ?? []).map(postUserToCreate);
2373
2789
  const toUsersGroups = toGroupCodes.length > 0 ? await resolveUserAdditions(client, projectId, [], toGroupCodes) : [];
2374
2790
  const ccUsersGroups = ccGroupCodes.length > 0 ? await resolveUserAdditions(client, projectId, [], ccGroupCodes) : [];
2375
2791
  const toUsers = [...toUsersMembers, ...toUsersGroups];
2376
2792
  const ccUsers = [...ccUsersMembers, ...ccUsersGroups];
2377
2793
  const tagInputs = (opts.tag ?? []).filter((s) => s.length > 0);
2794
+ const templateTagNames = (templateDetail?.tags ?? []).map((t) => t.name).filter((n) => !!n);
2795
+ const effectiveTagInputs = tagInputs.length > 0 ? tagInputs : templateTagNames;
2378
2796
  const [tagIds, parentPostId, milestoneId] = await Promise.all([
2379
- tagInputs.length > 0 ? resolveTags(client, projectId, tagInputs) : validateMandatoryTags(client, projectId).then(() => void 0),
2797
+ effectiveTagInputs.length > 0 ? resolveTags(client, projectId, effectiveTagInputs) : validateMandatoryTags(client, projectId).then(() => void 0),
2380
2798
  opts.parent ? resolvePostRef(client, opts.parent) : Promise.resolve(void 0),
2381
2799
  opts.milestone ? resolveMilestone(client, projectId, opts.milestone) : Promise.resolve(void 0)
2382
2800
  ]);
@@ -2412,8 +2830,8 @@ var postCreateCommand = new import_commander14.Command("create").description("\u
2412
2830
  });
2413
2831
 
2414
2832
  // src/commands/post/done.ts
2415
- var import_commander15 = require("commander");
2416
- var postDoneCommand = new import_commander15.Command("done").description("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
2833
+ var import_commander16 = require("commander");
2834
+ var postDoneCommand = new import_commander16.Command("done").description("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
2417
2835
  const config = await getConfigOrThrow();
2418
2836
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2419
2837
  startSpinner("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC911...");
@@ -2430,8 +2848,8 @@ var postDoneCommand = new import_commander15.Command("done").description("\uC5C5
2430
2848
  });
2431
2849
 
2432
2850
  // src/commands/post/workflow.ts
2433
- var import_commander16 = require("commander");
2434
- var postWorkflowCommand = new import_commander16.Command("workflow").description("\uC5C5\uBB34 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").argument("[workflow]", "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 \uB610\uB294 \uD074\uB798\uC2A4 (\uB610\uB294 --workflow \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--workflow <name>", "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 (positional \uB300\uCCB4)").action(async (project, postNumber, workflowArg, opts) => {
2851
+ var import_commander17 = require("commander");
2852
+ var postWorkflowCommand = new import_commander17.Command("workflow").description("\uC5C5\uBB34 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").argument("[workflow]", "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 \uB610\uB294 \uD074\uB798\uC2A4 (\uB610\uB294 --workflow \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--workflow <name>", "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC774\uB984 (positional \uB300\uCCB4)").action(async (project, postNumber, workflowArg, opts) => {
2435
2853
  const config = await getConfigOrThrow();
2436
2854
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2437
2855
  let workflowInput = opts.workflow;
@@ -2471,7 +2889,7 @@ var postWorkflowCommand = new import_commander16.Command("workflow").description
2471
2889
  });
2472
2890
 
2473
2891
  // src/commands/post/comment/list.ts
2474
- var import_commander17 = require("commander");
2892
+ var import_commander18 = require("commander");
2475
2893
 
2476
2894
  // src/utils/comment-enrich.ts
2477
2895
  function enrichCommentCreators(comments, nameMap) {
@@ -2548,7 +2966,7 @@ async function fetchSince(client, projectId, postId, sinceDate) {
2548
2966
  }
2549
2967
  return collected;
2550
2968
  }
2551
- var commentListCommand = new import_commander17.Command("list").description("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", PAGE_DEFAULT).option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", SIZE_DEFAULT).option("--sort <order>", "\uC815\uB82C (asc/desc), \uAE30\uBCF8 asc", "asc").option("--reverse", "--sort desc \uC758 alias").option("--latest <n>", "\uCD5C\uC2E0 N\uAC1C (--sort desc + size=N + page=0 \uB2E8\uCD95, \uCD5C\uB300 100)").option("--since <iso>", "\uC774 \uC2DC\uAC04 \uC774\uD6C4 \uB313\uAE00\uB9CC (ISO 8601 \uB610\uB294 YYYY-MM-DD)").option("--from-author <name>", "\uC791\uC131\uC790 \uC774\uB984\uC73C\uB85C \uD544\uD130 (\uBD80\uBD84\uC77C\uCE58)").action(async (project, postNumberStr, opts) => {
2969
+ var commentListCommand = new import_commander18.Command("list").description("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", PAGE_DEFAULT).option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", SIZE_DEFAULT).option("--sort <order>", "\uC815\uB82C (asc/desc), \uAE30\uBCF8 asc", "asc").option("--reverse", "--sort desc \uC758 alias").option("--latest <n>", "\uCD5C\uC2E0 N\uAC1C (--sort desc + size=N + page=0 \uB2E8\uCD95, \uCD5C\uB300 100)").option("--since <iso>", "\uC774 \uC2DC\uAC04 \uC774\uD6C4 \uB313\uAE00\uB9CC (ISO 8601 \uB610\uB294 YYYY-MM-DD)").option("--from-author <name>", "\uC791\uC131\uC790 \uC774\uB984\uC73C\uB85C \uD544\uD130 (\uBD80\uBD84\uC77C\uCE58)").action(async (project, postNumberStr, opts) => {
2552
2970
  const globalOpts = commentListCommand.optsWithGlobals();
2553
2971
  const config = await getConfigOrThrow();
2554
2972
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2610,8 +3028,8 @@ var commentListCommand = new import_commander17.Command("list").description("\uB
2610
3028
  });
2611
3029
 
2612
3030
  // src/commands/post/comment/latest.ts
2613
- var import_commander18 = require("commander");
2614
- var commentLatestCommand = new import_commander18.Command("latest").description("\uCD5C\uC2E0 \uB313\uAE00 1\uAC1C \uC870\uD68C (= comment list --latest 1)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("-n, --count <n>", "\uCD5C\uC2E0 N\uAC1C (\uAE30\uBCF8 1)", "1").action(async (project, postNumberStr, opts) => {
3031
+ var import_commander19 = require("commander");
3032
+ var commentLatestCommand = new import_commander19.Command("latest").description("\uCD5C\uC2E0 \uB313\uAE00 1\uAC1C \uC870\uD68C (= comment list --latest 1)").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("-n, --count <n>", "\uCD5C\uC2E0 N\uAC1C (\uAE30\uBCF8 1)", "1").action(async (project, postNumberStr, opts) => {
2615
3033
  const globalOpts = commentLatestCommand.optsWithGlobals();
2616
3034
  const config = await getConfigOrThrow();
2617
3035
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2648,8 +3066,8 @@ var commentLatestCommand = new import_commander18.Command("latest").description(
2648
3066
  });
2649
3067
 
2650
3068
  // src/commands/post/comment/add.ts
2651
- var import_commander19 = require("commander");
2652
- var commentAddCommand = new import_commander19.Command("add").description("\uB313\uAE00 \uCD94\uAC00").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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)").option(
3069
+ var import_commander20 = require("commander");
3070
+ var commentAddCommand = new import_commander20.Command("add").description("\uB313\uAE00 \uCD94\uAC00").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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)").option(
2653
3071
  "--mention <name>",
2654
3072
  "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)",
2655
3073
  (value, prev) => [...prev, value],
@@ -2728,8 +3146,8 @@ var commentAddCommand = new import_commander19.Command("add").description("\uB31
2728
3146
  });
2729
3147
 
2730
3148
  // src/commands/post/comment/edit.ts
2731
- var import_commander20 = require("commander");
2732
- var commentEditCommand = new import_commander20.Command("edit").description("\uB313\uAE00 \uC218\uC815 ($EDITOR \uB610\uB294 --body \uC635\uC158)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL / \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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)").option("--no-confirm", "\uB204\uB77D attachment \uACBD\uACE0 \uC2DC confirm \uC5C6\uC774 \uC9C4\uD589 (\uC790\uB3D9\uD654\uC6A9)").option(
3149
+ var import_commander21 = require("commander");
3150
+ var commentEditCommand = new import_commander21.Command("edit").description("\uB313\uAE00 \uC218\uC815 ($EDITOR \uB610\uB294 --body \uC635\uC158)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL / \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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)").option("--no-confirm", "\uB204\uB77D attachment \uACBD\uACE0 \uC2DC confirm \uC5C6\uC774 \uC9C4\uD589 (\uC790\uB3D9\uD654\uC6A9)").option(
2733
3151
  "--mention <name>",
2734
3152
  "\uBA64\uBC84 \uBA58\uC158 (\uBC18\uBCF5 \uAC00\uB2A5, \uC774\uB984 \uBD80\uBD84\uC77C\uCE58)",
2735
3153
  (value, prev) => [...prev, value],
@@ -2857,8 +3275,8 @@ var commentEditCommand = new import_commander20.Command("edit").description("\uB
2857
3275
  });
2858
3276
 
2859
3277
  // src/commands/post/comment/delete.ts
2860
- var import_commander21 = require("commander");
2861
- var commentDeleteCommand = new import_commander21.Command("delete").description("\uB313\uAE00 \uC0AD\uC81C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL / \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <commentId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3278
+ var import_commander22 = require("commander");
3279
+ var commentDeleteCommand = new import_commander22.Command("delete").description("\uB313\uAE00 \uC0AD\uC81C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL / \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 \uB313\uAE00 ID (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <commentId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
2862
3280
  const config = await getConfigOrThrow();
2863
3281
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2864
3282
  let projectArg;
@@ -2914,7 +3332,7 @@ var commentDeleteCommand = new import_commander21.Command("delete").description(
2914
3332
  });
2915
3333
 
2916
3334
  // src/commands/post/comment/get.ts
2917
- var import_commander22 = require("commander");
3335
+ var import_commander23 = require("commander");
2918
3336
 
2919
3337
  // src/formatters/comment.ts
2920
3338
  function formatCommentDetail(comment, opts) {
@@ -2988,7 +3406,7 @@ function parseGetArgs(arg1, arg2, arg3, opts) {
2988
3406
  EXIT_PARAM_ERROR
2989
3407
  );
2990
3408
  }
2991
- var commentGetCommand = new import_commander22.Command("get").description("\uB2E8\uC77C \uB313\uAE00 \uBCF8\uBB38 + \uBA54\uD0C0 + attachments \uC870\uD68C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (positional \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (positional \uB300\uC2E0)").option("--comment-id <id>", "\uB313\uAE00 ID (arg3 \uB300\uC2E0)").action(async (arg1, arg2, arg3, opts) => {
3409
+ var commentGetCommand = new import_commander23.Command("get").description("\uB2E8\uC77C \uB313\uAE00 \uBCF8\uBB38 + \uBA54\uD0C0 + attachments \uC870\uD68C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC / Dooray URL (\uBAA8\uB4DC\uBCC4)").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 (\uBAA8\uB4DC\uBCC4)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (positional \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (positional \uB300\uC2E0)").option("--comment-id <id>", "\uB313\uAE00 ID (arg3 \uB300\uC2E0)").action(async (arg1, arg2, arg3, opts) => {
2992
3410
  const parsed = parseGetArgs(arg1, arg2, arg3, opts);
2993
3411
  const config = await getConfigOrThrow();
2994
3412
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3023,10 +3441,10 @@ var commentGetCommand = new import_commander22.Command("get").description("\uB2E
3023
3441
  });
3024
3442
 
3025
3443
  // src/commands/post/comment/file/index.ts
3026
- var import_commander27 = require("commander");
3444
+ var import_commander28 = require("commander");
3027
3445
 
3028
3446
  // src/commands/post/comment/file/list.ts
3029
- var import_commander23 = require("commander");
3447
+ var import_commander24 = require("commander");
3030
3448
 
3031
3449
  // src/resolvers/comment-file-input.ts
3032
3450
  var FILE_ID_SECONDARY_LABEL = {
@@ -3101,7 +3519,7 @@ function formatSize(bytes) {
3101
3519
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
3102
3520
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
3103
3521
  }
3104
- var listCommentFileCommand = new import_commander23.Command("list").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 (positional \uBAA8\uB4DC)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3522
+ var listCommentFileCommand = new import_commander24.Command("list").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 (positional \uBAA8\uB4DC)").argument("[arg3]", "\uB313\uAE00 ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3105
3523
  const globalOpts = listCommentFileCommand.optsWithGlobals();
3106
3524
  const config = await getConfigOrThrow();
3107
3525
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3135,7 +3553,7 @@ var listCommentFileCommand = new import_commander23.Command("list").description(
3135
3553
  });
3136
3554
 
3137
3555
  // src/commands/post/comment/file/upload.ts
3138
- var import_commander24 = require("commander");
3556
+ var import_commander25 = require("commander");
3139
3557
  var import_node_path4 = require("path");
3140
3558
 
3141
3559
  // src/utils/comment-files.ts
@@ -3156,7 +3574,7 @@ function removeFileReference(body, fileId) {
3156
3574
  }
3157
3575
 
3158
3576
  // src/commands/post/comment/file/upload.ts
3159
- var uploadCommentFileCommand = new import_commander24.Command("upload").description("\uB313\uAE00\uC5D0 \uD30C\uC77C \uC5C5\uB85C\uB4DC (post-level \uD30C\uC77C \uC5C5\uB85C\uB4DC + \uB313\uAE00 reference \uCD94\uAC00, ADR-024)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg3]", "\uB313\uAE00 ID (positional \uBAA8\uB4DC)").argument("[arg4]", "\uD30C\uC77C \uACBD\uB85C (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--file <path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, arg4, opts) => {
3577
+ var uploadCommentFileCommand = new import_commander25.Command("upload").description("\uB313\uAE00\uC5D0 \uD30C\uC77C \uC5C5\uB85C\uB4DC (post-level \uD30C\uC77C \uC5C5\uB85C\uB4DC + \uB313\uAE00 reference \uCD94\uAC00, ADR-024)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg3]", "\uB313\uAE00 ID (positional \uBAA8\uB4DC)").argument("[arg4]", "\uD30C\uC77C \uACBD\uB85C (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--file <path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, arg4, opts) => {
3160
3578
  const globalOpts = uploadCommentFileCommand.optsWithGlobals();
3161
3579
  const config = await getConfigOrThrow();
3162
3580
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3205,10 +3623,10 @@ var uploadCommentFileCommand = new import_commander24.Command("upload").descript
3205
3623
  });
3206
3624
 
3207
3625
  // src/commands/post/comment/file/download.ts
3208
- var import_commander25 = require("commander");
3626
+ var import_commander26 = require("commander");
3209
3627
  var import_promises8 = require("fs/promises");
3210
3628
  var import_node_path5 = require("path");
3211
- var downloadCommentFileCommand = new import_commander25.Command("download").description(
3629
+ var downloadCommentFileCommand = new import_commander26.Command("download").description(
3212
3630
  "\uB313\uAE00\uC5D0 \uCCA8\uBD80\uB41C \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC (\uD604\uC7AC comment-id \uB294 \uBBF8\uC0AC\uC6A9 \u2014 \uBA58\uD0C8 \uBAA8\uB378 \uC77C\uAD00\uC131, \uBBF8\uB798 \uB313\uAE00 \uB2E8\uC704 \uAD8C\uD55C \uD638\uD658\uC6A9)"
3213
3631
  ).argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uB313\uAE00 ID (positional \uBAA8\uB4DC)").argument("[arg4]", "\uD30C\uC77C ID (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").option("--out <path>", "\uC800\uC7A5 \uACBD\uB85C (\uBBF8\uC9C0\uC815 \uC2DC \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0 \uC6D0\uBCF8 \uD30C\uC77C\uBA85\uC73C\uB85C \uC800\uC7A5)", ".").action(async (arg1, arg2, arg3, arg4, opts) => {
3214
3632
  const config = await getConfigOrThrow();
@@ -3236,8 +3654,8 @@ var downloadCommentFileCommand = new import_commander25.Command("download").desc
3236
3654
  });
3237
3655
 
3238
3656
  // src/commands/post/comment/file/delete.ts
3239
- var import_commander26 = require("commander");
3240
- var deleteCommentFileCommand = new import_commander26.Command("delete").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uC0AD\uC81C (\uB313\uAE00 \uBCF8\uBB38 reference \uC81C\uAC70 + \uD30C\uC77C \uC0AD\uC81C, ADR-024)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uB313\uAE00 ID (positional \uBAA8\uB4DC)").argument("[arg4]", "\uD30C\uC77C ID (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC0AD\uC81C").action(async (arg1, arg2, arg3, arg4, opts) => {
3657
+ var import_commander27 = require("commander");
3658
+ var deleteCommentFileCommand = new import_commander27.Command("delete").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uC0AD\uC81C (\uB313\uAE00 \uBCF8\uBB38 reference \uC81C\uAC70 + \uD30C\uC77C \uC0AD\uC81C, ADR-024)").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uB313\uAE00 ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uB313\uAE00 ID (positional \uBAA8\uB4DC)").argument("[arg4]", "\uD30C\uC77C ID (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--comment-id <logId>", "\uB313\uAE00 ID (positional \uB300\uCCB4)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC0AD\uC81C").action(async (arg1, arg2, arg3, arg4, opts) => {
3241
3659
  const config = await getConfigOrThrow();
3242
3660
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
3243
3661
  const { projectId, postId, commentId, secondary: fileId } = await resolveCommentFileInput(client, {
@@ -3294,16 +3712,16 @@ var deleteCommentFileCommand = new import_commander26.Command("delete").descript
3294
3712
  });
3295
3713
 
3296
3714
  // src/commands/post/comment/file/index.ts
3297
- var commentFileCommand = new import_commander27.Command("file").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uAD00\uB9AC (post-level files API + \uB313\uAE00 PUT \uD569\uC131, ADR-024)").addCommand(listCommentFileCommand).addCommand(uploadCommentFileCommand).addCommand(downloadCommentFileCommand).addCommand(deleteCommentFileCommand);
3715
+ var commentFileCommand = new import_commander28.Command("file").description("\uB313\uAE00 \uCCA8\uBD80 \uD30C\uC77C \uAD00\uB9AC (post-level files API + \uB313\uAE00 PUT \uD569\uC131, ADR-024)").addCommand(listCommentFileCommand).addCommand(uploadCommentFileCommand).addCommand(downloadCommentFileCommand).addCommand(deleteCommentFileCommand);
3298
3716
 
3299
3717
  // src/commands/post/file/list.ts
3300
- var import_commander28 = require("commander");
3718
+ var import_commander29 = require("commander");
3301
3719
  function formatSize2(bytes) {
3302
3720
  if (bytes < 1024) return `${bytes}B`;
3303
3721
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
3304
3722
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
3305
3723
  }
3306
- var fileListCommand = new import_commander28.Command("list").description("\uC5C5\uBB34 \uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
3724
+ var fileListCommand = new import_commander29.Command("list").description("\uC5C5\uBB34 \uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").action(async (project, postNumberStr, opts) => {
3307
3725
  const globalOpts = fileListCommand.optsWithGlobals();
3308
3726
  const config = await getConfigOrThrow();
3309
3727
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3331,10 +3749,10 @@ var fileListCommand = new import_commander28.Command("list").description("\uC5C5
3331
3749
  });
3332
3750
 
3333
3751
  // src/commands/post/file/download.ts
3334
- var import_commander29 = require("commander");
3752
+ var import_commander30 = require("commander");
3335
3753
  var import_promises9 = require("fs/promises");
3336
3754
  var import_node_path6 = require("path");
3337
- var fileDownloadCommand = new import_commander29.Command("download").description("\uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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) => {
3755
+ var fileDownloadCommand = new import_commander30.Command("download").description("\uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").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) => {
3338
3756
  const config = await getConfigOrThrow();
3339
3757
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
3340
3758
  let projectArg;
@@ -3389,10 +3807,10 @@ var fileDownloadCommand = new import_commander29.Command("download").description
3389
3807
  });
3390
3808
 
3391
3809
  // src/commands/post/file/download-all.ts
3392
- var import_commander30 = require("commander");
3810
+ var import_commander31 = require("commander");
3393
3811
  var import_promises10 = require("fs/promises");
3394
3812
  var import_node_path7 = require("path");
3395
- var fileDownloadAllCommand = new import_commander30.Command("download-all").description("\uC5C5\uBB34\uC758 \uBAA8\uB4E0 \uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (project, postNumberStr, opts) => {
3813
+ var fileDownloadAllCommand = new import_commander31.Command("download-all").description("\uC5C5\uBB34\uC758 \uBAA8\uB4E0 \uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("[project]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC (\uB610\uB294 \uCCAB \uC778\uC790\uC5D0 Dooray URL)").argument("[post-number]", "\uC5C5\uBB34 \uBC88\uD638 (project\uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (project, postNumberStr, opts) => {
3396
3814
  const config = await getConfigOrThrow();
3397
3815
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
3398
3816
  const spinner = startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
@@ -3425,9 +3843,9 @@ var fileDownloadAllCommand = new import_commander30.Command("download-all").desc
3425
3843
  });
3426
3844
 
3427
3845
  // src/commands/post/file/upload.ts
3428
- var import_commander31 = require("commander");
3846
+ var import_commander32 = require("commander");
3429
3847
  var import_node_path8 = require("path");
3430
- var fileUploadCommand = new import_commander31.Command("upload").description("\uCCA8\uBD80\uD30C\uC77C \uC5C5\uB85C\uB4DC").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg3]", "\uD30C\uC77C \uACBD\uB85C (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--file <path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3848
+ var fileUploadCommand = new import_commander32.Command("upload").description("\uCCA8\uBD80\uD30C\uC77C \uC5C5\uB85C\uB4DC").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C \uACBD\uB85C").argument("[arg3]", "\uD30C\uC77C \uACBD\uB85C (positional \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--file <path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3431
3849
  const globalOpts = fileUploadCommand.optsWithGlobals();
3432
3850
  const config = await getConfigOrThrow();
3433
3851
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3488,8 +3906,8 @@ var fileUploadCommand = new import_commander31.Command("upload").description("\u
3488
3906
  });
3489
3907
 
3490
3908
  // src/commands/post/file/delete.ts
3491
- var import_commander32 = require("commander");
3492
- var fileDeleteCommand = new import_commander32.Command("delete").description("\uCCA8\uBD80\uD30C\uC77C \uC0AD\uC81C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3909
+ var import_commander33 = require("commander");
3910
+ var fileDeleteCommand = new import_commander33.Command("delete").description("\uCCA8\uBD80\uD30C\uC77C \uC0AD\uC81C").argument("[arg1]", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC, Dooray URL, \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg2]", "\uC5C5\uBB34 \uBC88\uD638 \uB610\uB294 (`--id`/`--url` \uBAA8\uB4DC\uC77C \uB54C) \uD30C\uC77C ID").argument("[arg3]", "\uD30C\uC77C ID (positional 3\uAC1C \uBAA8\uB4DC)").option("--id <postId>", "Dooray post ID (project/post-number \uB300\uC2E0)").option("--url <url>", "Dooray \uC5C5\uBB34 URL (project/post-number \uB300\uC2E0)").option("--file-id <fileId>", "\uD30C\uC77C ID (positional \uB300\uCCB4)").action(async (arg1, arg2, arg3, opts) => {
3493
3911
  const config = await getConfigOrThrow();
3494
3912
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
3495
3913
  let projectArg;
@@ -3542,7 +3960,7 @@ var fileDeleteCommand = new import_commander32.Command("delete").description("\u
3542
3960
  });
3543
3961
 
3544
3962
  // src/commands/wiki/list.ts
3545
- var import_commander33 = require("commander");
3963
+ var import_commander34 = require("commander");
3546
3964
 
3547
3965
  // src/formatters/wiki.ts
3548
3966
  function formatWikiList(wikis, opts) {
@@ -3585,7 +4003,7 @@ function formatWikiPageDetail(page, opts) {
3585
4003
  }
3586
4004
 
3587
4005
  // src/commands/wiki/list.ts
3588
- var wikiListCommand = new import_commander33.Command("list").description("\uC704\uD0A4 \uBAA9\uB85D \uC870\uD68C").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (opts) => {
4006
+ var wikiListCommand = new import_commander34.Command("list").description("\uC704\uD0A4 \uBAA9\uB85D \uC870\uD68C").option("--page <number>", "\uD398\uC774\uC9C0 \uBC88\uD638", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (opts) => {
3589
4007
  const globalOpts = wikiListCommand.optsWithGlobals();
3590
4008
  const config = await getConfigOrThrow();
3591
4009
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3599,7 +4017,7 @@ var wikiListCommand = new import_commander33.Command("list").description("\uC704
3599
4017
  });
3600
4018
 
3601
4019
  // src/commands/wiki/pages.ts
3602
- var import_commander34 = require("commander");
4020
+ var import_commander35 = require("commander");
3603
4021
 
3604
4022
  // src/resolvers/wiki.ts
3605
4023
  async function resolveWiki(client, projectCode) {
@@ -3643,7 +4061,7 @@ async function resolveWikiHomePageId(client, wikiId) {
3643
4061
  }
3644
4062
 
3645
4063
  // src/commands/wiki/pages.ts
3646
- var wikiPagesCommand = new import_commander34.Command("pages").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").action(async (project, opts) => {
4064
+ var wikiPagesCommand = new import_commander35.Command("pages").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").action(async (project, opts) => {
3647
4065
  const globalOpts = wikiPagesCommand.optsWithGlobals();
3648
4066
  const config = await getConfigOrThrow();
3649
4067
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3655,8 +4073,8 @@ var wikiPagesCommand = new import_commander34.Command("pages").description("\uC7
3655
4073
  });
3656
4074
 
3657
4075
  // src/commands/wiki/page-get.ts
3658
- var import_commander35 = require("commander");
3659
- var wikiPageGetCommand = new import_commander35.Command("get").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0C1\uC138 \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
4076
+ var import_commander36 = require("commander");
4077
+ var wikiPageGetCommand = new import_commander36.Command("get").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0C1\uC138 \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
3660
4078
  const globalOpts = wikiPageGetCommand.optsWithGlobals();
3661
4079
  const config = await getConfigOrThrow();
3662
4080
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3668,8 +4086,8 @@ var wikiPageGetCommand = new import_commander35.Command("get").description("\uC7
3668
4086
  });
3669
4087
 
3670
4088
  // src/commands/wiki/page-create.ts
3671
- var import_commander36 = require("commander");
3672
- var wikiPageCreateCommand = new import_commander36.Command("create").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").requiredOption("--title <title>", "\uD398\uC774\uC9C0 \uC81C\uBAA9").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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, opts) => {
4089
+ var import_commander37 = require("commander");
4090
+ var wikiPageCreateCommand = new import_commander37.Command("create").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").requiredOption("--title <title>", "\uD398\uC774\uC9C0 \uC81C\uBAA9").option("--parent <page-id>", "\uBD80\uBAA8 \uD398\uC774\uC9C0 ID").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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, opts) => {
3673
4091
  const globalOpts = wikiPageCreateCommand.optsWithGlobals();
3674
4092
  const config = await getConfigOrThrow();
3675
4093
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3694,8 +4112,8 @@ var wikiPageCreateCommand = new import_commander36.Command("create").description
3694
4112
  });
3695
4113
 
3696
4114
  // src/commands/wiki/page-edit.ts
3697
- var import_commander37 = require("commander");
3698
- var wikiPageEditCommand = new import_commander37.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 (\uD50C\uB798\uADF8 \uC5C6\uC73C\uBA74 $EDITOR)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").option("--title <title>", "\uD398\uC774\uC9C0 \uC81C\uBAA9 (\uC9C0\uC815 \uC2DC $EDITOR \uC0DD\uB7B5)").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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, pageId, opts) => {
4115
+ var import_commander38 = require("commander");
4116
+ var wikiPageEditCommand = new import_commander38.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 (\uD50C\uB798\uADF8 \uC5C6\uC73C\uBA74 $EDITOR)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").option("--title <title>", "\uD398\uC774\uC9C0 \uC81C\uBAA9 (\uC9C0\uC815 \uC2DC $EDITOR \uC0DD\uB7B5)").option("--body <text>", "\uBCF8\uBB38 \uD14D\uC2A4\uD2B8 (- \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, pageId, opts) => {
3699
4117
  const config = await getConfigOrThrow();
3700
4118
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
3701
4119
  const hasTitle = opts.title != null;
@@ -3747,11 +4165,679 @@ var wikiPageEditCommand = new import_commander37.Command("edit").description("\u
3747
4165
  `);
3748
4166
  });
3749
4167
 
3750
- // src/commands/member/index.ts
4168
+ // src/commands/wiki/page-file/index.ts
4169
+ var import_commander44 = require("commander");
4170
+
4171
+ // src/commands/wiki/page-file/list.ts
4172
+ var import_commander39 = require("commander");
4173
+
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);
4181
+ }
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
+ );
4187
+ }
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);
4226
+ }
4227
+
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();
4236
+ const config = await getConfigOrThrow();
4237
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
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
+ }
4262
+ });
4263
+
4264
+ // src/commands/wiki/page-file/upload.ts
4265
+ var import_commander40 = require("commander");
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) => {
4267
+ const config = await getConfigOrThrow();
4268
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
4269
+ const fileType = opts.type;
4270
+ if (fileType !== "general" && fileType !== "inline_image") {
4271
+ throw new DoorayCliError(
4272
+ `--type \uC740 general \uB610\uB294 inline_image \uC5EC\uC57C \uD569\uB2C8\uB2E4 (\uC785\uB825: ${opts.type})`,
4273
+ EXIT_PARAM_ERROR
4274
+ );
4275
+ }
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;
4339
+ }
4340
+ });
4341
+
4342
+ // src/commands/wiki/page-file/download.ts
3751
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) => {
4347
+ const config = await getConfigOrThrow();
4348
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
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");
3752
4838
 
3753
4839
  // src/commands/member/get.ts
3754
- var import_commander38 = require("commander");
4840
+ var import_commander52 = require("commander");
3755
4841
 
3756
4842
  // src/formatters/member.ts
3757
4843
  function formatMemberDetail(member, opts) {
@@ -3797,7 +4883,7 @@ function formatMemberSearchResults(members, opts) {
3797
4883
  }
3798
4884
 
3799
4885
  // src/commands/member/get.ts
3800
- var memberGetCommand = new import_commander38.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
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) => {
3801
4887
  const globalOpts = memberGetCommand.optsWithGlobals();
3802
4888
  const config = await getConfigOrThrow();
3803
4889
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3806,8 +4892,8 @@ var memberGetCommand = new import_commander38.Command("get").description("\uBA64
3806
4892
  });
3807
4893
 
3808
4894
  // src/commands/member/list.ts
3809
- var import_commander39 = require("commander");
3810
- var memberListCommand = new import_commander39.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) => {
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) => {
3811
4897
  const globalOpts = memberListCommand.optsWithGlobals();
3812
4898
  const config = await getConfigOrThrow();
3813
4899
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -3822,8 +4908,8 @@ var memberListCommand = new import_commander39.Command("list").description("\uD5
3822
4908
  });
3823
4909
 
3824
4910
  // src/commands/member/search.ts
3825
- var import_commander40 = require("commander");
3826
- var memberSearchCommand = new import_commander40.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) => {
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) => {
3827
4913
  const globalOpts = memberSearchCommand.optsWithGlobals();
3828
4914
  const filterCount = [keyword, opts.email, opts.userCode, opts.userCodeExact].filter(Boolean).length;
3829
4915
  if (filterCount === 0) {
@@ -3856,13 +4942,13 @@ var memberSearchCommand = new import_commander40.Command("search").description("
3856
4942
  });
3857
4943
 
3858
4944
  // src/commands/member/index.ts
3859
- var memberCommand = new import_commander41.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
4945
+ var memberCommand = new import_commander55.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
3860
4946
  memberCommand.addCommand(memberGetCommand);
3861
4947
  memberCommand.addCommand(memberListCommand);
3862
4948
  memberCommand.addCommand(memberSearchCommand);
3863
4949
 
3864
4950
  // src/commands/mail/list.ts
3865
- var import_commander42 = require("commander");
4951
+ var import_commander56 = require("commander");
3866
4952
 
3867
4953
  // src/api/imapClient.ts
3868
4954
  var import_imapflow = require("imapflow");
@@ -3979,7 +5065,7 @@ async function getMail(config, uid) {
3979
5065
 
3980
5066
  // src/commands/mail/list.ts
3981
5067
  var import_chalk5 = __toESM(require("chalk"));
3982
- var mailListCommand = new import_commander42.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) => {
3983
5069
  const globalOpts = mailListCommand.optsWithGlobals();
3984
5070
  const config = await getConfigOrThrow();
3985
5071
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -4011,9 +5097,9 @@ var mailListCommand = new import_commander42.Command("list").description("\uBA54
4011
5097
  });
4012
5098
 
4013
5099
  // src/commands/mail/get.ts
4014
- var import_commander43 = require("commander");
5100
+ var import_commander57 = require("commander");
4015
5101
  var import_chalk6 = __toESM(require("chalk"));
4016
- var mailGetCommand = new import_commander43.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) => {
4017
5103
  const globalOpts = mailGetCommand.optsWithGlobals();
4018
5104
  const config = await getConfigOrThrow();
4019
5105
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -4044,8 +5130,8 @@ ${mail.body}
4044
5130
  });
4045
5131
 
4046
5132
  // src/commands/mail/send.ts
4047
- var import_commander44 = require("commander");
4048
- var import_promises11 = require("fs/promises");
5133
+ var import_commander58 = require("commander");
5134
+ var import_promises13 = require("fs/promises");
4049
5135
 
4050
5136
  // src/api/smtpClient.ts
4051
5137
  var import_nodemailer = __toESM(require("nodemailer"));
@@ -4094,12 +5180,12 @@ async function sendMail(config, opts) {
4094
5180
  }
4095
5181
 
4096
5182
  // src/commands/mail/send.ts
4097
- var mailSendCommand = new import_commander44.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) => {
4098
5184
  const globalOpts = mailSendCommand.optsWithGlobals();
4099
5185
  const config = await getConfigOrThrow();
4100
5186
  let body = opts.body ?? "";
4101
5187
  if (opts.bodyFile) {
4102
- body = await (0, import_promises11.readFile)(opts.bodyFile, "utf-8");
5188
+ body = await (0, import_promises13.readFile)(opts.bodyFile, "utf-8");
4103
5189
  }
4104
5190
  if (!body) {
4105
5191
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -4129,8 +5215,8 @@ var mailSendCommand = new import_commander44.Command("send").description("\uBA54
4129
5215
  });
4130
5216
 
4131
5217
  // src/commands/mail/reply.ts
4132
- var import_commander45 = require("commander");
4133
- var import_promises12 = require("fs/promises");
5218
+ var import_commander59 = require("commander");
5219
+ var import_promises14 = require("fs/promises");
4134
5220
  var import_imapflow2 = require("imapflow");
4135
5221
  async function getMessageId(config, uid) {
4136
5222
  const imap = getImapConfigOrThrow(config);
@@ -4158,12 +5244,12 @@ async function getMessageId(config, uid) {
4158
5244
  await client.logout();
4159
5245
  }
4160
5246
  }
4161
- var mailReplyCommand = new import_commander45.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) => {
4162
5248
  const globalOpts = mailReplyCommand.optsWithGlobals();
4163
5249
  const config = await getConfigOrThrow();
4164
5250
  let body = opts.body ?? "";
4165
5251
  if (opts.bodyFile) {
4166
- body = await (0, import_promises12.readFile)(opts.bodyFile, "utf-8");
5252
+ body = await (0, import_promises14.readFile)(opts.bodyFile, "utf-8");
4167
5253
  }
4168
5254
  if (!body) {
4169
5255
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -4199,29 +5285,29 @@ var mailReplyCommand = new import_commander45.Command("reply").description("\uBA
4199
5285
  });
4200
5286
 
4201
5287
  // src/commands/feedback.ts
4202
- var import_commander46 = require("commander");
5288
+ var import_commander60 = require("commander");
4203
5289
  var import_node_child_process2 = require("child_process");
4204
5290
  var import_node_util = require("util");
4205
- var import_promises15 = require("fs/promises");
5291
+ var import_promises17 = require("fs/promises");
4206
5292
  var import_node_os4 = require("os");
4207
- var import_node_path11 = require("path");
5293
+ var import_node_path13 = require("path");
4208
5294
  var import_node_crypto = require("crypto");
4209
5295
  var import_prompts = require("@inquirer/prompts");
4210
5296
 
4211
5297
  // src/utils/feedback-meta.ts
4212
- var import_promises13 = require("fs/promises");
4213
- var import_node_path9 = require("path");
5298
+ var import_promises15 = require("fs/promises");
5299
+ var import_node_path11 = require("path");
4214
5300
  async function readCliVersion() {
4215
5301
  const entry = process.argv[1];
4216
- const here = entry ? (0, import_node_path9.dirname)(entry) : process.cwd();
5302
+ const here = entry ? (0, import_node_path11.dirname)(entry) : process.cwd();
4217
5303
  const candidates = [
4218
- (0, import_node_path9.join)(here, "package.json"),
4219
- (0, import_node_path9.join)(here, "..", "package.json"),
4220
- (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")
4221
5307
  ];
4222
5308
  for (const p of candidates) {
4223
5309
  try {
4224
- const raw = await (0, import_promises13.readFile)(p, "utf-8");
5310
+ const raw = await (0, import_promises15.readFile)(p, "utf-8");
4225
5311
  const pkg = JSON.parse(raw);
4226
5312
  if (pkg.name === "@bifos/dooray-cli" && typeof pkg.version === "string") {
4227
5313
  return pkg.version;
@@ -4267,10 +5353,10 @@ function buildIssueBody(userBody, meta) {
4267
5353
  }
4268
5354
 
4269
5355
  // src/cache/last-run.ts
4270
- var import_promises14 = require("fs/promises");
4271
- var import_node_path10 = require("path");
5356
+ var import_promises16 = require("fs/promises");
5357
+ var import_node_path12 = require("path");
4272
5358
  var import_node_os3 = require("os");
4273
- 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");
4274
5360
  function isLastRun(obj) {
4275
5361
  if (typeof obj !== "object" || obj === null) return false;
4276
5362
  const o = obj;
@@ -4278,7 +5364,7 @@ function isLastRun(obj) {
4278
5364
  }
4279
5365
  async function readLastRun() {
4280
5366
  try {
4281
- 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");
4282
5368
  const parsed = JSON.parse(raw);
4283
5369
  return isLastRun(parsed) ? parsed : null;
4284
5370
  } catch {
@@ -4286,10 +5372,10 @@ async function readLastRun() {
4286
5372
  }
4287
5373
  }
4288
5374
  async function writeLastRun(data) {
4289
- 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 });
4290
5376
  const tmp2 = LAST_RUN_PATH + ".tmp";
4291
- await (0, import_promises14.writeFile)(tmp2, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
4292
- 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);
4293
5379
  }
4294
5380
 
4295
5381
  // src/commands/feedback.ts
@@ -4307,10 +5393,10 @@ async function ensureGhInstalled() {
4307
5393
  }
4308
5394
  async function readBody(opts) {
4309
5395
  if (opts.body) return opts.body;
4310
- 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");
4311
5397
  return void 0;
4312
5398
  }
4313
- var feedbackCommand = new import_commander46.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(
4314
5400
  "--label <name>",
4315
5401
  "\uB77C\uBCA8 (\uBC18\uBCF5 \uAC00\uB2A5)",
4316
5402
  (value, prev) => [...prev, value],
@@ -4401,8 +5487,8 @@ var feedbackCommand = new import_commander46.Command("feedback").description("do
4401
5487
  }
4402
5488
  }
4403
5489
  await ensureGhInstalled();
4404
- const bodyFile = (0, import_node_path11.join)((0, import_node_os4.tmpdir)(), `dooray-feedback-${(0, import_node_crypto.randomUUID)()}.md`);
4405
- 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);
4406
5492
  try {
4407
5493
  const args = [
4408
5494
  "issue",
@@ -4429,7 +5515,7 @@ gh \uC778\uC99D \uC548 \uB418\uC5B4 \uC788\uC73C\uBA74: gh auth login`,
4429
5515
  EXIT_PARAM_ERROR
4430
5516
  );
4431
5517
  } finally {
4432
- await (0, import_promises15.unlink)(bodyFile).catch(() => {
5518
+ await (0, import_promises17.unlink)(bodyFile).catch(() => {
4433
5519
  });
4434
5520
  }
4435
5521
  });
@@ -4473,8 +5559,8 @@ function sanitizeArgv(argv) {
4473
5559
  }
4474
5560
 
4475
5561
  // src/index.ts
4476
- var program = new import_commander47.Command();
4477
- program.name("dooray").description("Dooray REST API CLI").version("0.8.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");
4478
5564
  program.hook("preAction", () => {
4479
5565
  const opts = program.opts();
4480
5566
  if (opts.color === false || process.env.NO_COLOR) {
@@ -4484,13 +5570,14 @@ program.hook("preAction", () => {
4484
5570
  setQuiet(true);
4485
5571
  }
4486
5572
  });
4487
- var projectCommand = new import_commander47.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");
4488
5574
  projectCommand.addCommand(projectListCommand);
4489
5575
  projectCommand.addCommand(projectMembersCommand);
4490
5576
  projectCommand.addCommand(projectWorkflowsCommand);
4491
5577
  projectCommand.addCommand(projectGroupsCommand);
4492
5578
  projectCommand.addCommand(projectTagsCommand);
4493
- var postCommand = new import_commander47.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
5579
+ projectCommand.addCommand(projectTemplatesCommand);
5580
+ var postCommand = new import_commander61.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
4494
5581
  postCommand.addCommand(postListCommand);
4495
5582
  postCommand.addCommand(postSearchCommand);
4496
5583
  postCommand.addCommand(postGetCommand);
@@ -4498,7 +5585,7 @@ postCommand.addCommand(postEditCommand);
4498
5585
  postCommand.addCommand(postCreateCommand);
4499
5586
  postCommand.addCommand(postDoneCommand);
4500
5587
  postCommand.addCommand(postWorkflowCommand);
4501
- var commentCommand = new import_commander47.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
5588
+ var commentCommand = new import_commander61.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
4502
5589
  commentCommand.addCommand(commentListCommand);
4503
5590
  commentCommand.addCommand(commentLatestCommand);
4504
5591
  commentCommand.addCommand(commentGetCommand);
@@ -4507,22 +5594,24 @@ commentCommand.addCommand(commentEditCommand);
4507
5594
  commentCommand.addCommand(commentDeleteCommand);
4508
5595
  commentCommand.addCommand(commentFileCommand);
4509
5596
  postCommand.addCommand(commentCommand);
4510
- var fileCommand = new import_commander47.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");
4511
5598
  fileCommand.addCommand(fileListCommand);
4512
5599
  fileCommand.addCommand(fileDownloadCommand);
4513
5600
  fileCommand.addCommand(fileDownloadAllCommand);
4514
5601
  fileCommand.addCommand(fileUploadCommand);
4515
5602
  fileCommand.addCommand(fileDeleteCommand);
4516
5603
  postCommand.addCommand(fileCommand);
4517
- var wikiCommand = new import_commander47.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
5604
+ var wikiCommand = new import_commander61.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
4518
5605
  wikiCommand.addCommand(wikiListCommand);
4519
5606
  wikiCommand.addCommand(wikiPagesCommand);
4520
- var wikiPageCommand = new import_commander47.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");
4521
5608
  wikiPageCommand.addCommand(wikiPageGetCommand);
4522
5609
  wikiPageCommand.addCommand(wikiPageCreateCommand);
4523
5610
  wikiPageCommand.addCommand(wikiPageEditCommand);
5611
+ wikiPageCommand.addCommand(wikiPageFileCommand);
5612
+ wikiPageCommand.addCommand(wikiPageCommentCommand);
4524
5613
  wikiCommand.addCommand(wikiPageCommand);
4525
- var mailCommand = new import_commander47.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
5614
+ var mailCommand = new import_commander61.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
4526
5615
  mailCommand.addCommand(mailListCommand);
4527
5616
  mailCommand.addCommand(mailGetCommand);
4528
5617
  mailCommand.addCommand(mailSendCommand);