@bifos/dooray-cli 0.5.3 → 0.5.4

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_commander36 = require("commander");
27
+ var import_commander40 = require("commander");
28
28
  var import_chalk7 = __toESM(require("chalk"));
29
29
 
30
30
  // src/commands/config.ts
@@ -200,6 +200,7 @@ var MEMBERS_DIR = (0, import_node_path2.join)(CACHE_DIR, "members");
200
200
  var WORKFLOWS_DIR = (0, import_node_path2.join)(CACHE_DIR, "workflows");
201
201
  var TAGS_DIR = (0, import_node_path2.join)(CACHE_DIR, "tags");
202
202
  var MILESTONES_DIR = (0, import_node_path2.join)(CACHE_DIR, "milestones");
203
+ var MEMBER_GROUPS_DIR = (0, import_node_path2.join)(CACHE_DIR, "member-groups");
203
204
  var WIKIS_PATH = (0, import_node_path2.join)(CACHE_DIR, "wikis.json");
204
205
  async function ensureDir2(dir) {
205
206
  await (0, import_promises2.mkdir)(dir, { recursive: true });
@@ -278,6 +279,15 @@ async function getMilestones(projectId) {
278
279
  async function setMilestones(projectId, items) {
279
280
  await writeJson(milestonesPath(projectId), { updatedAt: now(), data: items });
280
281
  }
282
+ function memberGroupsPath(projectId) {
283
+ return (0, import_node_path2.join)(MEMBER_GROUPS_DIR, `${projectId}.json`);
284
+ }
285
+ async function getMemberGroups(projectId) {
286
+ return readJson(memberGroupsPath(projectId));
287
+ }
288
+ async function setMemberGroups(projectId, items) {
289
+ await writeJson(memberGroupsPath(projectId), { updatedAt: now(), data: items });
290
+ }
281
291
  async function getWikis() {
282
292
  return readJson(WIKIS_PATH);
283
293
  }
@@ -317,8 +327,14 @@ async function getCacheStats() {
317
327
  milestoneProjectCount = files.filter((f) => f.endsWith(".json")).length;
318
328
  } catch {
319
329
  }
330
+ let memberGroupProjectCount = 0;
331
+ try {
332
+ const files = await (0, import_promises2.readdir)(MEMBER_GROUPS_DIR);
333
+ memberGroupProjectCount = files.filter((f) => f.endsWith(".json")).length;
334
+ } catch {
335
+ }
320
336
  const me = await getMe();
321
- return { projectCount, memberProjectCount, workflowProjectCount, tagProjectCount, milestoneProjectCount, me: me?.data ?? null };
337
+ return { projectCount, memberProjectCount, workflowProjectCount, tagProjectCount, milestoneProjectCount, memberGroupProjectCount, me: me?.data ?? null };
322
338
  }
323
339
 
324
340
  // src/commands/cache.ts
@@ -572,6 +588,19 @@ var DoorayApiClient = class {
572
588
  return toDoorayCliError(e);
573
589
  }
574
590
  }
591
+ // ─── Member Groups ──────────────────────────────────
592
+ async getProjectMemberGroups(projectId, params) {
593
+ try {
594
+ return await this.api.get(`project/v1/projects/${projectId}/member-groups`, {
595
+ searchParams: {
596
+ ...params?.page != null && { page: params.page },
597
+ ...params?.size != null && { size: params.size }
598
+ }
599
+ }).json();
600
+ } catch (e) {
601
+ return toDoorayCliError(e);
602
+ }
603
+ }
575
604
  // ─── Milestones ─────────────────────────────────────
576
605
  async getProjectMilestones(projectId, params) {
577
606
  try {
@@ -745,6 +774,7 @@ var ME_TTL_MS = 864e5;
745
774
  var TAGS_TTL_MS = 864e5;
746
775
  var MILESTONES_TTL_MS = 864e5;
747
776
  var RESOLVER_FETCH_PAGE_SIZE = 100;
777
+ var MEMBER_GROUPS_TTL_MS = 864e5;
748
778
  var WIKIS_TTL_MS = 864e5;
749
779
 
750
780
  // src/resolvers/me.ts
@@ -787,6 +817,7 @@ var doctorCommand = new import_commander3.Command("doctor").description("\uC124\
787
817
  console.log(` \uC6CC\uD06C\uD50C\uB85C\uC6B0: ${stats.workflowProjectCount}\uAC1C \uD504\uB85C\uC81D\uD2B8`);
788
818
  console.log(` Tag \uCE90\uC2DC (\uD504\uB85C\uC81D\uD2B8 \uC218): ${stats.tagProjectCount}`);
789
819
  console.log(` Milestone \uCE90\uC2DC (\uD504\uB85C\uC81D\uD2B8 \uC218): ${stats.milestoneProjectCount}`);
820
+ console.log(` Member Group \uCE90\uC2DC (\uD504\uB85C\uC81D\uD2B8 \uC218): ${stats.memberGroupProjectCount}`);
790
821
  const claudeDir = import_path.default.join(
791
822
  process.env.HOME ?? process.env.USERPROFILE ?? "",
792
823
  ".claude"
@@ -832,10 +863,10 @@ var import_chalk4 = __toESM(require("chalk"));
832
863
  var import_path2 = __toESM(require("path"));
833
864
  var import_promises5 = __toESM(require("fs/promises"));
834
865
  var setupCommand = new import_commander4.Command("setup").description("\uB300\uD654\uD615 \uCD08\uAE30 \uC124\uC815 \uB9C8\uBC95\uC0AC").action(async () => {
835
- const { input, select, password, confirm } = await import("@inquirer/prompts");
866
+ const { input: input2, select, password, confirm: confirm2 } = await import("@inquirer/prompts");
836
867
  const existing = await getConfig();
837
868
  try {
838
- const tenantName = await input({
869
+ const tenantName = await input2({
839
870
  message: "\uD14C\uB10C\uD2B8\uBA85\uC744 \uC785\uB825\uD558\uC138\uC694",
840
871
  default: existing?.tenantName ?? DEFAULTS.tenantName,
841
872
  theme: { prefix: "\u{1F3E2}" }
@@ -884,7 +915,7 @@ var setupCommand = new import_commander4.Command("setup").description("\uB300\uD
884
915
  );
885
916
  }
886
917
  }
887
- const useMail = await confirm({
918
+ const useMail = await confirm2({
888
919
  message: "\uBA54\uC77C \uAE30\uB2A5\uC744 \uC0AC\uC6A9\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
889
920
  default: !!existing?.imapUsername,
890
921
  theme: { prefix: "\u{1F4E7}" }
@@ -892,7 +923,7 @@ var setupCommand = new import_commander4.Command("setup").description("\uB300\uD
892
923
  let imapUsername;
893
924
  let imapPassword;
894
925
  if (useMail) {
895
- imapUsername = await input({
926
+ imapUsername = await input2({
896
927
  message: `IMAP \uC0AC\uC6A9\uC790 \uC774\uBA54\uC77C (\uD655\uC778: https://${tenantName}.dooray.com/setting/mail/general/read)`,
897
928
  default: existing?.imapUsername,
898
929
  theme: { prefix: "\u{1F4E8}" }
@@ -917,7 +948,7 @@ var setupCommand = new import_commander4.Command("setup").description("\uB300\uD
917
948
  )
918
949
  );
919
950
  } else {
920
- const installSkill = await confirm({
951
+ const installSkill = await confirm2({
921
952
  message: "Claude Code \uC2A4\uD0AC\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
922
953
  default: true,
923
954
  theme: { prefix: "\u{1F527}" }
@@ -1009,17 +1040,17 @@ async function ensurePrivateProjects(client) {
1009
1040
  await setPrivateProjects(items);
1010
1041
  return items;
1011
1042
  }
1012
- async function resolveProject(client, input) {
1043
+ async function resolveProject(client, input2) {
1013
1044
  const projects = await ensureProjects(client);
1014
- const match = projects.find((p) => p.code === input || p.id === input);
1045
+ const match = projects.find((p) => p.code === input2 || p.id === input2);
1015
1046
  if (match) return match.id;
1016
1047
  const privateCached = await getPrivateProjects();
1017
1048
  if (privateCached && !isExpired(privateCached.updatedAt, PROJECTS_TTL_MS)) {
1018
- const privateMatch = privateCached.data.find((p) => p.code === input || p.id === input);
1049
+ const privateMatch = privateCached.data.find((p) => p.code === input2 || p.id === input2);
1019
1050
  if (privateMatch) return privateMatch.id;
1020
1051
  }
1021
1052
  throw new DoorayCliError(
1022
- `\uD504\uB85C\uC81D\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}
1053
+ `\uD504\uB85C\uC81D\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2}
1023
1054
  \uAC1C\uC778 \uD504\uB85C\uC81D\uD2B8\uB77C\uBA74: dooray project list --type private \uB85C \uCE90\uC2DC\uB97C \uAC31\uC2E0\uD558\uC138\uC694`,
1024
1055
  EXIT_PARAM_ERROR
1025
1056
  );
@@ -1095,27 +1126,27 @@ var projectListCommand = new import_commander5.Command("list").description("\uD5
1095
1126
  var import_commander6 = require("commander");
1096
1127
 
1097
1128
  // src/resolvers/match.ts
1098
- function matchByName(items, input, label, renderCandidate) {
1099
- const exact = items.filter((i) => i.name === input);
1129
+ function matchByName(items, input2, label, renderCandidate) {
1130
+ const exact = items.filter((i) => i.name === input2);
1100
1131
  if (exact.length === 1) return exact[0];
1101
1132
  if (exact.length > 1) {
1102
1133
  throw new DoorayCliError(
1103
- `\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4(\uC815\uD655\uC77C\uCE58): "${input}"
1134
+ `\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4(\uC815\uD655\uC77C\uCE58): "${input2}"
1104
1135
  ` + exact.map((i) => ` - ${renderCandidate(i)}`).join("\n"),
1105
1136
  EXIT_PARAM_ERROR
1106
1137
  );
1107
1138
  }
1108
- const partial = items.filter((i) => i.name.includes(input));
1139
+ const partial = items.filter((i) => i.name.includes(input2));
1109
1140
  if (partial.length === 1) return partial[0];
1110
1141
  if (partial.length > 1) {
1111
1142
  throw new DoorayCliError(
1112
- `\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4: "${input}"
1143
+ `\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4: "${input2}"
1113
1144
  ` + partial.map((i) => ` - ${renderCandidate(i)}`).join("\n"),
1114
1145
  EXIT_PARAM_ERROR
1115
1146
  );
1116
1147
  }
1117
1148
  throw new DoorayCliError(
1118
- `${label}\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}`,
1149
+ `${label}\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input2}`,
1119
1150
  EXIT_PARAM_ERROR
1120
1151
  );
1121
1152
  }
@@ -1169,11 +1200,11 @@ async function buildMemberNameMap(client, projectId) {
1169
1200
  }
1170
1201
  return map;
1171
1202
  }
1172
- async function resolveMember(client, projectId, input) {
1203
+ async function resolveMember(client, projectId, input2) {
1173
1204
  const members = await ensureMembers(client, projectId);
1174
1205
  const match = matchByName(
1175
1206
  members,
1176
- input,
1207
+ input2,
1177
1208
  "\uBA64\uBC84",
1178
1209
  (m) => `${m.name} (${m.organizationMemberId})`
1179
1210
  );
@@ -1219,17 +1250,17 @@ async function ensureWorkflows(client, projectId) {
1219
1250
  await setWorkflows(projectId, items);
1220
1251
  return items;
1221
1252
  }
1222
- async function resolveWorkflow(client, projectId, input) {
1253
+ async function resolveWorkflow(client, projectId, input2) {
1223
1254
  const workflows = await ensureWorkflows(client, projectId);
1224
- const byClass = workflows.filter((w) => w.class === input);
1255
+ const byClass = workflows.filter((w) => w.class === input2);
1225
1256
  if (byClass.length === 1) return byClass[0].id;
1226
1257
  if (byClass.length > 1) {
1227
1258
  throw new DoorayCliError(
1228
- `\uB3D9\uC77C class\uC758 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4: "${input}"`,
1259
+ `\uB3D9\uC77C class\uC758 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4: "${input2}"`,
1229
1260
  EXIT_PARAM_ERROR
1230
1261
  );
1231
1262
  }
1232
- const match = matchByName(workflows, input, "\uC6CC\uD06C\uD50C\uB85C\uC6B0", (w) => `${w.name} [${w.class}] (${w.id})`);
1263
+ const match = matchByName(workflows, input2, "\uC6CC\uD06C\uD50C\uB85C\uC6B0", (w) => `${w.name} [${w.class}] (${w.id})`);
1233
1264
  return match.id;
1234
1265
  }
1235
1266
 
@@ -1255,9 +1286,159 @@ var projectWorkflowsCommand = new import_commander7.Command("workflows").descrip
1255
1286
  });
1256
1287
  });
1257
1288
 
1258
- // src/commands/post/list.ts
1289
+ // src/commands/project/groups.ts
1259
1290
  var import_commander8 = require("commander");
1260
1291
 
1292
+ // src/resolvers/member-group.ts
1293
+ async function fetchAllMemberGroups(client, projectId) {
1294
+ const all = [];
1295
+ let page = 0;
1296
+ const size = RESOLVER_FETCH_PAGE_SIZE;
1297
+ while (true) {
1298
+ const res = await client.getProjectMemberGroups(projectId, { page, size });
1299
+ for (const g of res.result) {
1300
+ all.push({ id: g.id, code: g.code });
1301
+ }
1302
+ const total = res.totalCount ?? all.length;
1303
+ if (all.length >= total) break;
1304
+ page++;
1305
+ }
1306
+ return all;
1307
+ }
1308
+ async function ensureMemberGroups(client, projectId) {
1309
+ const entry = await getMemberGroups(projectId);
1310
+ if (entry && !isExpired(entry.updatedAt, MEMBER_GROUPS_TTL_MS)) return entry.data;
1311
+ const items = await fetchAllMemberGroups(client, projectId);
1312
+ await setMemberGroups(projectId, items);
1313
+ return items;
1314
+ }
1315
+
1316
+ // src/commands/project/groups.ts
1317
+ var projectGroupsCommand = new import_commander8.Command("groups").description("\uD504\uB85C\uC81D\uD2B8 \uBA64\uBC84 \uADF8\uB8F9 \uBAA9\uB85D \uC870\uD68C").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").action(async (project) => {
1318
+ const globalOpts = projectGroupsCommand.optsWithGlobals();
1319
+ const config = await getConfigOrThrow();
1320
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1321
+ startSpinner("\uBA64\uBC84 \uADF8\uB8F9 \uBAA9\uB85D \uC870\uD68C \uC911...");
1322
+ const projectId = await resolveProject(client, project);
1323
+ const groups = await ensureMemberGroups(client, projectId);
1324
+ stopSpinner(true, "\uBA64\uBC84 \uADF8\uB8F9 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
1325
+ output(globalOpts, {
1326
+ headers: ["ID", "Code"],
1327
+ rows: groups.map((g) => [g.id, g.code]),
1328
+ raw: groups,
1329
+ ids: groups.map((g) => g.id)
1330
+ });
1331
+ });
1332
+
1333
+ // src/commands/project/tags.ts
1334
+ var import_commander9 = require("commander");
1335
+
1336
+ // src/resolvers/tag.ts
1337
+ async function fetchAllTags(client, projectId) {
1338
+ const all = [];
1339
+ let page = 0;
1340
+ const size = RESOLVER_FETCH_PAGE_SIZE;
1341
+ while (true) {
1342
+ const res = await client.getProjectTags(projectId, { page, size });
1343
+ for (const t of res.result) {
1344
+ all.push({
1345
+ id: t.id,
1346
+ name: t.name ?? "",
1347
+ color: t.color ?? "",
1348
+ groupId: t.tagGroup?.id ?? null,
1349
+ groupName: t.tagGroup?.name ?? null,
1350
+ groupMandatory: t.tagGroup?.mandatory ?? false,
1351
+ groupSelectOne: t.tagGroup?.selectOne ?? false
1352
+ });
1353
+ }
1354
+ const total = res.totalCount ?? all.length;
1355
+ if (all.length >= total) break;
1356
+ page++;
1357
+ }
1358
+ return all;
1359
+ }
1360
+ async function ensureTags(client, projectId) {
1361
+ const entry = await getTags(projectId);
1362
+ if (entry && !isExpired(entry.updatedAt, TAGS_TTL_MS)) return entry.data;
1363
+ const items = await fetchAllTags(client, projectId);
1364
+ await setTags(projectId, items);
1365
+ return items;
1366
+ }
1367
+ async function resolveTags(client, projectId, inputs) {
1368
+ const allTags = await ensureTags(client, projectId);
1369
+ const selected = inputs.map(
1370
+ (input2) => matchByName(
1371
+ allTags,
1372
+ input2,
1373
+ "\uD0DC\uADF8",
1374
+ (t) => t.groupName ? `${t.groupName} / ${t.name} (${t.id})` : `${t.name} (${t.id})`
1375
+ )
1376
+ );
1377
+ const mandatoryGroups = /* @__PURE__ */ new Map();
1378
+ for (const t of allTags) {
1379
+ if (t.groupMandatory && t.groupId) mandatoryGroups.set(t.groupId, t.groupName ?? t.groupId);
1380
+ }
1381
+ const coveredGroups = new Set(selected.map((t) => t.groupId).filter((g) => !!g));
1382
+ const missing = [];
1383
+ for (const [gid, gname] of mandatoryGroups) {
1384
+ if (!coveredGroups.has(gid)) missing.push(gname);
1385
+ }
1386
+ if (missing.length > 0) {
1387
+ throw new DoorayCliError(
1388
+ `\uD544\uC218 \uD0DC\uADF8 \uADF8\uB8F9\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (\uADF8\uB8F9\uB2F9 1\uAC1C \uC774\uC0C1 \uD544\uC694):
1389
+ ` + missing.map((g) => ` - ${g}`).join("\n"),
1390
+ EXIT_PARAM_ERROR
1391
+ );
1392
+ }
1393
+ const selectOneGroups = /* @__PURE__ */ new Map();
1394
+ for (const t of selected) {
1395
+ if (!t.groupSelectOne || !t.groupId) continue;
1396
+ const entry = selectOneGroups.get(t.groupId) ?? { name: t.groupName ?? t.groupId, tags: [] };
1397
+ entry.tags.push(t.name);
1398
+ selectOneGroups.set(t.groupId, entry);
1399
+ }
1400
+ const violators = [];
1401
+ for (const [, info] of selectOneGroups) {
1402
+ if (info.tags.length > 1) {
1403
+ violators.push(`${info.name} (\uC120\uD0DD: ${info.tags.join(", ")})`);
1404
+ }
1405
+ }
1406
+ if (violators.length > 0) {
1407
+ throw new DoorayCliError(
1408
+ `\uB2E4\uC74C \uD0DC\uADF8 \uADF8\uB8F9\uC740 1\uAC1C\uB9CC \uC120\uD0DD \uAC00\uB2A5\uD569\uB2C8\uB2E4:
1409
+ ` + violators.map((v) => ` - ${v}`).join("\n"),
1410
+ EXIT_PARAM_ERROR
1411
+ );
1412
+ }
1413
+ return selected.map((t) => t.id);
1414
+ }
1415
+
1416
+ // src/commands/project/tags.ts
1417
+ 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) => {
1418
+ const globalOpts = projectTagsCommand.optsWithGlobals();
1419
+ const config = await getConfigOrThrow();
1420
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1421
+ startSpinner("\uD0DC\uADF8 \uBAA9\uB85D \uC870\uD68C \uC911...");
1422
+ const projectId = await resolveProject(client, project);
1423
+ const tags = await ensureTags(client, projectId);
1424
+ stopSpinner(true, "\uD0DC\uADF8 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
1425
+ output(globalOpts, {
1426
+ headers: ["ID", "Color", "Name", "Group", "Mandatory"],
1427
+ rows: tags.map((t) => [
1428
+ t.id,
1429
+ t.color,
1430
+ t.name,
1431
+ t.groupName ?? "",
1432
+ t.groupMandatory ? "Y" : ""
1433
+ ]),
1434
+ raw: tags,
1435
+ ids: tags.map((t) => t.id)
1436
+ });
1437
+ });
1438
+
1439
+ // src/commands/post/list.ts
1440
+ var import_commander10 = require("commander");
1441
+
1261
1442
  // src/formatters/post.ts
1262
1443
  function formatPostList(posts, opts) {
1263
1444
  output(opts, {
@@ -1307,7 +1488,7 @@ function formatCommentList(comments, opts) {
1307
1488
  }
1308
1489
 
1309
1490
  // src/commands/post/list.ts
1310
- var postListCommand = new import_commander8.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) => {
1491
+ 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) => {
1311
1492
  const globalOpts = postListCommand.optsWithGlobals();
1312
1493
  const config = await getConfigOrThrow();
1313
1494
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1341,8 +1522,8 @@ var postListCommand = new import_commander8.Command("list").description("\uC5C5\
1341
1522
  });
1342
1523
 
1343
1524
  // src/commands/post/search.ts
1344
- var import_commander9 = require("commander");
1345
- var postSearchCommand = new import_commander9.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) => {
1525
+ var import_commander11 = require("commander");
1526
+ 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) => {
1346
1527
  const globalOpts = postSearchCommand.optsWithGlobals();
1347
1528
  const config = await getConfigOrThrow();
1348
1529
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1354,7 +1535,7 @@ var postSearchCommand = new import_commander9.Command("search").description("\uC
1354
1535
  });
1355
1536
 
1356
1537
  // src/commands/post/get.ts
1357
- var import_commander10 = require("commander");
1538
+ var import_commander12 = require("commander");
1358
1539
 
1359
1540
  // src/resolvers/post.ts
1360
1541
  async function resolvePost(client, projectId, postNumber) {
@@ -1372,12 +1553,12 @@ async function resolvePost(client, projectId, postNumber) {
1372
1553
 
1373
1554
  // src/utils/dooray-url.ts
1374
1555
  var TASK_URL_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/task\/to\/(\d+)(?:[/?#].*)?$/;
1375
- function parseDoorayTaskUrl(input) {
1376
- const m = TASK_URL_RE.exec(input);
1556
+ function parseDoorayTaskUrl(input2) {
1557
+ const m = TASK_URL_RE.exec(input2);
1377
1558
  return m ? m[1] : null;
1378
1559
  }
1379
- function isLikelyDoorayUrl(input) {
1380
- return /^https?:\/\//.test(input);
1560
+ function isLikelyDoorayUrl(input2) {
1561
+ return /^https?:\/\//.test(input2);
1381
1562
  }
1382
1563
 
1383
1564
  // src/resolvers/post-input.ts
@@ -1448,7 +1629,7 @@ async function resolvePostInput(client, args) {
1448
1629
  }
1449
1630
 
1450
1631
  // src/commands/post/get.ts
1451
- var postGetCommand = new import_commander10.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) => {
1632
+ 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) => {
1452
1633
  const globalOpts = postGetCommand.optsWithGlobals();
1453
1634
  const config = await getConfigOrThrow();
1454
1635
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1465,7 +1646,7 @@ var postGetCommand = new import_commander10.Command("get").description("\uC5C5\u
1465
1646
  });
1466
1647
 
1467
1648
  // src/commands/post/edit.ts
1468
- var import_commander11 = require("commander");
1649
+ var import_commander13 = require("commander");
1469
1650
 
1470
1651
  // src/editor/index.ts
1471
1652
  var import_node_child_process = require("child_process");
@@ -1473,8 +1654,8 @@ var import_promises6 = __toESM(require("fs/promises"));
1473
1654
  var import_tmp = __toESM(require("tmp"));
1474
1655
  var import_js_yaml = __toESM(require("js-yaml"));
1475
1656
  function openInEditor(content) {
1476
- const editor = process.env.EDITOR;
1477
- if (!editor) {
1657
+ const editor2 = process.env.EDITOR;
1658
+ if (!editor2) {
1478
1659
  throw new DoorayCliError(
1479
1660
  "$EDITOR \uD658\uACBD\uBCC0\uC218\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. export EDITOR=vim \uB4F1\uC73C\uB85C \uC124\uC815\uD574\uC8FC\uC138\uC694.",
1480
1661
  EXIT_PARAM_ERROR
@@ -1484,7 +1665,7 @@ function openInEditor(content) {
1484
1665
  return new Promise(async (resolve, reject) => {
1485
1666
  try {
1486
1667
  await import_promises6.default.writeFile(tmpFile.name, content, "utf-8");
1487
- const child = (0, import_node_child_process.spawn)(editor, [tmpFile.name], {
1668
+ const child = (0, import_node_child_process.spawn)(editor2, [tmpFile.name], {
1488
1669
  stdio: "inherit"
1489
1670
  });
1490
1671
  child.on("error", (err) => {
@@ -1635,7 +1816,7 @@ async function resolveUsers(client, projectId, emails) {
1635
1816
  }
1636
1817
  return users;
1637
1818
  }
1638
- var postEditCommand = new import_commander11.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)").action(async (project, postNumberStr, opts) => {
1819
+ 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)").action(async (project, postNumberStr, opts) => {
1639
1820
  const config = await getConfigOrThrow();
1640
1821
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1641
1822
  startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
@@ -1709,86 +1890,7 @@ var postEditCommand = new import_commander11.Command("edit").description("\uC5C5
1709
1890
  });
1710
1891
 
1711
1892
  // src/commands/post/create.ts
1712
- var import_commander12 = require("commander");
1713
-
1714
- // src/resolvers/tag.ts
1715
- async function fetchAllTags(client, projectId) {
1716
- const all = [];
1717
- let page = 0;
1718
- const size = RESOLVER_FETCH_PAGE_SIZE;
1719
- while (true) {
1720
- const res = await client.getProjectTags(projectId, { page, size });
1721
- for (const t of res.result) {
1722
- all.push({
1723
- id: t.id,
1724
- name: t.name ?? "",
1725
- groupId: t.tagGroup?.id ?? null,
1726
- groupName: t.tagGroup?.name ?? null,
1727
- groupMandatory: t.tagGroup?.mandatory ?? false,
1728
- groupSelectOne: t.tagGroup?.selectOne ?? false
1729
- });
1730
- }
1731
- const total = res.totalCount ?? all.length;
1732
- if (all.length >= total) break;
1733
- page++;
1734
- }
1735
- return all;
1736
- }
1737
- async function ensureTags(client, projectId) {
1738
- const entry = await getTags(projectId);
1739
- if (entry && !isExpired(entry.updatedAt, TAGS_TTL_MS)) return entry.data;
1740
- const items = await fetchAllTags(client, projectId);
1741
- await setTags(projectId, items);
1742
- return items;
1743
- }
1744
- async function resolveTags(client, projectId, inputs) {
1745
- const allTags = await ensureTags(client, projectId);
1746
- const selected = inputs.map(
1747
- (input) => matchByName(
1748
- allTags,
1749
- input,
1750
- "\uD0DC\uADF8",
1751
- (t) => t.groupName ? `${t.groupName} / ${t.name} (${t.id})` : `${t.name} (${t.id})`
1752
- )
1753
- );
1754
- const mandatoryGroups = /* @__PURE__ */ new Map();
1755
- for (const t of allTags) {
1756
- if (t.groupMandatory && t.groupId) mandatoryGroups.set(t.groupId, t.groupName ?? t.groupId);
1757
- }
1758
- const coveredGroups = new Set(selected.map((t) => t.groupId).filter((g) => !!g));
1759
- const missing = [];
1760
- for (const [gid, gname] of mandatoryGroups) {
1761
- if (!coveredGroups.has(gid)) missing.push(gname);
1762
- }
1763
- if (missing.length > 0) {
1764
- throw new DoorayCliError(
1765
- `\uD544\uC218 \uD0DC\uADF8 \uADF8\uB8F9\uC774 \uB204\uB77D\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (\uADF8\uB8F9\uB2F9 1\uAC1C \uC774\uC0C1 \uD544\uC694):
1766
- ` + missing.map((g) => ` - ${g}`).join("\n"),
1767
- EXIT_PARAM_ERROR
1768
- );
1769
- }
1770
- const selectOneGroups = /* @__PURE__ */ new Map();
1771
- for (const t of selected) {
1772
- if (!t.groupSelectOne || !t.groupId) continue;
1773
- const entry = selectOneGroups.get(t.groupId) ?? { name: t.groupName ?? t.groupId, tags: [] };
1774
- entry.tags.push(t.name);
1775
- selectOneGroups.set(t.groupId, entry);
1776
- }
1777
- const violators = [];
1778
- for (const [, info] of selectOneGroups) {
1779
- if (info.tags.length > 1) {
1780
- violators.push(`${info.name} (\uC120\uD0DD: ${info.tags.join(", ")})`);
1781
- }
1782
- }
1783
- if (violators.length > 0) {
1784
- throw new DoorayCliError(
1785
- `\uB2E4\uC74C \uD0DC\uADF8 \uADF8\uB8F9\uC740 1\uAC1C\uB9CC \uC120\uD0DD \uAC00\uB2A5\uD569\uB2C8\uB2E4:
1786
- ` + violators.map((v) => ` - ${v}`).join("\n"),
1787
- EXIT_PARAM_ERROR
1788
- );
1789
- }
1790
- return selected.map((t) => t.id);
1791
- }
1893
+ var import_commander14 = require("commander");
1792
1894
 
1793
1895
  // src/resolvers/milestone.ts
1794
1896
  async function fetchAllMilestones(client, projectId) {
@@ -1811,9 +1913,9 @@ async function ensureMilestones(client, projectId) {
1811
1913
  await setMilestones(projectId, items);
1812
1914
  return items;
1813
1915
  }
1814
- async function resolveMilestone(client, projectId, input) {
1916
+ async function resolveMilestone(client, projectId, input2) {
1815
1917
  const all = await ensureMilestones(client, projectId);
1816
- const match = matchByName(all, input, "\uB9C8\uC77C\uC2A4\uD1A4", (m) => `${m.name} (${m.id})`);
1918
+ const match = matchByName(all, input2, "\uB9C8\uC77C\uC2A4\uD1A4", (m) => `${m.name} (${m.id})`);
1817
1919
  return match.id;
1818
1920
  }
1819
1921
 
@@ -1837,13 +1939,13 @@ async function resolvePostRef(client, ref) {
1837
1939
  // src/commands/post/create.ts
1838
1940
  async function resolveUsers2(client, projectId, inputs) {
1839
1941
  const users = [];
1840
- for (const input of inputs) {
1841
- const memberId = await resolveMember(client, projectId, input);
1942
+ for (const input2 of inputs) {
1943
+ const memberId = await resolveMember(client, projectId, input2);
1842
1944
  users.push({ type: "member", member: { organizationMemberId: memberId } });
1843
1945
  }
1844
1946
  return users;
1845
1947
  }
1846
- var postCreateCommand = new import_commander12.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("--cc <members...>", "\uCC38\uC870\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").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("--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").action(async (project, opts) => {
1948
+ 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("--cc <members...>", "\uCC38\uC870\uC790 (\uC774\uB984 \uB610\uB294 \uC774\uBA54\uC77C, \uC5EC\uB7EC \uBA85 \uAC00\uB2A5)").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("--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").action(async (project, opts) => {
1847
1949
  const globalOpts = postCreateCommand.optsWithGlobals();
1848
1950
  const config = await getConfigOrThrow();
1849
1951
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -1902,8 +2004,8 @@ var postCreateCommand = new import_commander12.Command("create").description("\u
1902
2004
  });
1903
2005
 
1904
2006
  // src/commands/post/done.ts
1905
- var import_commander13 = require("commander");
1906
- var postDoneCommand = new import_commander13.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) => {
2007
+ var import_commander15 = require("commander");
2008
+ 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) => {
1907
2009
  const config = await getConfigOrThrow();
1908
2010
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1909
2011
  startSpinner("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC911...");
@@ -1920,8 +2022,8 @@ var postDoneCommand = new import_commander13.Command("done").description("\uC5C5
1920
2022
  });
1921
2023
 
1922
2024
  // src/commands/post/workflow.ts
1923
- var import_commander14 = require("commander");
1924
- var postWorkflowCommand = new import_commander14.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) => {
2025
+ var import_commander16 = require("commander");
2026
+ 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) => {
1925
2027
  const config = await getConfigOrThrow();
1926
2028
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
1927
2029
  let workflowInput = opts.workflow;
@@ -1961,7 +2063,7 @@ var postWorkflowCommand = new import_commander14.Command("workflow").description
1961
2063
  });
1962
2064
 
1963
2065
  // src/commands/post/comment/list.ts
1964
- var import_commander15 = require("commander");
2066
+ var import_commander17 = require("commander");
1965
2067
 
1966
2068
  // src/utils/comment-enrich.ts
1967
2069
  function enrichCommentCreators(comments, nameMap) {
@@ -1982,10 +2084,77 @@ function enrichCommentCreators(comments, nameMap) {
1982
2084
  }
1983
2085
 
1984
2086
  // src/commands/post/comment/list.ts
1985
- var commentListCommand = new import_commander15.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", "0").option("--size <number>", "\uD398\uC774\uC9C0 \uD06C\uAE30", "20").action(async (project, postNumberStr, opts) => {
2087
+ var PAGE_DEFAULT = "0";
2088
+ var SIZE_DEFAULT = "20";
2089
+ function parseSinceDate(input2) {
2090
+ const d = new Date(input2);
2091
+ if (isNaN(d.getTime())) {
2092
+ throw new DoorayCliError(
2093
+ `--since \uAC12\uC744 \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: "${input2}" (ISO 8601 \uB610\uB294 YYYY-MM-DD)`,
2094
+ EXIT_PARAM_ERROR
2095
+ );
2096
+ }
2097
+ return d;
2098
+ }
2099
+ function validateExclusive(opts) {
2100
+ function err(msg) {
2101
+ return new DoorayCliError(msg, EXIT_PARAM_ERROR);
2102
+ }
2103
+ if (opts.latest) {
2104
+ if (opts.page && opts.page !== PAGE_DEFAULT) throw err("--latest\uC640 --page\uB294 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2105
+ if (opts.size && opts.size !== SIZE_DEFAULT) throw err("--latest\uC640 --size\uB294 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2106
+ if (opts.sort && opts.sort !== "asc") throw err("--latest\uC640 --sort\uB294 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2107
+ if (opts.reverse) throw err("--latest\uC640 --reverse\uB294 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2108
+ if (opts.since) throw err("--latest\uC640 --since\uB294 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2109
+ }
2110
+ if (opts.reverse && opts.sort && opts.sort !== "asc") {
2111
+ throw err("--reverse\uC640 --sort \uC635\uC158\uC740 \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00");
2112
+ }
2113
+ if (opts.sort && opts.sort !== "asc" && opts.sort !== "desc") {
2114
+ throw err(`--sort\uB294 asc \uB610\uB294 desc\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4: "${opts.sort}"`);
2115
+ }
2116
+ }
2117
+ function resolveOrder(opts) {
2118
+ if (opts.reverse) return "-createdAt";
2119
+ if (opts.sort === "desc") return "-createdAt";
2120
+ return "createdAt";
2121
+ }
2122
+ async function fetchSince(client, projectId, postId, sinceDate) {
2123
+ const sinceMs = sinceDate.getTime();
2124
+ const collected = [];
2125
+ let page = 0;
2126
+ const size = 100;
2127
+ while (true) {
2128
+ const res = await client.getPostComments(projectId, postId, {
2129
+ page,
2130
+ size,
2131
+ order: "-createdAt"
2132
+ });
2133
+ const pageItems = res.result;
2134
+ const survivors = pageItems.filter((c) => new Date(c.createdAt).getTime() >= sinceMs);
2135
+ collected.push(...survivors);
2136
+ const hasOlder = pageItems.length > survivors.length;
2137
+ if (hasOlder) break;
2138
+ if (pageItems.length < size) break;
2139
+ page++;
2140
+ }
2141
+ return collected;
2142
+ }
2143
+ 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) => {
1986
2144
  const globalOpts = commentListCommand.optsWithGlobals();
1987
2145
  const config = await getConfigOrThrow();
1988
2146
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2147
+ validateExclusive(opts);
2148
+ if (opts.latest) {
2149
+ const n = Number(opts.latest);
2150
+ if (!Number.isFinite(n) || n <= 0) {
2151
+ throw new DoorayCliError("--latest\uB294 \uC591\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
2152
+ }
2153
+ if (n > 100) {
2154
+ throw new DoorayCliError("--latest\uB294 \uCD5C\uB300 100\uAE4C\uC9C0 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
2155
+ }
2156
+ }
2157
+ const sinceDate = opts.since ? parseSinceDate(opts.since) : null;
1989
2158
  startSpinner("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC911...");
1990
2159
  const { projectId, postId } = await resolvePostInput(client, {
1991
2160
  projectArg: project,
@@ -1993,12 +2162,72 @@ var commentListCommand = new import_commander15.Command("list").description("\uB
1993
2162
  idOpt: opts.id,
1994
2163
  urlOpt: opts.url
1995
2164
  });
2165
+ const order = resolveOrder(opts);
2166
+ let comments;
2167
+ if (opts.latest) {
2168
+ const n = Number(opts.latest);
2169
+ const res = await client.getPostComments(projectId, postId, {
2170
+ page: 0,
2171
+ size: n,
2172
+ order: "-createdAt"
2173
+ });
2174
+ comments = res.result;
2175
+ } else if (sinceDate) {
2176
+ comments = await fetchSince(client, projectId, postId, sinceDate);
2177
+ if (order === "createdAt") comments = [...comments].reverse();
2178
+ } else {
2179
+ const res = await client.getPostComments(projectId, postId, {
2180
+ page: Number(opts.page),
2181
+ size: Number(opts.size),
2182
+ order
2183
+ });
2184
+ comments = res.result;
2185
+ }
2186
+ stopSpinner(true, "\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
2187
+ if (opts.fromAuthor) {
2188
+ const memberId = await resolveMember(client, projectId, opts.fromAuthor);
2189
+ comments = comments.filter(
2190
+ (c) => c.creator?.member?.organizationMemberId === memberId
2191
+ );
2192
+ }
2193
+ if (!globalOpts.json) {
2194
+ let nameMap = /* @__PURE__ */ new Map();
2195
+ try {
2196
+ nameMap = await buildMemberNameMap(client, projectId);
2197
+ } catch {
2198
+ }
2199
+ comments = enrichCommentCreators(comments, nameMap);
2200
+ }
2201
+ formatCommentList(comments, globalOpts);
2202
+ });
2203
+
2204
+ // src/commands/post/comment/latest.ts
2205
+ var import_commander18 = require("commander");
2206
+ 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) => {
2207
+ const globalOpts = commentLatestCommand.optsWithGlobals();
2208
+ const config = await getConfigOrThrow();
2209
+ const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2210
+ const n = Number(opts.count);
2211
+ if (!Number.isFinite(n) || n <= 0) {
2212
+ throw new DoorayCliError("--count\uB294 \uC591\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
2213
+ }
2214
+ if (n > 100) {
2215
+ throw new DoorayCliError("--count\uB294 \uCD5C\uB300 100\uAE4C\uC9C0 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
2216
+ }
2217
+ startSpinner("\uCD5C\uC2E0 \uB313\uAE00 \uC870\uD68C \uC911...");
2218
+ const { projectId, postId } = await resolvePostInput(client, {
2219
+ projectArg: project,
2220
+ postNumberArg: postNumberStr,
2221
+ idOpt: opts.id,
2222
+ urlOpt: opts.url
2223
+ });
1996
2224
  const res = await client.getPostComments(projectId, postId, {
1997
- page: Number(opts.page),
1998
- size: Number(opts.size)
2225
+ page: 0,
2226
+ size: Math.min(n, 100),
2227
+ order: "-createdAt"
1999
2228
  });
2000
- stopSpinner(true, "\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
2001
- let comments = res.result;
2229
+ stopSpinner(true, "\uC870\uD68C \uC644\uB8CC");
2230
+ let comments = res.result.slice(0, n);
2002
2231
  if (!globalOpts.json) {
2003
2232
  let nameMap = /* @__PURE__ */ new Map();
2004
2233
  try {
@@ -2011,8 +2240,8 @@ var commentListCommand = new import_commander15.Command("list").description("\uB
2011
2240
  });
2012
2241
 
2013
2242
  // src/commands/post/comment/add.ts
2014
- var import_commander16 = require("commander");
2015
- var commentAddCommand = new import_commander16.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)").action(async (project, postNumberStr, opts) => {
2243
+ var import_commander19 = require("commander");
2244
+ 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)").action(async (project, postNumberStr, opts) => {
2016
2245
  const globalOpts = commentAddCommand.optsWithGlobals();
2017
2246
  const config = await getConfigOrThrow();
2018
2247
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2046,8 +2275,8 @@ var commentAddCommand = new import_commander16.Command("add").description("\uB31
2046
2275
  });
2047
2276
 
2048
2277
  // src/commands/post/comment/edit.ts
2049
- var import_commander17 = require("commander");
2050
- var commentEditCommand = new import_commander17.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)").action(async (arg1, arg2, arg3, opts) => {
2278
+ var import_commander20 = require("commander");
2279
+ 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)").action(async (arg1, arg2, arg3, opts) => {
2051
2280
  const config = await getConfigOrThrow();
2052
2281
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2053
2282
  let projectArg;
@@ -2123,8 +2352,8 @@ var commentEditCommand = new import_commander17.Command("edit").description("\uB
2123
2352
  });
2124
2353
 
2125
2354
  // src/commands/post/comment/delete.ts
2126
- var import_commander18 = require("commander");
2127
- var commentDeleteCommand = new import_commander18.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) => {
2355
+ var import_commander21 = require("commander");
2356
+ 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) => {
2128
2357
  const config = await getConfigOrThrow();
2129
2358
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2130
2359
  let projectArg;
@@ -2180,13 +2409,13 @@ var commentDeleteCommand = new import_commander18.Command("delete").description(
2180
2409
  });
2181
2410
 
2182
2411
  // src/commands/post/file/list.ts
2183
- var import_commander19 = require("commander");
2412
+ var import_commander22 = require("commander");
2184
2413
  function formatSize(bytes) {
2185
2414
  if (bytes < 1024) return `${bytes}B`;
2186
2415
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
2187
2416
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
2188
2417
  }
2189
- var fileListCommand = new import_commander19.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) => {
2418
+ var fileListCommand = new import_commander22.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) => {
2190
2419
  const globalOpts = fileListCommand.optsWithGlobals();
2191
2420
  const config = await getConfigOrThrow();
2192
2421
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2214,10 +2443,10 @@ var fileListCommand = new import_commander19.Command("list").description("\uC5C5
2214
2443
  });
2215
2444
 
2216
2445
  // src/commands/post/file/download.ts
2217
- var import_commander20 = require("commander");
2446
+ var import_commander23 = require("commander");
2218
2447
  var import_promises8 = require("fs/promises");
2219
2448
  var import_node_path4 = require("path");
2220
- var fileDownloadCommand = new import_commander20.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) => {
2449
+ var fileDownloadCommand = new import_commander23.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) => {
2221
2450
  const config = await getConfigOrThrow();
2222
2451
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2223
2452
  let projectArg;
@@ -2272,10 +2501,10 @@ var fileDownloadCommand = new import_commander20.Command("download").description
2272
2501
  });
2273
2502
 
2274
2503
  // src/commands/post/file/download-all.ts
2275
- var import_commander21 = require("commander");
2504
+ var import_commander24 = require("commander");
2276
2505
  var import_promises9 = require("fs/promises");
2277
2506
  var import_node_path5 = require("path");
2278
- var fileDownloadAllCommand = new import_commander21.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) => {
2507
+ var fileDownloadAllCommand = new import_commander24.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) => {
2279
2508
  const config = await getConfigOrThrow();
2280
2509
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2281
2510
  const spinner = startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
@@ -2308,9 +2537,9 @@ var fileDownloadAllCommand = new import_commander21.Command("download-all").desc
2308
2537
  });
2309
2538
 
2310
2539
  // src/commands/post/file/upload.ts
2311
- var import_commander22 = require("commander");
2540
+ var import_commander25 = require("commander");
2312
2541
  var import_node_path6 = require("path");
2313
- var fileUploadCommand = new import_commander22.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) => {
2542
+ var fileUploadCommand = new import_commander25.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) => {
2314
2543
  const globalOpts = fileUploadCommand.optsWithGlobals();
2315
2544
  const config = await getConfigOrThrow();
2316
2545
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2371,8 +2600,8 @@ var fileUploadCommand = new import_commander22.Command("upload").description("\u
2371
2600
  });
2372
2601
 
2373
2602
  // src/commands/post/file/delete.ts
2374
- var import_commander23 = require("commander");
2375
- var fileDeleteCommand = new import_commander23.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) => {
2603
+ var import_commander26 = require("commander");
2604
+ var fileDeleteCommand = new import_commander26.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) => {
2376
2605
  const config = await getConfigOrThrow();
2377
2606
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2378
2607
  let projectArg;
@@ -2425,7 +2654,7 @@ var fileDeleteCommand = new import_commander23.Command("delete").description("\u
2425
2654
  });
2426
2655
 
2427
2656
  // src/commands/wiki/list.ts
2428
- var import_commander24 = require("commander");
2657
+ var import_commander27 = require("commander");
2429
2658
 
2430
2659
  // src/formatters/wiki.ts
2431
2660
  function formatWikiList(wikis, opts) {
@@ -2468,7 +2697,7 @@ function formatWikiPageDetail(page, opts) {
2468
2697
  }
2469
2698
 
2470
2699
  // src/commands/wiki/list.ts
2471
- var wikiListCommand = new import_commander24.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) => {
2700
+ var wikiListCommand = new import_commander27.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) => {
2472
2701
  const globalOpts = wikiListCommand.optsWithGlobals();
2473
2702
  const config = await getConfigOrThrow();
2474
2703
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2482,7 +2711,7 @@ var wikiListCommand = new import_commander24.Command("list").description("\uC704
2482
2711
  });
2483
2712
 
2484
2713
  // src/commands/wiki/pages.ts
2485
- var import_commander25 = require("commander");
2714
+ var import_commander28 = require("commander");
2486
2715
 
2487
2716
  // src/resolvers/wiki.ts
2488
2717
  async function resolveWiki(client, projectCode) {
@@ -2526,7 +2755,7 @@ async function resolveWikiHomePageId(client, wikiId) {
2526
2755
  }
2527
2756
 
2528
2757
  // src/commands/wiki/pages.ts
2529
- var wikiPagesCommand = new import_commander25.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) => {
2758
+ var wikiPagesCommand = new import_commander28.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) => {
2530
2759
  const globalOpts = wikiPagesCommand.optsWithGlobals();
2531
2760
  const config = await getConfigOrThrow();
2532
2761
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2538,8 +2767,8 @@ var wikiPagesCommand = new import_commander25.Command("pages").description("\uC7
2538
2767
  });
2539
2768
 
2540
2769
  // src/commands/wiki/page-get.ts
2541
- var import_commander26 = require("commander");
2542
- var wikiPageGetCommand = new import_commander26.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) => {
2770
+ var import_commander29 = require("commander");
2771
+ var wikiPageGetCommand = new import_commander29.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) => {
2543
2772
  const globalOpts = wikiPageGetCommand.optsWithGlobals();
2544
2773
  const config = await getConfigOrThrow();
2545
2774
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2551,8 +2780,8 @@ var wikiPageGetCommand = new import_commander26.Command("get").description("\uC7
2551
2780
  });
2552
2781
 
2553
2782
  // src/commands/wiki/page-create.ts
2554
- var import_commander27 = require("commander");
2555
- var wikiPageCreateCommand = new import_commander27.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) => {
2783
+ var import_commander30 = require("commander");
2784
+ var wikiPageCreateCommand = new import_commander30.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) => {
2556
2785
  const globalOpts = wikiPageCreateCommand.optsWithGlobals();
2557
2786
  const config = await getConfigOrThrow();
2558
2787
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2577,8 +2806,8 @@ var wikiPageCreateCommand = new import_commander27.Command("create").description
2577
2806
  });
2578
2807
 
2579
2808
  // src/commands/wiki/page-edit.ts
2580
- var import_commander28 = require("commander");
2581
- var wikiPageEditCommand = new import_commander28.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) => {
2809
+ var import_commander31 = require("commander");
2810
+ var wikiPageEditCommand = new import_commander31.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) => {
2582
2811
  const config = await getConfigOrThrow();
2583
2812
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
2584
2813
  const hasTitle = opts.title != null;
@@ -2631,10 +2860,10 @@ var wikiPageEditCommand = new import_commander28.Command("edit").description("\u
2631
2860
  });
2632
2861
 
2633
2862
  // src/commands/member/index.ts
2634
- var import_commander31 = require("commander");
2863
+ var import_commander34 = require("commander");
2635
2864
 
2636
2865
  // src/commands/member/get.ts
2637
- var import_commander29 = require("commander");
2866
+ var import_commander32 = require("commander");
2638
2867
 
2639
2868
  // src/formatters/member.ts
2640
2869
  function formatMemberDetail(member, opts) {
@@ -2666,7 +2895,7 @@ function formatMemberList(rows, opts) {
2666
2895
  }
2667
2896
 
2668
2897
  // src/commands/member/get.ts
2669
- var memberGetCommand = new import_commander29.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
2898
+ var memberGetCommand = new import_commander32.Command("get").description("\uBA64\uBC84 \uC0C1\uC138 \uC815\uBCF4 \uC870\uD68C (organizationMemberId)").argument("<member-id>", "\uC870\uD68C\uD560 organization member ID").action(async (memberId) => {
2670
2899
  const globalOpts = memberGetCommand.optsWithGlobals();
2671
2900
  const config = await getConfigOrThrow();
2672
2901
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2675,8 +2904,8 @@ var memberGetCommand = new import_commander29.Command("get").description("\uBA64
2675
2904
  });
2676
2905
 
2677
2906
  // src/commands/member/list.ts
2678
- var import_commander30 = require("commander");
2679
- var memberListCommand = new import_commander30.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) => {
2907
+ var import_commander33 = require("commander");
2908
+ var memberListCommand = new import_commander33.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) => {
2680
2909
  const globalOpts = memberListCommand.optsWithGlobals();
2681
2910
  const config = await getConfigOrThrow();
2682
2911
  const client = new DoorayApiClient(config.apiKey, config.baseUrl);
@@ -2691,12 +2920,12 @@ var memberListCommand = new import_commander30.Command("list").description("\uD5
2691
2920
  });
2692
2921
 
2693
2922
  // src/commands/member/index.ts
2694
- var memberCommand = new import_commander31.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
2923
+ var memberCommand = new import_commander34.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
2695
2924
  memberCommand.addCommand(memberGetCommand);
2696
2925
  memberCommand.addCommand(memberListCommand);
2697
2926
 
2698
2927
  // src/commands/mail/list.ts
2699
- var import_commander32 = require("commander");
2928
+ var import_commander35 = require("commander");
2700
2929
 
2701
2930
  // src/api/imapClient.ts
2702
2931
  var import_imapflow = require("imapflow");
@@ -2804,7 +3033,7 @@ async function getMail(config, uid) {
2804
3033
 
2805
3034
  // src/commands/mail/list.ts
2806
3035
  var import_chalk5 = __toESM(require("chalk"));
2807
- var mailListCommand = new import_commander32.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) => {
3036
+ var mailListCommand = new import_commander35.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) => {
2808
3037
  const globalOpts = mailListCommand.optsWithGlobals();
2809
3038
  const config = await getConfigOrThrow();
2810
3039
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -2836,9 +3065,9 @@ var mailListCommand = new import_commander32.Command("list").description("\uBA54
2836
3065
  });
2837
3066
 
2838
3067
  // src/commands/mail/get.ts
2839
- var import_commander33 = require("commander");
3068
+ var import_commander36 = require("commander");
2840
3069
  var import_chalk6 = __toESM(require("chalk"));
2841
- var mailGetCommand = new import_commander33.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
3070
+ var mailGetCommand = new import_commander36.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
2842
3071
  const globalOpts = mailGetCommand.optsWithGlobals();
2843
3072
  const config = await getConfigOrThrow();
2844
3073
  startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
@@ -2869,7 +3098,7 @@ ${mail.body}
2869
3098
  });
2870
3099
 
2871
3100
  // src/commands/mail/send.ts
2872
- var import_commander34 = require("commander");
3101
+ var import_commander37 = require("commander");
2873
3102
  var import_promises10 = require("fs/promises");
2874
3103
 
2875
3104
  // src/api/smtpClient.ts
@@ -2919,7 +3148,7 @@ async function sendMail(config, opts) {
2919
3148
  }
2920
3149
 
2921
3150
  // src/commands/mail/send.ts
2922
- var mailSendCommand = new import_commander34.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) => {
3151
+ var mailSendCommand = new import_commander37.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) => {
2923
3152
  const globalOpts = mailSendCommand.optsWithGlobals();
2924
3153
  const config = await getConfigOrThrow();
2925
3154
  let body = opts.body ?? "";
@@ -2954,7 +3183,7 @@ var mailSendCommand = new import_commander34.Command("send").description("\uBA54
2954
3183
  });
2955
3184
 
2956
3185
  // src/commands/mail/reply.ts
2957
- var import_commander35 = require("commander");
3186
+ var import_commander38 = require("commander");
2958
3187
  var import_promises11 = require("fs/promises");
2959
3188
  var import_imapflow2 = require("imapflow");
2960
3189
  async function getMessageId(config, uid) {
@@ -2982,7 +3211,7 @@ async function getMessageId(config, uid) {
2982
3211
  await client.logout();
2983
3212
  }
2984
3213
  }
2985
- var mailReplyCommand = new import_commander35.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) => {
3214
+ var mailReplyCommand = new import_commander38.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) => {
2986
3215
  const globalOpts = mailReplyCommand.optsWithGlobals();
2987
3216
  const config = await getConfigOrThrow();
2988
3217
  let body = opts.body ?? "";
@@ -3022,20 +3251,201 @@ var mailReplyCommand = new import_commander35.Command("reply").description("\uBA
3022
3251
  }
3023
3252
  });
3024
3253
 
3254
+ // src/commands/feedback.ts
3255
+ var import_commander39 = require("commander");
3256
+ var import_node_child_process2 = require("child_process");
3257
+ var import_node_util = require("util");
3258
+ var import_promises13 = require("fs/promises");
3259
+ var import_node_os3 = require("os");
3260
+ var import_node_path8 = require("path");
3261
+ var import_node_crypto = require("crypto");
3262
+ var import_prompts = require("@inquirer/prompts");
3263
+
3264
+ // src/utils/feedback-meta.ts
3265
+ var import_promises12 = require("fs/promises");
3266
+ var import_node_path7 = require("path");
3267
+ async function readCliVersion() {
3268
+ const entry = process.argv[1];
3269
+ const here = entry ? (0, import_node_path7.dirname)(entry) : process.cwd();
3270
+ const candidates = [
3271
+ (0, import_node_path7.join)(here, "package.json"),
3272
+ (0, import_node_path7.join)(here, "..", "package.json"),
3273
+ (0, import_node_path7.join)(here, "..", "..", "package.json")
3274
+ ];
3275
+ for (const p of candidates) {
3276
+ try {
3277
+ const raw = await (0, import_promises12.readFile)(p, "utf-8");
3278
+ const pkg = JSON.parse(raw);
3279
+ if (pkg.name === "@bifos/dooray-cli" && typeof pkg.version === "string") {
3280
+ return pkg.version;
3281
+ }
3282
+ } catch {
3283
+ }
3284
+ }
3285
+ return "unknown";
3286
+ }
3287
+ function collectMeta(version) {
3288
+ return {
3289
+ cliVersion: version,
3290
+ nodeVersion: process.version,
3291
+ os: process.platform,
3292
+ arch: process.arch
3293
+ };
3294
+ }
3295
+ function buildIssueBody(userBody, meta) {
3296
+ return [
3297
+ "## \uD658\uACBD",
3298
+ `- dooray-cli \uBC84\uC804: ${meta.cliVersion}`,
3299
+ `- Node: ${meta.nodeVersion}`,
3300
+ `- OS: ${meta.os} ${meta.arch}`,
3301
+ "",
3302
+ "## \uC0AC\uC6A9\uC790 \uD53C\uB4DC\uBC31",
3303
+ "",
3304
+ userBody.trim(),
3305
+ ""
3306
+ ].join("\n");
3307
+ }
3308
+
3309
+ // src/commands/feedback.ts
3310
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process2.execFile);
3311
+ var TARGET_REPO = "jon890/dooray-cli";
3312
+ async function ensureGhInstalled() {
3313
+ try {
3314
+ await execFileAsync("gh", ["--version"]);
3315
+ } catch {
3316
+ throw new DoorayCliError(
3317
+ "gh CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.\n \uC124\uCE58: brew install gh (\uB610\uB294 https://cli.github.com)\n \uC124\uCE58 \uD6C4: gh auth login",
3318
+ EXIT_PARAM_ERROR
3319
+ );
3320
+ }
3321
+ }
3322
+ async function readBody(opts) {
3323
+ if (opts.body) return opts.body;
3324
+ if (opts.bodyFile) return await (0, import_promises13.readFile)(opts.bodyFile, "utf-8");
3325
+ return void 0;
3326
+ }
3327
+ var feedbackCommand = new import_commander39.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(
3328
+ "--label <name>",
3329
+ "\uB77C\uBCA8 (\uBC18\uBCF5 \uAC00\uB2A5)",
3330
+ (value, prev) => [...prev, value],
3331
+ []
3332
+ ).option("--dry-run", "gh \uD638\uCD9C \uC5C6\uC774 \uBCF8\uBB38\uB9CC \uBBF8\uB9AC\uBCF4\uAE30").action(async (opts) => {
3333
+ let title = opts.title;
3334
+ let userBody = await readBody(opts);
3335
+ let labels = [...opts.label];
3336
+ if (!title) {
3337
+ title = await (0, import_prompts.input)({ message: "\uC774\uC288 \uC81C\uBAA9" });
3338
+ }
3339
+ if (!title || !title.trim()) {
3340
+ throw new DoorayCliError("\uC81C\uBAA9\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
3341
+ }
3342
+ if (labels.length === 0 && !opts.title && !opts.body && !opts.bodyFile) {
3343
+ const labelInput = await (0, import_prompts.input)({
3344
+ message: "\uB77C\uBCA8 (\uCF64\uB9C8\uB85C \uC5EC\uB7EC \uAC1C, \uBE44\uC6B0\uBA74 \uC5C6\uC74C)",
3345
+ default: ""
3346
+ });
3347
+ labels = labelInput.split(",").map((s) => s.trim()).filter(Boolean);
3348
+ }
3349
+ if (userBody == null) {
3350
+ userBody = await (0, import_prompts.editor)({
3351
+ message: "\uBCF8\uBB38 \uC791\uC131 ($EDITOR\uAC00 \uC5F4\uB9BC)",
3352
+ default: ""
3353
+ });
3354
+ }
3355
+ if (!userBody.trim()) {
3356
+ throw new DoorayCliError("\uBCF8\uBB38\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
3357
+ }
3358
+ const version = await readCliVersion();
3359
+ const meta = collectMeta(version);
3360
+ const issueBody = buildIssueBody(userBody, meta);
3361
+ if (opts.dryRun) {
3362
+ process.stdout.write("--- DRY RUN ---\n");
3363
+ process.stdout.write(`Repo: ${TARGET_REPO}
3364
+ `);
3365
+ process.stdout.write(`Title: ${title}
3366
+ `);
3367
+ process.stdout.write(
3368
+ `Labels: ${labels.length > 0 ? labels.join(", ") : "(\uC5C6\uC74C)"}
3369
+ `
3370
+ );
3371
+ process.stdout.write("Body:\n");
3372
+ process.stdout.write(issueBody);
3373
+ process.stdout.write("--- END ---\n");
3374
+ return;
3375
+ }
3376
+ const isInteractive = !opts.title;
3377
+ if (isInteractive) {
3378
+ process.stderr.write("\n--- \uBBF8\uB9AC\uBCF4\uAE30 ---\n");
3379
+ process.stderr.write(`Repo: ${TARGET_REPO}
3380
+ `);
3381
+ process.stderr.write(`Title: ${title}
3382
+ `);
3383
+ process.stderr.write(
3384
+ `Labels: ${labels.length > 0 ? labels.join(", ") : "(\uC5C6\uC74C)"}
3385
+ `
3386
+ );
3387
+ process.stderr.write("Body:\n");
3388
+ process.stderr.write(issueBody);
3389
+ process.stderr.write("--- \uB05D ---\n\n");
3390
+ const ok = await (0, import_prompts.confirm)({
3391
+ message: "\uC774 \uB0B4\uC6A9\uC73C\uB85C \uB4F1\uB85D\uD560\uAE4C\uC694?",
3392
+ default: true
3393
+ });
3394
+ if (!ok) {
3395
+ process.stderr.write("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\n");
3396
+ return;
3397
+ }
3398
+ }
3399
+ await ensureGhInstalled();
3400
+ const bodyFile = (0, import_node_path8.join)((0, import_node_os3.tmpdir)(), `dooray-feedback-${(0, import_node_crypto.randomUUID)()}.md`);
3401
+ await (0, import_promises13.writeFile)(bodyFile, issueBody);
3402
+ try {
3403
+ const args = [
3404
+ "issue",
3405
+ "create",
3406
+ "--repo",
3407
+ TARGET_REPO,
3408
+ "--title",
3409
+ title,
3410
+ "--body-file",
3411
+ bodyFile
3412
+ ];
3413
+ for (const l of labels) {
3414
+ args.push("--label", l);
3415
+ }
3416
+ const { stdout } = await execFileAsync("gh", args);
3417
+ process.stdout.write(stdout);
3418
+ } catch (err) {
3419
+ const msg = err instanceof Error ? err.message : String(err);
3420
+ throw new DoorayCliError(
3421
+ `GitHub issue \uC0DD\uC131 \uC2E4\uD328:
3422
+ ${msg}
3423
+
3424
+ gh \uC778\uC99D \uC548 \uB418\uC5B4 \uC788\uC73C\uBA74: gh auth login`,
3425
+ EXIT_PARAM_ERROR
3426
+ );
3427
+ } finally {
3428
+ await (0, import_promises13.unlink)(bodyFile).catch(() => {
3429
+ });
3430
+ }
3431
+ });
3432
+
3025
3433
  // src/index.ts
3026
- var program = new import_commander36.Command();
3027
- program.name("dooray").description("Dooray REST API CLI").version("0.5.3").option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "ID\uB9CC \uCD9C\uB825").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654");
3434
+ var program = new import_commander40.Command();
3435
+ program.name("dooray").description("Dooray REST API CLI").version("0.5.4").option("--json", "JSON \uD615\uC2DD\uC73C\uB85C \uCD9C\uB825").option("--quiet", "ID\uB9CC \uCD9C\uB825").option("--no-color", "\uC0C9\uC0C1 \uBE44\uD65C\uC131\uD654");
3028
3436
  program.hook("preAction", () => {
3029
3437
  const opts = program.opts();
3030
3438
  if (opts.color === false || process.env.NO_COLOR) {
3031
3439
  import_chalk7.default.level = 0;
3032
3440
  }
3033
3441
  });
3034
- var projectCommand = new import_commander36.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
3442
+ var projectCommand = new import_commander40.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
3035
3443
  projectCommand.addCommand(projectListCommand);
3036
3444
  projectCommand.addCommand(projectMembersCommand);
3037
3445
  projectCommand.addCommand(projectWorkflowsCommand);
3038
- var postCommand = new import_commander36.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
3446
+ projectCommand.addCommand(projectGroupsCommand);
3447
+ projectCommand.addCommand(projectTagsCommand);
3448
+ var postCommand = new import_commander40.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
3039
3449
  postCommand.addCommand(postListCommand);
3040
3450
  postCommand.addCommand(postSearchCommand);
3041
3451
  postCommand.addCommand(postGetCommand);
@@ -3043,28 +3453,29 @@ postCommand.addCommand(postEditCommand);
3043
3453
  postCommand.addCommand(postCreateCommand);
3044
3454
  postCommand.addCommand(postDoneCommand);
3045
3455
  postCommand.addCommand(postWorkflowCommand);
3046
- var commentCommand = new import_commander36.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
3456
+ var commentCommand = new import_commander40.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
3047
3457
  commentCommand.addCommand(commentListCommand);
3458
+ commentCommand.addCommand(commentLatestCommand);
3048
3459
  commentCommand.addCommand(commentAddCommand);
3049
3460
  commentCommand.addCommand(commentEditCommand);
3050
3461
  commentCommand.addCommand(commentDeleteCommand);
3051
3462
  postCommand.addCommand(commentCommand);
3052
- var fileCommand = new import_commander36.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
3463
+ var fileCommand = new import_commander40.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
3053
3464
  fileCommand.addCommand(fileListCommand);
3054
3465
  fileCommand.addCommand(fileDownloadCommand);
3055
3466
  fileCommand.addCommand(fileDownloadAllCommand);
3056
3467
  fileCommand.addCommand(fileUploadCommand);
3057
3468
  fileCommand.addCommand(fileDeleteCommand);
3058
3469
  postCommand.addCommand(fileCommand);
3059
- var wikiCommand = new import_commander36.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
3470
+ var wikiCommand = new import_commander40.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
3060
3471
  wikiCommand.addCommand(wikiListCommand);
3061
3472
  wikiCommand.addCommand(wikiPagesCommand);
3062
- var wikiPageCommand = new import_commander36.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
3473
+ var wikiPageCommand = new import_commander40.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
3063
3474
  wikiPageCommand.addCommand(wikiPageGetCommand);
3064
3475
  wikiPageCommand.addCommand(wikiPageCreateCommand);
3065
3476
  wikiPageCommand.addCommand(wikiPageEditCommand);
3066
3477
  wikiCommand.addCommand(wikiPageCommand);
3067
- var mailCommand = new import_commander36.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
3478
+ var mailCommand = new import_commander40.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
3068
3479
  mailCommand.addCommand(mailListCommand);
3069
3480
  mailCommand.addCommand(mailGetCommand);
3070
3481
  mailCommand.addCommand(mailSendCommand);
@@ -3078,6 +3489,7 @@ program.addCommand(projectCommand);
3078
3489
  program.addCommand(postCommand);
3079
3490
  program.addCommand(wikiCommand);
3080
3491
  program.addCommand(mailCommand);
3492
+ program.addCommand(feedbackCommand);
3081
3493
  program.parseAsync().catch((err) => {
3082
3494
  if (err instanceof DoorayCliError) {
3083
3495
  process.stderr.write(import_chalk7.default.red(`\uC624\uB958: ${err.message}`) + "\n");