@bifos/dooray-cli 0.2.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +22 -0
  2. package/dist/index.js +266 -45
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -108,6 +108,28 @@ dooray mail send --to "a@b.com" --subject "HTML 메일" --body "<h1>Hello</h1>"
108
108
  dooray mail reply <uid> --body "답장 내용"
109
109
  ```
110
110
 
111
+ ### 첨부파일
112
+
113
+ 업무에 파일을 첨부하거나, 첨부된 파일을 다운로드할 수 있습니다.
114
+
115
+ ```bash
116
+ # 첨부파일 목록
117
+ dooray post file list <project> <number>
118
+
119
+ # 파일 다운로드
120
+ dooray post file download <project> <number> <file-id>
121
+ dooray post file download <project> <number> <file-id> -o ./downloads
122
+
123
+ # 전체 파일 다운로드
124
+ dooray post file download-all <project> <number> -o ./downloads
125
+
126
+ # 파일 업로드
127
+ dooray post file upload <project> <number> ./report.pdf
128
+
129
+ # 파일 삭제
130
+ dooray post file delete <project> <number> <file-id>
131
+ ```
132
+
111
133
  ## 출력 모드
112
134
 
113
135
  | 플래그 | 설명 | 용도 |
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_commander27 = require("commander");
27
+ var import_commander32 = require("commander");
28
28
  var import_chalk6 = __toESM(require("chalk"));
29
29
 
30
30
  // src/commands/config.ts
@@ -278,6 +278,8 @@ var import_chalk3 = __toESM(require("chalk"));
278
278
 
279
279
  // src/api/client.ts
280
280
  var import_ky = __toESM(require("ky"));
281
+ var import_promises3 = require("fs/promises");
282
+ var import_node_path3 = require("path");
281
283
  function joinIds(ids) {
282
284
  return ids && ids.length > 0 ? ids.join(",") : void 0;
283
285
  }
@@ -303,11 +305,15 @@ async function toDoorayCliError(error) {
303
305
  }
304
306
  var DoorayApiClient = class {
305
307
  api;
308
+ authHeader;
309
+ baseUrl;
306
310
  constructor(apiKey, baseUrl) {
311
+ this.authHeader = `dooray-api ${apiKey}`;
312
+ this.baseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
307
313
  this.api = import_ky.default.create({
308
314
  prefixUrl: baseUrl,
309
315
  headers: {
310
- Authorization: `dooray-api ${apiKey}`
316
+ Authorization: this.authHeader
311
317
  }
312
318
  });
313
319
  }
@@ -518,6 +524,97 @@ var DoorayApiClient = class {
518
524
  return toDoorayCliError(e);
519
525
  }
520
526
  }
527
+ // ─── Post Files ─────────────────────────────────────
528
+ async getPostFiles(projectId, postId) {
529
+ try {
530
+ return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/files`).json();
531
+ } catch (e) {
532
+ return toDoorayCliError(e);
533
+ }
534
+ }
535
+ async getPostFileMeta(projectId, postId, fileId) {
536
+ try {
537
+ return await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/files/${fileId}`, {
538
+ searchParams: { media: "meta" }
539
+ }).json();
540
+ } catch (e) {
541
+ return toDoorayCliError(e);
542
+ }
543
+ }
544
+ async downloadPostFile(projectId, postId, fileId) {
545
+ try {
546
+ const res = await this.api.get(`project/v1/projects/${projectId}/posts/${postId}/files/${fileId}`, {
547
+ searchParams: { media: "raw" },
548
+ redirect: "manual",
549
+ throwHttpErrors: false
550
+ });
551
+ const location = res.headers.get("location");
552
+ if (!location) {
553
+ throw new DoorayCliError("\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uB9AC\uB2E4\uC774\uB809\uD2B8 URL\uC744 \uBC1B\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.", EXIT_API_ERROR);
554
+ }
555
+ const fileRes = await fetch(location, {
556
+ headers: { Authorization: this.authHeader }
557
+ });
558
+ if (!fileRes.ok) {
559
+ throw new DoorayCliError(`\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328 (${fileRes.status})`, EXIT_API_ERROR);
560
+ }
561
+ const disposition = fileRes.headers.get("content-disposition");
562
+ let fileName = `file-${fileId}`;
563
+ if (disposition) {
564
+ const match = disposition.match(/filename\*?=(?:UTF-8''|"?)([^";]+)/i);
565
+ if (match) fileName = decodeURIComponent(match[1].replace(/"/g, ""));
566
+ }
567
+ const buffer = await fileRes.arrayBuffer();
568
+ return { buffer, fileName };
569
+ } catch (e) {
570
+ if (e instanceof DoorayCliError) throw e;
571
+ return toDoorayCliError(e);
572
+ }
573
+ }
574
+ async uploadPostFile(projectId, postId, filePath) {
575
+ try {
576
+ const fileName = (0, import_node_path3.basename)(filePath);
577
+ const fileBuffer = await (0, import_promises3.readFile)(filePath);
578
+ const formData = new FormData();
579
+ formData.append("file", new Blob([fileBuffer]), fileName);
580
+ const url = `${this.baseUrl}project/v1/projects/${projectId}/posts/${postId}/files`;
581
+ const res = await fetch(url, {
582
+ method: "POST",
583
+ headers: { Authorization: this.authHeader },
584
+ body: formData,
585
+ redirect: "manual"
586
+ });
587
+ if (res.status === 307) {
588
+ const location = res.headers.get("location");
589
+ if (!location) {
590
+ throw new DoorayCliError("\uD30C\uC77C \uC5C5\uB85C\uB4DC \uB9AC\uB2E4\uC774\uB809\uD2B8 URL\uC744 \uBC1B\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.", EXIT_API_ERROR);
591
+ }
592
+ const uploadRes = await fetch(location, {
593
+ method: "POST",
594
+ headers: { Authorization: this.authHeader },
595
+ body: formData
596
+ });
597
+ if (!uploadRes.ok) {
598
+ throw new DoorayCliError(`\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${uploadRes.status})`, EXIT_API_ERROR);
599
+ }
600
+ return await uploadRes.json();
601
+ }
602
+ if (!res.ok) {
603
+ throw new DoorayCliError(`\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${res.status})`, EXIT_API_ERROR);
604
+ }
605
+ return await res.json();
606
+ } catch (e) {
607
+ if (e instanceof DoorayCliError) throw e;
608
+ return toDoorayCliError(e);
609
+ }
610
+ }
611
+ async deletePostFile(projectId, postId, fileId) {
612
+ try {
613
+ return await this.api.delete(`project/v1/projects/${projectId}/posts/${postId}/files/${fileId}`).json();
614
+ } catch (e) {
615
+ return toDoorayCliError(e);
616
+ }
617
+ }
521
618
  };
522
619
 
523
620
  // src/cache/types.ts
@@ -942,11 +1039,11 @@ var postGetCommand = new import_commander9.Command("get").description("\uC5C5\uB
942
1039
 
943
1040
  // src/commands/post/edit.ts
944
1041
  var import_commander10 = require("commander");
945
- var import_promises4 = __toESM(require("fs/promises"));
1042
+ var import_promises5 = __toESM(require("fs/promises"));
946
1043
 
947
1044
  // src/editor/index.ts
948
1045
  var import_node_child_process = require("child_process");
949
- var import_promises3 = __toESM(require("fs/promises"));
1046
+ var import_promises4 = __toESM(require("fs/promises"));
950
1047
  var import_tmp = __toESM(require("tmp"));
951
1048
  var import_js_yaml = __toESM(require("js-yaml"));
952
1049
  function openInEditor(content) {
@@ -960,7 +1057,7 @@ function openInEditor(content) {
960
1057
  const tmpFile = import_tmp.default.fileSync({ prefix: "dooray-", postfix: ".md" });
961
1058
  return new Promise(async (resolve, reject) => {
962
1059
  try {
963
- await import_promises3.default.writeFile(tmpFile.name, content, "utf-8");
1060
+ await import_promises4.default.writeFile(tmpFile.name, content, "utf-8");
964
1061
  const child = (0, import_node_child_process.spawn)(editor, [tmpFile.name], {
965
1062
  stdio: "inherit"
966
1063
  });
@@ -976,7 +1073,7 @@ function openInEditor(content) {
976
1073
  EXIT_PARAM_ERROR
977
1074
  );
978
1075
  }
979
- const result = await import_promises3.default.readFile(tmpFile.name, "utf-8");
1076
+ const result = await import_promises4.default.readFile(tmpFile.name, "utf-8");
980
1077
  resolve(result);
981
1078
  } catch (e) {
982
1079
  reject(e);
@@ -1098,7 +1195,7 @@ async function resolveBody(opts) {
1098
1195
  }
1099
1196
  if (opts.bodyFile) {
1100
1197
  if (opts.bodyFile === "-") return readStdin();
1101
- return import_promises4.default.readFile(opts.bodyFile, "utf-8");
1198
+ return import_promises5.default.readFile(opts.bodyFile, "utf-8");
1102
1199
  }
1103
1200
  return null;
1104
1201
  }
@@ -1167,13 +1264,13 @@ var postEditCommand = new import_commander10.Command("edit").description("\uC5C5
1167
1264
 
1168
1265
  // src/commands/post/create.ts
1169
1266
  var import_commander11 = require("commander");
1170
- var import_promises5 = __toESM(require("fs/promises"));
1267
+ var import_promises6 = __toESM(require("fs/promises"));
1171
1268
  async function readBody(opts) {
1172
1269
  if (opts.bodyFile) {
1173
1270
  if (opts.bodyFile === "-") {
1174
1271
  return readStdin2();
1175
1272
  }
1176
- return import_promises5.default.readFile(opts.bodyFile, "utf-8");
1273
+ return import_promises6.default.readFile(opts.bodyFile, "utf-8");
1177
1274
  }
1178
1275
  if (opts.body === "-") {
1179
1276
  return readStdin2();
@@ -1276,7 +1373,7 @@ var commentListCommand = new import_commander14.Command("list").description("\uB
1276
1373
 
1277
1374
  // src/commands/post/comment/add.ts
1278
1375
  var import_commander15 = require("commander");
1279
- var import_promises6 = __toESM(require("fs/promises"));
1376
+ var import_promises7 = __toESM(require("fs/promises"));
1280
1377
  async function readStdin3() {
1281
1378
  if (process.stdin.isTTY) {
1282
1379
  throw new DoorayCliError(
@@ -1297,7 +1394,7 @@ async function resolveBody2(opts) {
1297
1394
  }
1298
1395
  if (opts.bodyFile) {
1299
1396
  if (opts.bodyFile === "-") return readStdin3();
1300
- return import_promises6.default.readFile(opts.bodyFile, "utf-8");
1397
+ return import_promises7.default.readFile(opts.bodyFile, "utf-8");
1301
1398
  }
1302
1399
  return null;
1303
1400
  }
@@ -1332,7 +1429,7 @@ var commentAddCommand = new import_commander15.Command("add").description("\uB31
1332
1429
 
1333
1430
  // src/commands/post/comment/edit.ts
1334
1431
  var import_commander16 = require("commander");
1335
- var import_promises7 = __toESM(require("fs/promises"));
1432
+ var import_promises8 = __toESM(require("fs/promises"));
1336
1433
  async function readStdin4() {
1337
1434
  if (process.stdin.isTTY) {
1338
1435
  throw new DoorayCliError(
@@ -1353,7 +1450,7 @@ async function resolveBody3(opts) {
1353
1450
  }
1354
1451
  if (opts.bodyFile) {
1355
1452
  if (opts.bodyFile === "-") return readStdin4();
1356
- return import_promises7.default.readFile(opts.bodyFile, "utf-8");
1453
+ return import_promises8.default.readFile(opts.bodyFile, "utf-8");
1357
1454
  }
1358
1455
  return null;
1359
1456
  }
@@ -1403,8 +1500,125 @@ var commentDeleteCommand = new import_commander17.Command("delete").description(
1403
1500
  `);
1404
1501
  });
1405
1502
 
1406
- // src/commands/wiki/list.ts
1503
+ // src/commands/post/file/list.ts
1407
1504
  var import_commander18 = require("commander");
1505
+ function formatSize(bytes) {
1506
+ if (bytes < 1024) return `${bytes}B`;
1507
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
1508
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
1509
+ }
1510
+ var fileListCommand = new import_commander18.Command("list").description("\uC5C5\uBB34 \uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").action(async (project, postNumberStr) => {
1511
+ const globalOpts = fileListCommand.optsWithGlobals();
1512
+ const config = await getConfigOrThrow();
1513
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1514
+ startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
1515
+ const projectId = await resolveProject(client, project);
1516
+ const postId = await resolvePost(client, projectId, Number(postNumberStr));
1517
+ const res = await client.getPostFiles(projectId, postId);
1518
+ stopSpinner(true, `\uCCA8\uBD80\uD30C\uC77C ${res.result.length}\uAC1C`);
1519
+ output(globalOpts, {
1520
+ headers: ["ID", "\uD30C\uC77C\uBA85", "\uD06C\uAE30", "MIME", "\uC0DD\uC131\uC77C"],
1521
+ rows: res.result.map((f) => [
1522
+ f.id,
1523
+ f.name,
1524
+ formatSize(f.size),
1525
+ f.mimeType,
1526
+ f.createdAt
1527
+ ]),
1528
+ raw: res.result,
1529
+ ids: res.result.map((f) => f.id)
1530
+ });
1531
+ });
1532
+
1533
+ // src/commands/post/file/download.ts
1534
+ var import_commander19 = require("commander");
1535
+ var import_promises9 = require("fs/promises");
1536
+ var import_node_path4 = require("path");
1537
+ var fileDownloadCommand = new import_commander19.Command("download").description("\uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<file-id>", "\uD30C\uC77C ID").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (project, postNumberStr, fileId, opts) => {
1538
+ const config = await getConfigOrThrow();
1539
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1540
+ startSpinner("\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
1541
+ const projectId = await resolveProject(client, project);
1542
+ const postId = await resolvePost(client, projectId, Number(postNumberStr));
1543
+ const { buffer, fileName } = await client.downloadPostFile(projectId, postId, fileId);
1544
+ const outputPath = (0, import_node_path4.join)(opts.output, fileName);
1545
+ await (0, import_promises9.writeFile)(outputPath, Buffer.from(buffer));
1546
+ stopSpinner(true, "\uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC");
1547
+ process.stdout.write(`${outputPath}
1548
+ `);
1549
+ });
1550
+
1551
+ // src/commands/post/file/download-all.ts
1552
+ var import_commander20 = require("commander");
1553
+ var import_promises10 = require("fs/promises");
1554
+ var import_node_path5 = require("path");
1555
+ var fileDownloadAllCommand = new import_commander20.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 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").option("-o, --output <dir>", "\uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC", ".").action(async (project, postNumberStr, opts) => {
1556
+ const config = await getConfigOrThrow();
1557
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1558
+ const spinner = startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
1559
+ const projectId = await resolveProject(client, project);
1560
+ const postId = await resolvePost(client, projectId, Number(postNumberStr));
1561
+ const res = await client.getPostFiles(projectId, postId);
1562
+ if (res.result.length === 0) {
1563
+ stopSpinner(true, "\uCCA8\uBD80\uD30C\uC77C \uC5C6\uC74C");
1564
+ process.stdout.write("\uCCA8\uBD80\uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
1565
+ return;
1566
+ }
1567
+ await (0, import_promises10.mkdir)(opts.output, { recursive: true });
1568
+ const downloaded = [];
1569
+ for (const file of res.result) {
1570
+ spinner.text = `\uB2E4\uC6B4\uB85C\uB4DC \uC911: ${file.name} (${downloaded.length + 1}/${res.result.length})`;
1571
+ const { buffer, fileName } = await client.downloadPostFile(projectId, postId, file.id);
1572
+ const outputPath = (0, import_node_path5.join)(opts.output, fileName);
1573
+ await (0, import_promises10.writeFile)(outputPath, Buffer.from(buffer));
1574
+ downloaded.push(outputPath);
1575
+ }
1576
+ stopSpinner(true, `${downloaded.length}\uAC1C \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC`);
1577
+ for (const path of downloaded) {
1578
+ process.stdout.write(`${path}
1579
+ `);
1580
+ }
1581
+ });
1582
+
1583
+ // src/commands/post/file/upload.ts
1584
+ var import_commander21 = require("commander");
1585
+ var import_node_path6 = require("path");
1586
+ var fileUploadCommand = new import_commander21.Command("upload").description("\uCCA8\uBD80\uD30C\uC77C \uC5C5\uB85C\uB4DC").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<file-path>", "\uC5C5\uB85C\uB4DC\uD560 \uD30C\uC77C \uACBD\uB85C").action(async (project, postNumberStr, filePath) => {
1587
+ const globalOpts = fileUploadCommand.optsWithGlobals();
1588
+ const config = await getConfigOrThrow();
1589
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1590
+ startSpinner("\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC911...");
1591
+ const projectId = await resolveProject(client, project);
1592
+ const postId = await resolvePost(client, projectId, Number(postNumberStr));
1593
+ const res = await client.uploadPostFile(projectId, postId, filePath);
1594
+ stopSpinner(true, "\uC5C5\uB85C\uB4DC \uC644\uB8CC");
1595
+ if (globalOpts.json) {
1596
+ printJson(res.result);
1597
+ } else if (globalOpts.quiet) {
1598
+ process.stdout.write(`${res.result.id}
1599
+ `);
1600
+ } else {
1601
+ process.stdout.write(`\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC644\uB8CC: ${(0, import_node_path6.basename)(filePath)} (ID: ${res.result.id})
1602
+ `);
1603
+ }
1604
+ });
1605
+
1606
+ // src/commands/post/file/delete.ts
1607
+ var import_commander22 = require("commander");
1608
+ var fileDeleteCommand = new import_commander22.Command("delete").description("\uCCA8\uBD80\uD30C\uC77C \uC0AD\uC81C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<file-id>", "\uD30C\uC77C ID").action(async (project, postNumberStr, fileId) => {
1609
+ const config = await getConfigOrThrow();
1610
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1611
+ startSpinner("\uD30C\uC77C \uC0AD\uC81C \uC911...");
1612
+ const projectId = await resolveProject(client, project);
1613
+ const postId = await resolvePost(client, projectId, Number(postNumberStr));
1614
+ await client.deletePostFile(projectId, postId, fileId);
1615
+ stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
1616
+ process.stdout.write(`\uD30C\uC77C(${fileId})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
1617
+ `);
1618
+ });
1619
+
1620
+ // src/commands/wiki/list.ts
1621
+ var import_commander23 = require("commander");
1408
1622
 
1409
1623
  // src/formatters/wiki.ts
1410
1624
  function formatWikiList(wikis, opts) {
@@ -1447,7 +1661,7 @@ function formatWikiPageDetail(page, opts) {
1447
1661
  }
1448
1662
 
1449
1663
  // src/commands/wiki/list.ts
1450
- var wikiListCommand = new import_commander18.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) => {
1664
+ var wikiListCommand = new import_commander23.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) => {
1451
1665
  const globalOpts = wikiListCommand.optsWithGlobals();
1452
1666
  const config = await getConfigOrThrow();
1453
1667
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1461,7 +1675,7 @@ var wikiListCommand = new import_commander18.Command("list").description("\uC704
1461
1675
  });
1462
1676
 
1463
1677
  // src/commands/wiki/pages.ts
1464
- var import_commander19 = require("commander");
1678
+ var import_commander24 = require("commander");
1465
1679
 
1466
1680
  // src/resolvers/wiki.ts
1467
1681
  async function resolveWiki(client, projectCode) {
@@ -1480,7 +1694,7 @@ async function resolveWiki(client, projectCode) {
1480
1694
  }
1481
1695
 
1482
1696
  // src/commands/wiki/pages.ts
1483
- var wikiPagesCommand = new import_commander19.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) => {
1697
+ var wikiPagesCommand = new import_commander24.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) => {
1484
1698
  const globalOpts = wikiPagesCommand.optsWithGlobals();
1485
1699
  const config = await getConfigOrThrow();
1486
1700
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1492,8 +1706,8 @@ var wikiPagesCommand = new import_commander19.Command("pages").description("\uC7
1492
1706
  });
1493
1707
 
1494
1708
  // src/commands/wiki/page-get.ts
1495
- var import_commander20 = require("commander");
1496
- var wikiPageGetCommand = new import_commander20.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) => {
1709
+ var import_commander25 = require("commander");
1710
+ var wikiPageGetCommand = new import_commander25.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) => {
1497
1711
  const globalOpts = wikiPageGetCommand.optsWithGlobals();
1498
1712
  const config = await getConfigOrThrow();
1499
1713
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1505,14 +1719,14 @@ var wikiPageGetCommand = new import_commander20.Command("get").description("\uC7
1505
1719
  });
1506
1720
 
1507
1721
  // src/commands/wiki/page-create.ts
1508
- var import_commander21 = require("commander");
1509
- var import_promises8 = __toESM(require("fs/promises"));
1722
+ var import_commander26 = require("commander");
1723
+ var import_promises11 = __toESM(require("fs/promises"));
1510
1724
  async function readBody2(opts) {
1511
1725
  if (opts.bodyFile) {
1512
1726
  if (opts.bodyFile === "-") {
1513
1727
  return readStdin5();
1514
1728
  }
1515
- return import_promises8.default.readFile(opts.bodyFile, "utf-8");
1729
+ return import_promises11.default.readFile(opts.bodyFile, "utf-8");
1516
1730
  }
1517
1731
  if (opts.body === "-") {
1518
1732
  return readStdin5();
@@ -1532,7 +1746,7 @@ async function readStdin5() {
1532
1746
  }
1533
1747
  return Buffer.concat(chunks).toString("utf-8");
1534
1748
  }
1535
- var wikiPageCreateCommand = new import_commander21.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) => {
1749
+ var wikiPageCreateCommand = new import_commander26.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) => {
1536
1750
  const globalOpts = wikiPageCreateCommand.optsWithGlobals();
1537
1751
  const config = await getConfigOrThrow();
1538
1752
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1556,8 +1770,8 @@ var wikiPageCreateCommand = new import_commander21.Command("create").description
1556
1770
  });
1557
1771
 
1558
1772
  // src/commands/wiki/page-edit.ts
1559
- var import_commander22 = require("commander");
1560
- var wikiPageEditCommand = new import_commander22.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 ($EDITOR)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
1773
+ var import_commander27 = require("commander");
1774
+ var wikiPageEditCommand = new import_commander27.Command("edit").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 ($EDITOR)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<page-id>", "\uD398\uC774\uC9C0 ID").action(async (project, pageId) => {
1561
1775
  const config = await getConfigOrThrow();
1562
1776
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1563
1777
  startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC911...");
@@ -1583,7 +1797,7 @@ var wikiPageEditCommand = new import_commander22.Command("edit").description("\u
1583
1797
  });
1584
1798
 
1585
1799
  // src/commands/mail/list.ts
1586
- var import_commander23 = require("commander");
1800
+ var import_commander28 = require("commander");
1587
1801
 
1588
1802
  // src/api/imapClient.ts
1589
1803
  var import_imapflow = require("imapflow");
@@ -1691,7 +1905,7 @@ async function getMail(config, uid) {
1691
1905
 
1692
1906
  // src/commands/mail/list.ts
1693
1907
  var import_chalk4 = __toESM(require("chalk"));
1694
- var mailListCommand = new import_commander23.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) => {
1908
+ var mailListCommand = new import_commander28.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) => {
1695
1909
  const globalOpts = mailListCommand.optsWithGlobals();
1696
1910
  const config = await getConfigOrThrow();
1697
1911
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -1723,9 +1937,9 @@ var mailListCommand = new import_commander23.Command("list").description("\uBA54
1723
1937
  });
1724
1938
 
1725
1939
  // src/commands/mail/get.ts
1726
- var import_commander24 = require("commander");
1940
+ var import_commander29 = require("commander");
1727
1941
  var import_chalk5 = __toESM(require("chalk"));
1728
- var mailGetCommand = new import_commander24.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
1942
+ var mailGetCommand = new import_commander29.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
1729
1943
  const globalOpts = mailGetCommand.optsWithGlobals();
1730
1944
  const config = await getConfigOrThrow();
1731
1945
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -1756,8 +1970,8 @@ ${mail.body}
1756
1970
  });
1757
1971
 
1758
1972
  // src/commands/mail/send.ts
1759
- var import_commander25 = require("commander");
1760
- var import_promises9 = require("fs/promises");
1973
+ var import_commander30 = require("commander");
1974
+ var import_promises12 = require("fs/promises");
1761
1975
 
1762
1976
  // src/api/smtpClient.ts
1763
1977
  var import_nodemailer = __toESM(require("nodemailer"));
@@ -1806,12 +2020,12 @@ async function sendMail(config, opts) {
1806
2020
  }
1807
2021
 
1808
2022
  // src/commands/mail/send.ts
1809
- var mailSendCommand = new import_commander25.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) => {
2023
+ var mailSendCommand = new import_commander30.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) => {
1810
2024
  const globalOpts = mailSendCommand.optsWithGlobals();
1811
2025
  const config = await getConfigOrThrow();
1812
2026
  let body = opts.body ?? "";
1813
2027
  if (opts.bodyFile) {
1814
- body = await (0, import_promises9.readFile)(opts.bodyFile, "utf-8");
2028
+ body = await (0, import_promises12.readFile)(opts.bodyFile, "utf-8");
1815
2029
  }
1816
2030
  if (!body) {
1817
2031
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -1841,8 +2055,8 @@ var mailSendCommand = new import_commander25.Command("send").description("\uBA54
1841
2055
  });
1842
2056
 
1843
2057
  // src/commands/mail/reply.ts
1844
- var import_commander26 = require("commander");
1845
- var import_promises10 = require("fs/promises");
2058
+ var import_commander31 = require("commander");
2059
+ var import_promises13 = require("fs/promises");
1846
2060
  var import_imapflow2 = require("imapflow");
1847
2061
  async function getMessageId(config, uid) {
1848
2062
  const imap = getImapConfigOrThrow(config);
@@ -1869,12 +2083,12 @@ async function getMessageId(config, uid) {
1869
2083
  await client.logout();
1870
2084
  }
1871
2085
  }
1872
- var mailReplyCommand = new import_commander26.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) => {
2086
+ var mailReplyCommand = new import_commander31.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) => {
1873
2087
  const globalOpts = mailReplyCommand.optsWithGlobals();
1874
2088
  const config = await getConfigOrThrow();
1875
2089
  let body = opts.body ?? "";
1876
2090
  if (opts.bodyFile) {
1877
- body = await (0, import_promises10.readFile)(opts.bodyFile, "utf-8");
2091
+ body = await (0, import_promises13.readFile)(opts.bodyFile, "utf-8");
1878
2092
  }
1879
2093
  if (!body) {
1880
2094
  process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
@@ -1910,19 +2124,19 @@ var mailReplyCommand = new import_commander26.Command("reply").description("\uBA
1910
2124
  });
1911
2125
 
1912
2126
  // src/index.ts
1913
- var program = new import_commander27.Command();
1914
- program.name("dooray").description("Dooray REST API CLI").version("0.2.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");
2127
+ var program = new import_commander32.Command();
2128
+ program.name("dooray").description("Dooray REST API CLI").version("0.3.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");
1915
2129
  program.hook("preAction", () => {
1916
2130
  const opts = program.opts();
1917
2131
  if (opts.color === false || process.env.NO_COLOR) {
1918
2132
  import_chalk6.default.level = 0;
1919
2133
  }
1920
2134
  });
1921
- var projectCommand = new import_commander27.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
2135
+ var projectCommand = new import_commander32.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
1922
2136
  projectCommand.addCommand(projectListCommand);
1923
2137
  projectCommand.addCommand(projectMembersCommand);
1924
2138
  projectCommand.addCommand(projectWorkflowsCommand);
1925
- var postCommand = new import_commander27.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
2139
+ var postCommand = new import_commander32.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
1926
2140
  postCommand.addCommand(postListCommand);
1927
2141
  postCommand.addCommand(postSearchCommand);
1928
2142
  postCommand.addCommand(postGetCommand);
@@ -1930,21 +2144,28 @@ postCommand.addCommand(postEditCommand);
1930
2144
  postCommand.addCommand(postCreateCommand);
1931
2145
  postCommand.addCommand(postDoneCommand);
1932
2146
  postCommand.addCommand(postWorkflowCommand);
1933
- var commentCommand = new import_commander27.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
2147
+ var commentCommand = new import_commander32.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
1934
2148
  commentCommand.addCommand(commentListCommand);
1935
2149
  commentCommand.addCommand(commentAddCommand);
1936
2150
  commentCommand.addCommand(commentEditCommand);
1937
2151
  commentCommand.addCommand(commentDeleteCommand);
1938
2152
  postCommand.addCommand(commentCommand);
1939
- var wikiCommand = new import_commander27.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
2153
+ var fileCommand = new import_commander32.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
2154
+ fileCommand.addCommand(fileListCommand);
2155
+ fileCommand.addCommand(fileDownloadCommand);
2156
+ fileCommand.addCommand(fileDownloadAllCommand);
2157
+ fileCommand.addCommand(fileUploadCommand);
2158
+ fileCommand.addCommand(fileDeleteCommand);
2159
+ postCommand.addCommand(fileCommand);
2160
+ var wikiCommand = new import_commander32.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
1940
2161
  wikiCommand.addCommand(wikiListCommand);
1941
2162
  wikiCommand.addCommand(wikiPagesCommand);
1942
- var wikiPageCommand = new import_commander27.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
2163
+ var wikiPageCommand = new import_commander32.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
1943
2164
  wikiPageCommand.addCommand(wikiPageGetCommand);
1944
2165
  wikiPageCommand.addCommand(wikiPageCreateCommand);
1945
2166
  wikiPageCommand.addCommand(wikiPageEditCommand);
1946
2167
  wikiCommand.addCommand(wikiPageCommand);
1947
- var mailCommand = new import_commander27.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
2168
+ var mailCommand = new import_commander32.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
1948
2169
  mailCommand.addCommand(mailListCommand);
1949
2170
  mailCommand.addCommand(mailGetCommand);
1950
2171
  mailCommand.addCommand(mailSendCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bifos/dooray-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI tool for Dooray project management — AI agent & terminal friendly",
5
5
  "keywords": [
6
6
  "dooray",