@bifos/dooray-cli 0.4.0 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -6
- package/dist/index.js +1028 -243
- package/package.json +7 -3
- package/skills/dooray-cli/SKILL.md +269 -0
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
|
|
27
|
+
var import_commander36 = require("commander");
|
|
28
28
|
var import_chalk7 = __toESM(require("chalk"));
|
|
29
29
|
|
|
30
30
|
// src/commands/config.ts
|
|
@@ -195,23 +195,27 @@ var import_node_os2 = require("os");
|
|
|
195
195
|
var CACHE_DIR = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".dooray", "cache");
|
|
196
196
|
var ME_PATH = (0, import_node_path2.join)(CACHE_DIR, "me.json");
|
|
197
197
|
var PROJECTS_PATH = (0, import_node_path2.join)(CACHE_DIR, "projects.json");
|
|
198
|
+
var PROJECTS_PRIVATE_PATH = (0, import_node_path2.join)(CACHE_DIR, "projects-private.json");
|
|
198
199
|
var MEMBERS_DIR = (0, import_node_path2.join)(CACHE_DIR, "members");
|
|
199
200
|
var WORKFLOWS_DIR = (0, import_node_path2.join)(CACHE_DIR, "workflows");
|
|
201
|
+
var TAGS_DIR = (0, import_node_path2.join)(CACHE_DIR, "tags");
|
|
202
|
+
var MILESTONES_DIR = (0, import_node_path2.join)(CACHE_DIR, "milestones");
|
|
203
|
+
var WIKIS_PATH = (0, import_node_path2.join)(CACHE_DIR, "wikis.json");
|
|
200
204
|
async function ensureDir2(dir) {
|
|
201
205
|
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
202
206
|
}
|
|
203
|
-
async function readJson(
|
|
207
|
+
async function readJson(path3) {
|
|
204
208
|
try {
|
|
205
|
-
const raw = await (0, import_promises2.readFile)(
|
|
209
|
+
const raw = await (0, import_promises2.readFile)(path3, "utf-8");
|
|
206
210
|
return JSON.parse(raw);
|
|
207
211
|
} catch {
|
|
208
212
|
return null;
|
|
209
213
|
}
|
|
210
214
|
}
|
|
211
|
-
async function writeJson(
|
|
212
|
-
const dir =
|
|
215
|
+
async function writeJson(path3, data) {
|
|
216
|
+
const dir = path3.substring(0, path3.lastIndexOf("/"));
|
|
213
217
|
await ensureDir2(dir);
|
|
214
|
-
await (0, import_promises2.writeFile)(
|
|
218
|
+
await (0, import_promises2.writeFile)(path3, JSON.stringify(data, null, 2) + "\n");
|
|
215
219
|
}
|
|
216
220
|
function isExpired(updatedAt, ttlMs) {
|
|
217
221
|
if (!updatedAt) return true;
|
|
@@ -232,6 +236,12 @@ async function getProjects() {
|
|
|
232
236
|
async function setProjects(items) {
|
|
233
237
|
await writeJson(PROJECTS_PATH, { updatedAt: now(), data: items });
|
|
234
238
|
}
|
|
239
|
+
async function getPrivateProjects() {
|
|
240
|
+
return readJson(PROJECTS_PRIVATE_PATH);
|
|
241
|
+
}
|
|
242
|
+
async function setPrivateProjects(items) {
|
|
243
|
+
await writeJson(PROJECTS_PRIVATE_PATH, { updatedAt: now(), data: items });
|
|
244
|
+
}
|
|
235
245
|
function membersPath(projectId) {
|
|
236
246
|
return (0, import_node_path2.join)(MEMBERS_DIR, `${projectId}.json`);
|
|
237
247
|
}
|
|
@@ -250,6 +260,30 @@ async function getWorkflows(projectId) {
|
|
|
250
260
|
async function setWorkflows(projectId, items) {
|
|
251
261
|
await writeJson(workflowsPath(projectId), { updatedAt: now(), data: items });
|
|
252
262
|
}
|
|
263
|
+
function tagsPath(projectId) {
|
|
264
|
+
return (0, import_node_path2.join)(TAGS_DIR, `${projectId}.json`);
|
|
265
|
+
}
|
|
266
|
+
async function getTags(projectId) {
|
|
267
|
+
return readJson(tagsPath(projectId));
|
|
268
|
+
}
|
|
269
|
+
async function setTags(projectId, items) {
|
|
270
|
+
await writeJson(tagsPath(projectId), { updatedAt: now(), data: items });
|
|
271
|
+
}
|
|
272
|
+
function milestonesPath(projectId) {
|
|
273
|
+
return (0, import_node_path2.join)(MILESTONES_DIR, `${projectId}.json`);
|
|
274
|
+
}
|
|
275
|
+
async function getMilestones(projectId) {
|
|
276
|
+
return readJson(milestonesPath(projectId));
|
|
277
|
+
}
|
|
278
|
+
async function setMilestones(projectId, items) {
|
|
279
|
+
await writeJson(milestonesPath(projectId), { updatedAt: now(), data: items });
|
|
280
|
+
}
|
|
281
|
+
async function getWikis() {
|
|
282
|
+
return readJson(WIKIS_PATH);
|
|
283
|
+
}
|
|
284
|
+
async function setWikis(items) {
|
|
285
|
+
await writeJson(WIKIS_PATH, { updatedAt: now(), data: items });
|
|
286
|
+
}
|
|
253
287
|
async function clearCache() {
|
|
254
288
|
try {
|
|
255
289
|
await (0, import_promises2.rm)(CACHE_DIR, { recursive: true, force: true });
|
|
@@ -271,8 +305,20 @@ async function getCacheStats() {
|
|
|
271
305
|
workflowProjectCount = files.filter((f) => f.endsWith(".json")).length;
|
|
272
306
|
} catch {
|
|
273
307
|
}
|
|
308
|
+
let tagProjectCount = 0;
|
|
309
|
+
try {
|
|
310
|
+
const files = await (0, import_promises2.readdir)(TAGS_DIR);
|
|
311
|
+
tagProjectCount = files.filter((f) => f.endsWith(".json")).length;
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
let milestoneProjectCount = 0;
|
|
315
|
+
try {
|
|
316
|
+
const files = await (0, import_promises2.readdir)(MILESTONES_DIR);
|
|
317
|
+
milestoneProjectCount = files.filter((f) => f.endsWith(".json")).length;
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
274
320
|
const me = await getMe();
|
|
275
|
-
return { projectCount, memberProjectCount, workflowProjectCount, me: me?.data ?? null };
|
|
321
|
+
return { projectCount, memberProjectCount, workflowProjectCount, tagProjectCount, milestoneProjectCount, me: me?.data ?? null };
|
|
276
322
|
}
|
|
277
323
|
|
|
278
324
|
// src/commands/cache.ts
|
|
@@ -289,11 +335,24 @@ cacheCommand.command("refresh").description("\uCE90\uC2DC \uAC31\uC2E0 (API \uD0
|
|
|
289
335
|
// src/commands/doctor.ts
|
|
290
336
|
var import_commander3 = require("commander");
|
|
291
337
|
var import_chalk3 = __toESM(require("chalk"));
|
|
338
|
+
var import_path = __toESM(require("path"));
|
|
339
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
292
340
|
|
|
293
341
|
// src/api/client.ts
|
|
294
342
|
var import_ky = __toESM(require("ky"));
|
|
295
343
|
var import_promises3 = require("fs/promises");
|
|
296
344
|
var import_node_path3 = require("path");
|
|
345
|
+
|
|
346
|
+
// src/utils/dooray-message.ts
|
|
347
|
+
function normalizeDoorayMessage(raw) {
|
|
348
|
+
try {
|
|
349
|
+
return decodeURIComponent(raw.replace(/\+/g, " "));
|
|
350
|
+
} catch {
|
|
351
|
+
return raw;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/api/client.ts
|
|
297
356
|
function joinIds(ids) {
|
|
298
357
|
return ids && ids.length > 0 ? ids.join(",") : void 0;
|
|
299
358
|
}
|
|
@@ -304,7 +363,7 @@ async function toDoorayCliError(error) {
|
|
|
304
363
|
try {
|
|
305
364
|
const body = await error.response.json();
|
|
306
365
|
throw new DoorayCliError(
|
|
307
|
-
`API \uD638\uCD9C \uC2E4\uD328: ${body.header.resultMessage}`,
|
|
366
|
+
`API \uD638\uCD9C \uC2E4\uD328: ${normalizeDoorayMessage(body.header.resultMessage)}`,
|
|
308
367
|
exitCode
|
|
309
368
|
);
|
|
310
369
|
} catch (e) {
|
|
@@ -390,6 +449,13 @@ var DoorayApiClient = class {
|
|
|
390
449
|
return toDoorayCliError(e);
|
|
391
450
|
}
|
|
392
451
|
}
|
|
452
|
+
async getPostStandalone(postId) {
|
|
453
|
+
try {
|
|
454
|
+
return await this.api.get(`project/v1/posts/${postId}`).json();
|
|
455
|
+
} catch (e) {
|
|
456
|
+
return toDoorayCliError(e);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
393
459
|
async createPost(projectId, body) {
|
|
394
460
|
try {
|
|
395
461
|
return await this.api.post(`project/v1/projects/${projectId}/posts`, { json: body }).json();
|
|
@@ -493,6 +559,32 @@ var DoorayApiClient = class {
|
|
|
493
559
|
return toDoorayCliError(e);
|
|
494
560
|
}
|
|
495
561
|
}
|
|
562
|
+
// ─── Tags ───────────────────────────────────────────
|
|
563
|
+
async getProjectTags(projectId, params) {
|
|
564
|
+
try {
|
|
565
|
+
return await this.api.get(`project/v1/projects/${projectId}/tags`, {
|
|
566
|
+
searchParams: {
|
|
567
|
+
...params?.page != null && { page: params.page },
|
|
568
|
+
...params?.size != null && { size: params.size }
|
|
569
|
+
}
|
|
570
|
+
}).json();
|
|
571
|
+
} catch (e) {
|
|
572
|
+
return toDoorayCliError(e);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
// ─── Milestones ─────────────────────────────────────
|
|
576
|
+
async getProjectMilestones(projectId, params) {
|
|
577
|
+
try {
|
|
578
|
+
return await this.api.get(`project/v1/projects/${projectId}/milestones`, {
|
|
579
|
+
searchParams: {
|
|
580
|
+
...params?.page != null && { page: params.page },
|
|
581
|
+
...params?.size != null && { size: params.size }
|
|
582
|
+
}
|
|
583
|
+
}).json();
|
|
584
|
+
} catch (e) {
|
|
585
|
+
return toDoorayCliError(e);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
496
588
|
// ─── Wiki ───────────────────────────────────────────
|
|
497
589
|
async getWikis(params) {
|
|
498
590
|
try {
|
|
@@ -538,6 +630,20 @@ var DoorayApiClient = class {
|
|
|
538
630
|
return toDoorayCliError(e);
|
|
539
631
|
}
|
|
540
632
|
}
|
|
633
|
+
async updateWikiPageTitle(wikiId, pageId, body) {
|
|
634
|
+
try {
|
|
635
|
+
return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}/title`, { json: body }).json();
|
|
636
|
+
} catch (e) {
|
|
637
|
+
return toDoorayCliError(e);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
async updateWikiPageContent(wikiId, pageId, body) {
|
|
641
|
+
try {
|
|
642
|
+
return await this.api.put(`wiki/v1/wikis/${wikiId}/pages/${pageId}/content`, { json: body }).json();
|
|
643
|
+
} catch (e) {
|
|
644
|
+
return toDoorayCliError(e);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
541
647
|
// ─── Post Files ─────────────────────────────────────
|
|
542
648
|
async getPostFiles(projectId, postId) {
|
|
543
649
|
try {
|
|
@@ -636,6 +742,10 @@ var PROJECTS_TTL_MS = 36e5;
|
|
|
636
742
|
var MEMBERS_TTL_MS = 36e5;
|
|
637
743
|
var WORKFLOWS_TTL_MS = 864e5;
|
|
638
744
|
var ME_TTL_MS = 864e5;
|
|
745
|
+
var TAGS_TTL_MS = 864e5;
|
|
746
|
+
var MILESTONES_TTL_MS = 864e5;
|
|
747
|
+
var RESOLVER_FETCH_PAGE_SIZE = 100;
|
|
748
|
+
var WIKIS_TTL_MS = 864e5;
|
|
639
749
|
|
|
640
750
|
// src/resolvers/me.ts
|
|
641
751
|
async function ensureMe(client) {
|
|
@@ -675,6 +785,37 @@ var doctorCommand = new import_commander3.Command("doctor").description("\uC124\
|
|
|
675
785
|
console.log(` \uD504\uB85C\uC81D\uD2B8: ${stats.projectCount}\uAC1C`);
|
|
676
786
|
console.log(` \uBA64\uBC84: ${stats.memberProjectCount}\uAC1C \uD504\uB85C\uC81D\uD2B8`);
|
|
677
787
|
console.log(` \uC6CC\uD06C\uD50C\uB85C\uC6B0: ${stats.workflowProjectCount}\uAC1C \uD504\uB85C\uC81D\uD2B8`);
|
|
788
|
+
console.log(` Tag \uCE90\uC2DC (\uD504\uB85C\uC81D\uD2B8 \uC218): ${stats.tagProjectCount}`);
|
|
789
|
+
console.log(` Milestone \uCE90\uC2DC (\uD504\uB85C\uC81D\uD2B8 \uC218): ${stats.milestoneProjectCount}`);
|
|
790
|
+
const claudeDir = import_path.default.join(
|
|
791
|
+
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
792
|
+
".claude"
|
|
793
|
+
);
|
|
794
|
+
const claudeDirExists = await import_promises4.default.access(claudeDir).then(() => true).catch(() => false);
|
|
795
|
+
if (claudeDirExists) {
|
|
796
|
+
console.log(import_chalk3.default.bold("\n\u{1F527} Claude Code \uC2A4\uD0AC\n"));
|
|
797
|
+
const skillDst = import_path.default.join(claudeDir, "skills", "dooray-cli");
|
|
798
|
+
try {
|
|
799
|
+
const stat2 = await import_promises4.default.lstat(skillDst);
|
|
800
|
+
if (stat2.isSymbolicLink()) {
|
|
801
|
+
const target = await import_promises4.default.readlink(skillDst);
|
|
802
|
+
const targetExists = await import_promises4.default.access(target).then(() => true).catch(() => false);
|
|
803
|
+
if (targetExists) {
|
|
804
|
+
console.log(` dooray-cli: ${import_chalk3.default.green("\u2705 \uC124\uCE58\uB428 (\uC2EC\uBCFC\uB9AD \uB9C1\uD06C)")}`);
|
|
805
|
+
} else {
|
|
806
|
+
console.log(
|
|
807
|
+
` dooray-cli: ${import_chalk3.default.yellow("\u26A0\uFE0F \uB9C1\uD06C \uAE68\uC9D0 \u2014 dooray setup\uC73C\uB85C \uC7AC\uC124\uCE58")}`
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
} else {
|
|
811
|
+
console.log(` dooray-cli: ${import_chalk3.default.green("\u2705 \uC124\uCE58\uB428 (\uBCF5\uC0AC\uBCF8)")}`);
|
|
812
|
+
}
|
|
813
|
+
} catch {
|
|
814
|
+
console.log(
|
|
815
|
+
` dooray-cli: ${import_chalk3.default.red("\u274C \uBBF8\uC124\uCE58 \u2014 dooray setup\uC73C\uB85C \uC124\uCE58")}`
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
678
819
|
console.log();
|
|
679
820
|
if (apiKeyOk && baseUrlOk) {
|
|
680
821
|
console.log(import_chalk3.default.green("\u2713 \uAE30\uBCF8 \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
@@ -688,6 +829,8 @@ var doctorCommand = new import_commander3.Command("doctor").description("\uC124\
|
|
|
688
829
|
// src/commands/setup.ts
|
|
689
830
|
var import_commander4 = require("commander");
|
|
690
831
|
var import_chalk4 = __toESM(require("chalk"));
|
|
832
|
+
var import_path2 = __toESM(require("path"));
|
|
833
|
+
var import_promises5 = __toESM(require("fs/promises"));
|
|
691
834
|
var setupCommand = new import_commander4.Command("setup").description("\uB300\uD654\uD615 \uCD08\uAE30 \uC124\uC815 \uB9C8\uBC95\uC0AC").action(async () => {
|
|
692
835
|
const { input, select, password, confirm } = await import("@inquirer/prompts");
|
|
693
836
|
const existing = await getConfig();
|
|
@@ -760,6 +903,45 @@ var setupCommand = new import_commander4.Command("setup").description("\uB300\uD
|
|
|
760
903
|
theme: { prefix: "\u{1F512}" }
|
|
761
904
|
});
|
|
762
905
|
}
|
|
906
|
+
const claudeDir = import_path2.default.join(
|
|
907
|
+
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
908
|
+
".claude"
|
|
909
|
+
);
|
|
910
|
+
const claudeDirExists = await import_promises5.default.access(claudeDir).then(() => true).catch(() => false);
|
|
911
|
+
if (claudeDirExists) {
|
|
912
|
+
const isNpx = /_npx[/\\]/.test(__dirname) || /\.npm[/\\]_npx/.test(__dirname) || /npx-/.test(__dirname);
|
|
913
|
+
if (isNpx) {
|
|
914
|
+
console.log(
|
|
915
|
+
import_chalk4.default.yellow(
|
|
916
|
+
" \u26A0 npx \uD658\uACBD\uC5D0\uC11C\uB294 \uC2A4\uD0AC \uC124\uCE58\uAC00 \uBD88\uAC00\uD569\uB2C8\uB2E4. npm i -g @bifos/dooray-cli \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."
|
|
917
|
+
)
|
|
918
|
+
);
|
|
919
|
+
} else {
|
|
920
|
+
const installSkill = await confirm({
|
|
921
|
+
message: "Claude Code \uC2A4\uD0AC\uC744 \uC124\uCE58\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?",
|
|
922
|
+
default: true,
|
|
923
|
+
theme: { prefix: "\u{1F527}" }
|
|
924
|
+
});
|
|
925
|
+
if (installSkill) {
|
|
926
|
+
try {
|
|
927
|
+
const skillSrc = import_path2.default.resolve(__dirname, "../skills/dooray-cli");
|
|
928
|
+
const skillsDir = import_path2.default.join(claudeDir, "skills");
|
|
929
|
+
const skillDst = import_path2.default.join(skillsDir, "dooray-cli");
|
|
930
|
+
await import_promises5.default.mkdir(skillsDir, { recursive: true });
|
|
931
|
+
await import_promises5.default.lstat(skillDst).then(() => import_promises5.default.rm(skillDst, { recursive: true, force: true })).catch(() => {
|
|
932
|
+
});
|
|
933
|
+
await import_promises5.default.symlink(skillSrc, skillDst);
|
|
934
|
+
console.log(import_chalk4.default.green(" \u2713 Claude Code \uC2A4\uD0AC \uC124\uCE58 \uC644\uB8CC"));
|
|
935
|
+
} catch (err) {
|
|
936
|
+
console.log(
|
|
937
|
+
import_chalk4.default.yellow(
|
|
938
|
+
` \u26A0 \uC2A4\uD0AC \uC124\uCE58 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}`
|
|
939
|
+
)
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
763
945
|
const config = {
|
|
764
946
|
version: 1,
|
|
765
947
|
apiKey,
|
|
@@ -791,12 +973,12 @@ var setupCommand = new import_commander4.Command("setup").description("\uB300\uD
|
|
|
791
973
|
var import_commander5 = require("commander");
|
|
792
974
|
|
|
793
975
|
// src/resolvers/project.ts
|
|
794
|
-
async function fetchAllProjects(client) {
|
|
976
|
+
async function fetchAllProjects(client, options) {
|
|
795
977
|
const all = [];
|
|
796
978
|
let page = 0;
|
|
797
979
|
const size = 100;
|
|
798
980
|
while (true) {
|
|
799
|
-
const res = await client.getProjects({ page, size });
|
|
981
|
+
const res = await client.getProjects({ page, size, type: options?.type });
|
|
800
982
|
for (const p of res.result) {
|
|
801
983
|
all.push({
|
|
802
984
|
id: p.id,
|
|
@@ -818,12 +1000,27 @@ async function ensureProjects(client) {
|
|
|
818
1000
|
await setProjects(items);
|
|
819
1001
|
return items;
|
|
820
1002
|
}
|
|
1003
|
+
async function ensurePrivateProjects(client) {
|
|
1004
|
+
const entry = await getPrivateProjects();
|
|
1005
|
+
if (entry && !isExpired(entry.updatedAt, PROJECTS_TTL_MS)) {
|
|
1006
|
+
return entry.data;
|
|
1007
|
+
}
|
|
1008
|
+
const items = await fetchAllProjects(client, { type: "private" });
|
|
1009
|
+
await setPrivateProjects(items);
|
|
1010
|
+
return items;
|
|
1011
|
+
}
|
|
821
1012
|
async function resolveProject(client, input) {
|
|
822
1013
|
const projects = await ensureProjects(client);
|
|
823
1014
|
const match = projects.find((p) => p.code === input || p.id === input);
|
|
824
1015
|
if (match) return match.id;
|
|
1016
|
+
const privateCached = await getPrivateProjects();
|
|
1017
|
+
if (privateCached && !isExpired(privateCached.updatedAt, PROJECTS_TTL_MS)) {
|
|
1018
|
+
const privateMatch = privateCached.data.find((p) => p.code === input || p.id === input);
|
|
1019
|
+
if (privateMatch) return privateMatch.id;
|
|
1020
|
+
}
|
|
825
1021
|
throw new DoorayCliError(
|
|
826
|
-
`\uD504\uB85C\uC81D\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}
|
|
1022
|
+
`\uD504\uB85C\uC81D\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}
|
|
1023
|
+
\uAC1C\uC778 \uD504\uB85C\uC81D\uD2B8\uB77C\uBA74: dooray project list --type private \uB85C \uCE90\uC2DC\uB97C \uAC31\uC2E0\uD558\uC138\uC694`,
|
|
827
1024
|
EXIT_PARAM_ERROR
|
|
828
1025
|
);
|
|
829
1026
|
}
|
|
@@ -871,13 +1068,16 @@ function stopSpinner(success, text) {
|
|
|
871
1068
|
}
|
|
872
1069
|
|
|
873
1070
|
// src/commands/project/list.ts
|
|
874
|
-
var projectListCommand = new import_commander5.Command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C").option("-s, --search <keyword>", "code \uD544\uD130\uB9C1").
|
|
1071
|
+
var projectListCommand = new import_commander5.Command("list").description("\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C").option("-s, --search <keyword>", "code \uD544\uD130\uB9C1").addOption(
|
|
1072
|
+
new import_commander5.Option("-t, --type <type>", "\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785 \uD544\uD130").choices(["public", "private"]).default("public")
|
|
1073
|
+
).action(async (opts) => {
|
|
875
1074
|
const globalOpts = projectListCommand.optsWithGlobals();
|
|
876
1075
|
const config = await getConfigOrThrow();
|
|
877
1076
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1077
|
+
const isPrivate = opts.type === "private";
|
|
1078
|
+
startSpinner(isPrivate ? "\uAC1C\uC778 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911..." : "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1079
|
+
const projects = isPrivate ? await ensurePrivateProjects(client) : await ensureProjects(client);
|
|
1080
|
+
stopSpinner(true, isPrivate ? "\uAC1C\uC778 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC" : "\uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
881
1081
|
let filtered = projects;
|
|
882
1082
|
if (opts.search) {
|
|
883
1083
|
const keyword = opts.search.toLowerCase();
|
|
@@ -894,6 +1094,32 @@ var projectListCommand = new import_commander5.Command("list").description("\uD5
|
|
|
894
1094
|
// src/commands/project/members.ts
|
|
895
1095
|
var import_commander6 = require("commander");
|
|
896
1096
|
|
|
1097
|
+
// src/resolvers/match.ts
|
|
1098
|
+
function matchByName(items, input, label, renderCandidate) {
|
|
1099
|
+
const exact = items.filter((i) => i.name === input);
|
|
1100
|
+
if (exact.length === 1) return exact[0];
|
|
1101
|
+
if (exact.length > 1) {
|
|
1102
|
+
throw new DoorayCliError(
|
|
1103
|
+
`\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4(\uC815\uD655\uC77C\uCE58): "${input}"
|
|
1104
|
+
` + exact.map((i) => ` - ${renderCandidate(i)}`).join("\n"),
|
|
1105
|
+
EXIT_PARAM_ERROR
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
const partial = items.filter((i) => i.name.includes(input));
|
|
1109
|
+
if (partial.length === 1) return partial[0];
|
|
1110
|
+
if (partial.length > 1) {
|
|
1111
|
+
throw new DoorayCliError(
|
|
1112
|
+
`\uBCF5\uC218\uC758 ${label}\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4: "${input}"
|
|
1113
|
+
` + partial.map((i) => ` - ${renderCandidate(i)}`).join("\n"),
|
|
1114
|
+
EXIT_PARAM_ERROR
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
throw new DoorayCliError(
|
|
1118
|
+
`${label}\uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input}`,
|
|
1119
|
+
EXIT_PARAM_ERROR
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
897
1123
|
// src/resolvers/member.ts
|
|
898
1124
|
async function fetchAllMembers(client, projectId) {
|
|
899
1125
|
const memberIds = [];
|
|
@@ -935,22 +1161,23 @@ async function ensureMembers(client, projectId) {
|
|
|
935
1161
|
await setMembers(projectId, items);
|
|
936
1162
|
return items;
|
|
937
1163
|
}
|
|
938
|
-
async function
|
|
1164
|
+
async function buildMemberNameMap(client, projectId) {
|
|
939
1165
|
const members = await ensureMembers(client, projectId);
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
const candidates = byName.map((m) => ` - ${m.name} (${m.organizationMemberId})`).join("\n");
|
|
944
|
-
throw new DoorayCliError(
|
|
945
|
-
`\uBCF5\uC218\uC758 \uBA64\uBC84\uAC00 \uB9E4\uCE6D\uB429\uB2C8\uB2E4: "${input}"
|
|
946
|
-
${candidates}`,
|
|
947
|
-
EXIT_PARAM_ERROR
|
|
948
|
-
);
|
|
1166
|
+
const map = /* @__PURE__ */ new Map();
|
|
1167
|
+
for (const m of members) {
|
|
1168
|
+
if (m.name) map.set(m.organizationMemberId, m.name);
|
|
949
1169
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1170
|
+
return map;
|
|
1171
|
+
}
|
|
1172
|
+
async function resolveMember(client, projectId, input) {
|
|
1173
|
+
const members = await ensureMembers(client, projectId);
|
|
1174
|
+
const match = matchByName(
|
|
1175
|
+
members,
|
|
1176
|
+
input,
|
|
1177
|
+
"\uBA64\uBC84",
|
|
1178
|
+
(m) => `${m.name} (${m.organizationMemberId})`
|
|
953
1179
|
);
|
|
1180
|
+
return match.organizationMemberId;
|
|
954
1181
|
}
|
|
955
1182
|
|
|
956
1183
|
// src/commands/project/members.ts
|
|
@@ -994,12 +1221,16 @@ async function ensureWorkflows(client, projectId) {
|
|
|
994
1221
|
}
|
|
995
1222
|
async function resolveWorkflow(client, projectId, input) {
|
|
996
1223
|
const workflows = await ensureWorkflows(client, projectId);
|
|
997
|
-
const
|
|
998
|
-
if (
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1224
|
+
const byClass = workflows.filter((w) => w.class === input);
|
|
1225
|
+
if (byClass.length === 1) return byClass[0].id;
|
|
1226
|
+
if (byClass.length > 1) {
|
|
1227
|
+
throw new DoorayCliError(
|
|
1228
|
+
`\uB3D9\uC77C class\uC758 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4: "${input}"`,
|
|
1229
|
+
EXIT_PARAM_ERROR
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
const match = matchByName(workflows, input, "\uC6CC\uD06C\uD50C\uB85C\uC6B0", (w) => `${w.name} [${w.class}] (${w.id})`);
|
|
1233
|
+
return match.id;
|
|
1003
1234
|
}
|
|
1004
1235
|
|
|
1005
1236
|
// src/commands/project/workflows.ts
|
|
@@ -1139,14 +1370,95 @@ async function resolvePost(client, projectId, postNumber) {
|
|
|
1139
1370
|
return res.result[0].id;
|
|
1140
1371
|
}
|
|
1141
1372
|
|
|
1373
|
+
// src/utils/dooray-url.ts
|
|
1374
|
+
var TASK_URL_RE = /^https?:\/\/[\w.-]+\.dooray\.com\/task\/to\/(\d+)(?:[/?#].*)?$/;
|
|
1375
|
+
function parseDoorayTaskUrl(input) {
|
|
1376
|
+
const m = TASK_URL_RE.exec(input);
|
|
1377
|
+
return m ? m[1] : null;
|
|
1378
|
+
}
|
|
1379
|
+
function isLikelyDoorayUrl(input) {
|
|
1380
|
+
return /^https?:\/\//.test(input);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// src/resolvers/post-input.ts
|
|
1384
|
+
var INPUT_HELP = "\uC5C5\uBB34\uB97C \uC2DD\uBCC4\uD560 \uC815\uBCF4\uAC00 \uBD80\uC871\uD569\uB2C8\uB2E4. \uB2E4\uC74C \uC911 \uD558\uB098\uB97C \uC785\uB825\uD558\uC138\uC694:\n - <project> <post-number> \uC608: tc-ocr 337\n - --id <postId> \uC608: --id 4319587406666362045\n - <Dooray URL> \uC608: https://x.dooray.com/task/to/4319587406666362045";
|
|
1385
|
+
async function resolveByPostId(client, postId) {
|
|
1386
|
+
const res = await client.getPostStandalone(postId);
|
|
1387
|
+
const d = res.result;
|
|
1388
|
+
return {
|
|
1389
|
+
projectId: d.project.id,
|
|
1390
|
+
projectCode: d.project.code,
|
|
1391
|
+
postId: d.id,
|
|
1392
|
+
postNumber: d.number
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
async function resolvePostInput(client, args) {
|
|
1396
|
+
const { projectArg, postNumberArg, idOpt, urlOpt } = args;
|
|
1397
|
+
const hasPositional = !!projectArg || !!postNumberArg;
|
|
1398
|
+
if (idOpt && urlOpt) {
|
|
1399
|
+
throw new DoorayCliError(
|
|
1400
|
+
"--id\uC640 --url\uC740 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
1401
|
+
EXIT_PARAM_ERROR
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
if ((idOpt || urlOpt) && hasPositional) {
|
|
1405
|
+
throw new DoorayCliError(
|
|
1406
|
+
"--id/--url\uACFC positional \uC778\uC790(<project> <post-number>)\uB294 \uB3D9\uC2DC\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
1407
|
+
EXIT_PARAM_ERROR
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
if (urlOpt) {
|
|
1411
|
+
const postId = parseDoorayTaskUrl(urlOpt);
|
|
1412
|
+
if (!postId) {
|
|
1413
|
+
throw new DoorayCliError(
|
|
1414
|
+
`--url \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${urlOpt}"
|
|
1415
|
+
\uC608: https://x.dooray.com/task/to/4319587406666362045`,
|
|
1416
|
+
EXIT_PARAM_ERROR
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
return resolveByPostId(client, postId);
|
|
1420
|
+
}
|
|
1421
|
+
if (idOpt) {
|
|
1422
|
+
return resolveByPostId(client, idOpt);
|
|
1423
|
+
}
|
|
1424
|
+
if (projectArg && !postNumberArg && isLikelyDoorayUrl(projectArg)) {
|
|
1425
|
+
const postId = parseDoorayTaskUrl(projectArg);
|
|
1426
|
+
if (!postId) {
|
|
1427
|
+
throw new DoorayCliError(
|
|
1428
|
+
`Dooray URL \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${projectArg}"
|
|
1429
|
+
\uC608: https://x.dooray.com/task/to/4319587406666362045`,
|
|
1430
|
+
EXIT_PARAM_ERROR
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
return resolveByPostId(client, postId);
|
|
1434
|
+
}
|
|
1435
|
+
if (projectArg && postNumberArg) {
|
|
1436
|
+
const projectId = await resolveProject(client, projectArg);
|
|
1437
|
+
const num = Number(postNumberArg);
|
|
1438
|
+
if (!Number.isFinite(num) || num <= 0) {
|
|
1439
|
+
throw new DoorayCliError(
|
|
1440
|
+
`<post-number>\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${postNumberArg}"`,
|
|
1441
|
+
EXIT_PARAM_ERROR
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
const postId = await resolvePost(client, projectId, num);
|
|
1445
|
+
return { projectId, projectCode: projectArg, postId, postNumber: num };
|
|
1446
|
+
}
|
|
1447
|
+
throw new DoorayCliError(INPUT_HELP, EXIT_PARAM_ERROR);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1142
1450
|
// src/commands/post/get.ts
|
|
1143
|
-
var postGetCommand = new import_commander10.Command("get").description("\uC5C5\uBB34 \uC0C1\uC138 \uC870\uD68C").argument("
|
|
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) => {
|
|
1144
1452
|
const globalOpts = postGetCommand.optsWithGlobals();
|
|
1145
1453
|
const config = await getConfigOrThrow();
|
|
1146
1454
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1147
1455
|
startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
|
|
1148
|
-
const projectId = await
|
|
1149
|
-
|
|
1456
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
1457
|
+
projectArg: project,
|
|
1458
|
+
postNumberArg: postNumberStr,
|
|
1459
|
+
idOpt: opts.id,
|
|
1460
|
+
urlOpt: opts.url
|
|
1461
|
+
});
|
|
1150
1462
|
const res = await client.getPost(projectId, postId);
|
|
1151
1463
|
stopSpinner(true, "\uC5C5\uBB34 \uC870\uD68C \uC644\uB8CC");
|
|
1152
1464
|
formatPostDetail(res.result, globalOpts);
|
|
@@ -1154,11 +1466,10 @@ var postGetCommand = new import_commander10.Command("get").description("\uC5C5\u
|
|
|
1154
1466
|
|
|
1155
1467
|
// src/commands/post/edit.ts
|
|
1156
1468
|
var import_commander11 = require("commander");
|
|
1157
|
-
var import_promises5 = __toESM(require("fs/promises"));
|
|
1158
1469
|
|
|
1159
1470
|
// src/editor/index.ts
|
|
1160
1471
|
var import_node_child_process = require("child_process");
|
|
1161
|
-
var
|
|
1472
|
+
var import_promises6 = __toESM(require("fs/promises"));
|
|
1162
1473
|
var import_tmp = __toESM(require("tmp"));
|
|
1163
1474
|
var import_js_yaml = __toESM(require("js-yaml"));
|
|
1164
1475
|
function openInEditor(content) {
|
|
@@ -1172,7 +1483,7 @@ function openInEditor(content) {
|
|
|
1172
1483
|
const tmpFile = import_tmp.default.fileSync({ prefix: "dooray-", postfix: ".md" });
|
|
1173
1484
|
return new Promise(async (resolve, reject) => {
|
|
1174
1485
|
try {
|
|
1175
|
-
await
|
|
1486
|
+
await import_promises6.default.writeFile(tmpFile.name, content, "utf-8");
|
|
1176
1487
|
const child = (0, import_node_child_process.spawn)(editor, [tmpFile.name], {
|
|
1177
1488
|
stdio: "inherit"
|
|
1178
1489
|
});
|
|
@@ -1188,7 +1499,7 @@ function openInEditor(content) {
|
|
|
1188
1499
|
EXIT_PARAM_ERROR
|
|
1189
1500
|
);
|
|
1190
1501
|
}
|
|
1191
|
-
const result = await
|
|
1502
|
+
const result = await import_promises6.default.readFile(tmpFile.name, "utf-8");
|
|
1192
1503
|
resolve(result);
|
|
1193
1504
|
} catch (e) {
|
|
1194
1505
|
reject(e);
|
|
@@ -1281,14 +1592,25 @@ function parseWikiFrontmatter(content) {
|
|
|
1281
1592
|
};
|
|
1282
1593
|
}
|
|
1283
1594
|
|
|
1284
|
-
// src/
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1595
|
+
// src/utils/body-input.ts
|
|
1596
|
+
var import_promises7 = require("fs/promises");
|
|
1597
|
+
async function readBodyInput(opts) {
|
|
1598
|
+
if (opts.body != null && opts.bodyFile != null) {
|
|
1599
|
+
throw new DoorayCliError(
|
|
1600
|
+
"--body\uC640 --body-file\uC740 \uD568\uAED8 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
1601
|
+
EXIT_PARAM_ERROR
|
|
1602
|
+
);
|
|
1290
1603
|
}
|
|
1291
|
-
|
|
1604
|
+
if (opts.bodyFile) {
|
|
1605
|
+
if (opts.bodyFile === "-") return readStdin();
|
|
1606
|
+
return (0, import_promises7.readFile)(opts.bodyFile, "utf-8");
|
|
1607
|
+
}
|
|
1608
|
+
if (opts.body === "-") return readStdin();
|
|
1609
|
+
return opts.body ?? "";
|
|
1610
|
+
}
|
|
1611
|
+
async function readBodyInputOrNull(opts) {
|
|
1612
|
+
if (opts.body == null && opts.bodyFile == null) return null;
|
|
1613
|
+
return readBodyInput(opts);
|
|
1292
1614
|
}
|
|
1293
1615
|
async function readStdin() {
|
|
1294
1616
|
if (process.stdin.isTTY) {
|
|
@@ -1303,30 +1625,39 @@ async function readStdin() {
|
|
|
1303
1625
|
}
|
|
1304
1626
|
return Buffer.concat(chunks).toString("utf-8");
|
|
1305
1627
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
return import_promises5.default.readFile(opts.bodyFile, "utf-8");
|
|
1628
|
+
|
|
1629
|
+
// src/commands/post/edit.ts
|
|
1630
|
+
async function resolveUsers(client, projectId, emails) {
|
|
1631
|
+
const users = [];
|
|
1632
|
+
for (const email of emails) {
|
|
1633
|
+
const memberId = await resolveMember(client, projectId, email);
|
|
1634
|
+
users.push({ type: "member", member: { organizationMemberId: memberId } });
|
|
1314
1635
|
}
|
|
1315
|
-
return
|
|
1636
|
+
return users;
|
|
1316
1637
|
}
|
|
1317
|
-
var postEditCommand = new import_commander11.Command("edit").description("\uC5C5\uBB34 \uC218\uC815 ($EDITOR \uB610\uB294 --
|
|
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) => {
|
|
1318
1639
|
const config = await getConfigOrThrow();
|
|
1319
1640
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1320
1641
|
startSpinner("\uC5C5\uBB34 \uC870\uD68C \uC911...");
|
|
1321
|
-
const projectId = await
|
|
1322
|
-
|
|
1642
|
+
const { projectId, postId, postNumber } = await resolvePostInput(client, {
|
|
1643
|
+
projectArg: project,
|
|
1644
|
+
postNumberArg: postNumberStr,
|
|
1645
|
+
idOpt: opts.id,
|
|
1646
|
+
urlOpt: opts.url
|
|
1647
|
+
});
|
|
1323
1648
|
const res = await client.getPost(projectId, postId);
|
|
1324
1649
|
const post = res.result;
|
|
1325
1650
|
const members = await ensureMembers(client, projectId);
|
|
1326
1651
|
stopSpinner(true, "\uC5C5\uBB34 \uC870\uD68C \uC644\uB8CC");
|
|
1327
|
-
const
|
|
1652
|
+
const title = opts.title ?? opts.subject;
|
|
1653
|
+
if (opts.subject && !opts.title) {
|
|
1654
|
+
process.stderr.write(
|
|
1655
|
+
"\u26A0 --subject\uB294 deprecated\uC785\uB2C8\uB2E4. \uB300\uC2E0 --title\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.\n"
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1658
|
+
const nonInteractive = title || opts.body || opts.bodyFile;
|
|
1328
1659
|
if (nonInteractive) {
|
|
1329
|
-
const newBody = await
|
|
1660
|
+
const newBody = await readBodyInputOrNull(opts);
|
|
1330
1661
|
startSpinner("\uC5C5\uBB34 \uC218\uC815 \uC911...");
|
|
1331
1662
|
const toUsers = post.users.to.map((u) => ({
|
|
1332
1663
|
type: u.type,
|
|
@@ -1341,7 +1672,7 @@ var postEditCommand = new import_commander11.Command("edit").description("\uC5C5
|
|
|
1341
1672
|
group: u.group
|
|
1342
1673
|
}));
|
|
1343
1674
|
await client.updatePost(projectId, postId, {
|
|
1344
|
-
subject:
|
|
1675
|
+
subject: title ?? post.subject,
|
|
1345
1676
|
body: {
|
|
1346
1677
|
mimeType: "text/x-markdown",
|
|
1347
1678
|
content: newBody ?? post.body.content
|
|
@@ -1373,38 +1704,137 @@ var postEditCommand = new import_commander11.Command("edit").description("\uC5C5
|
|
|
1373
1704
|
});
|
|
1374
1705
|
stopSpinner(true, "\uC5C5\uBB34 \uC218\uC815 \uC644\uB8CC");
|
|
1375
1706
|
}
|
|
1376
|
-
process.stdout.write(`#${
|
|
1707
|
+
process.stdout.write(`#${postNumber} \uC5C5\uBB34\uAC00 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1377
1708
|
`);
|
|
1378
1709
|
});
|
|
1379
1710
|
|
|
1380
1711
|
// src/commands/post/create.ts
|
|
1381
1712
|
var import_commander12 = require("commander");
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
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
|
+
});
|
|
1387
1730
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
return readStdin2();
|
|
1731
|
+
const total = res.totalCount ?? all.length;
|
|
1732
|
+
if (all.length >= total) break;
|
|
1733
|
+
page++;
|
|
1392
1734
|
}
|
|
1393
|
-
return
|
|
1735
|
+
return all;
|
|
1394
1736
|
}
|
|
1395
|
-
async function
|
|
1396
|
-
|
|
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) {
|
|
1397
1764
|
throw new DoorayCliError(
|
|
1398
|
-
|
|
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"),
|
|
1399
1767
|
EXIT_PARAM_ERROR
|
|
1400
1768
|
);
|
|
1401
1769
|
}
|
|
1402
|
-
const
|
|
1403
|
-
for
|
|
1404
|
-
|
|
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
|
+
}
|
|
1405
1782
|
}
|
|
1406
|
-
|
|
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
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// src/resolvers/milestone.ts
|
|
1794
|
+
async function fetchAllMilestones(client, projectId) {
|
|
1795
|
+
const all = [];
|
|
1796
|
+
let page = 0;
|
|
1797
|
+
const size = RESOLVER_FETCH_PAGE_SIZE;
|
|
1798
|
+
while (true) {
|
|
1799
|
+
const res = await client.getProjectMilestones(projectId, { page, size });
|
|
1800
|
+
for (const m of res.result) all.push({ id: m.id, name: m.name });
|
|
1801
|
+
const total = res.totalCount ?? all.length;
|
|
1802
|
+
if (all.length >= total) break;
|
|
1803
|
+
page++;
|
|
1804
|
+
}
|
|
1805
|
+
return all;
|
|
1806
|
+
}
|
|
1807
|
+
async function ensureMilestones(client, projectId) {
|
|
1808
|
+
const entry = await getMilestones(projectId);
|
|
1809
|
+
if (entry && !isExpired(entry.updatedAt, MILESTONES_TTL_MS)) return entry.data;
|
|
1810
|
+
const items = await fetchAllMilestones(client, projectId);
|
|
1811
|
+
await setMilestones(projectId, items);
|
|
1812
|
+
return items;
|
|
1813
|
+
}
|
|
1814
|
+
async function resolveMilestone(client, projectId, input) {
|
|
1815
|
+
const all = await ensureMilestones(client, projectId);
|
|
1816
|
+
const match = matchByName(all, input, "\uB9C8\uC77C\uC2A4\uD1A4", (m) => `${m.name} (${m.id})`);
|
|
1817
|
+
return match.id;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/resolvers/postRef.ts
|
|
1821
|
+
async function resolvePostRef(client, ref) {
|
|
1822
|
+
if (ref.includes("/")) {
|
|
1823
|
+
const [code, numStr] = ref.split("/", 2);
|
|
1824
|
+
const num = Number(numStr);
|
|
1825
|
+
if (!code || !Number.isFinite(num) || num <= 0) {
|
|
1826
|
+
throw new DoorayCliError(
|
|
1827
|
+
`--parent \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: "${ref}" (\uC608: "tc-ocr/337" \uB610\uB294 raw postId)`,
|
|
1828
|
+
EXIT_PARAM_ERROR
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
const projectId = await resolveProject(client, code);
|
|
1832
|
+
return resolvePost(client, projectId, num);
|
|
1833
|
+
}
|
|
1834
|
+
return ref;
|
|
1407
1835
|
}
|
|
1836
|
+
|
|
1837
|
+
// src/commands/post/create.ts
|
|
1408
1838
|
async function resolveUsers2(client, projectId, inputs) {
|
|
1409
1839
|
const users = [];
|
|
1410
1840
|
for (const input of inputs) {
|
|
@@ -1413,23 +1843,54 @@ async function resolveUsers2(client, projectId, inputs) {
|
|
|
1413
1843
|
}
|
|
1414
1844
|
return users;
|
|
1415
1845
|
}
|
|
1416
|
-
var postCreateCommand = new import_commander12.Command("create").description("\uC5C5\uBB34 \uC0DD\uC131").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").
|
|
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) => {
|
|
1417
1847
|
const globalOpts = postCreateCommand.optsWithGlobals();
|
|
1418
1848
|
const config = await getConfigOrThrow();
|
|
1419
1849
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1420
|
-
const
|
|
1850
|
+
const subject = opts.title ?? opts.subject;
|
|
1851
|
+
if (!subject) {
|
|
1852
|
+
throw new DoorayCliError(
|
|
1853
|
+
"--title\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
1854
|
+
EXIT_PARAM_ERROR
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
if (opts.subject && !opts.title) {
|
|
1858
|
+
process.stderr.write(
|
|
1859
|
+
"\u26A0 --subject\uB294 deprecated\uC785\uB2C8\uB2E4. \uB300\uC2E0 --title\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.\n"
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
const bodyContent = await readBodyInput(opts);
|
|
1421
1863
|
startSpinner("\uC5C5\uBB34 \uC0DD\uC131 \uC911...");
|
|
1422
1864
|
const projectId = await resolveProject(client, project);
|
|
1423
1865
|
const toUsers = opts.to ? await resolveUsers2(client, projectId, opts.to) : [];
|
|
1424
1866
|
const ccUsers = opts.cc ? await resolveUsers2(client, projectId, opts.cc) : [];
|
|
1867
|
+
const tagInputs = (opts.tag ?? []).filter((s) => s.length > 0);
|
|
1868
|
+
const [tagIds, parentPostId, milestoneId] = await Promise.all([
|
|
1869
|
+
tagInputs.length > 0 ? resolveTags(client, projectId, tagInputs) : Promise.resolve(void 0),
|
|
1870
|
+
opts.parent ? resolvePostRef(client, opts.parent) : Promise.resolve(void 0),
|
|
1871
|
+
opts.milestone ? resolveMilestone(client, projectId, opts.milestone) : Promise.resolve(void 0)
|
|
1872
|
+
]);
|
|
1425
1873
|
const res = await client.createPost(projectId, {
|
|
1426
|
-
subject
|
|
1874
|
+
subject,
|
|
1427
1875
|
body: { mimeType: "text/x-markdown", content: bodyContent },
|
|
1428
1876
|
users: { to: toUsers, cc: ccUsers },
|
|
1429
1877
|
priority: opts.priority,
|
|
1430
|
-
...opts.dueDate && { dueDate: opts.dueDate, dueDateFlag: true }
|
|
1878
|
+
...opts.dueDate && { dueDate: opts.dueDate, dueDateFlag: true },
|
|
1879
|
+
...parentPostId && { parentPostId },
|
|
1880
|
+
...milestoneId && { milestoneId },
|
|
1881
|
+
...tagIds && tagIds.length > 0 && { tagIds }
|
|
1431
1882
|
});
|
|
1432
1883
|
stopSpinner(true, "\uC5C5\uBB34 \uC0DD\uC131 \uC644\uB8CC");
|
|
1884
|
+
if (opts.workflow) {
|
|
1885
|
+
try {
|
|
1886
|
+
const workflowId = await resolveWorkflow(client, projectId, opts.workflow);
|
|
1887
|
+
await client.setPostWorkflow(projectId, res.result.id, workflowId);
|
|
1888
|
+
} catch (err) {
|
|
1889
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1890
|
+
process.stderr.write(`\u26A0 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC124\uC815 \uC2E4\uD328 (post\uB294 \uC0DD\uC131\uB428): ${msg}
|
|
1891
|
+
`);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1433
1894
|
if (globalOpts.json) {
|
|
1434
1895
|
printJson(res.result);
|
|
1435
1896
|
} else if (globalOpts.quiet) {
|
|
@@ -1442,82 +1903,120 @@ var postCreateCommand = new import_commander12.Command("create").description("\u
|
|
|
1442
1903
|
|
|
1443
1904
|
// src/commands/post/done.ts
|
|
1444
1905
|
var import_commander13 = require("commander");
|
|
1445
|
-
var postDoneCommand = new import_commander13.Command("done").description("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC").argument("
|
|
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) => {
|
|
1446
1907
|
const config = await getConfigOrThrow();
|
|
1447
1908
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1448
1909
|
startSpinner("\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC911...");
|
|
1449
|
-
const projectId = await
|
|
1450
|
-
|
|
1910
|
+
const { projectId, postId, postNumber } = await resolvePostInput(client, {
|
|
1911
|
+
projectArg: project,
|
|
1912
|
+
postNumberArg: postNumberStr,
|
|
1913
|
+
idOpt: opts.id,
|
|
1914
|
+
urlOpt: opts.url
|
|
1915
|
+
});
|
|
1451
1916
|
await client.setPostDone(projectId, postId);
|
|
1452
1917
|
stopSpinner(true, "\uC5C5\uBB34 \uC644\uB8CC \uCC98\uB9AC \uC644\uB8CC");
|
|
1453
|
-
process.stdout.write(`#${
|
|
1918
|
+
process.stdout.write(`#${postNumber} \uC5C5\uBB34\uAC00 \uC644\uB8CC \uCC98\uB9AC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1454
1919
|
`);
|
|
1455
1920
|
});
|
|
1456
1921
|
|
|
1457
1922
|
// src/commands/post/workflow.ts
|
|
1458
1923
|
var import_commander14 = require("commander");
|
|
1459
|
-
var postWorkflowCommand = new import_commander14.Command("workflow").description("\uC5C5\uBB34 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD").argument("
|
|
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) => {
|
|
1460
1925
|
const config = await getConfigOrThrow();
|
|
1461
1926
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1927
|
+
let workflowInput = opts.workflow;
|
|
1928
|
+
let projectArg = project;
|
|
1929
|
+
let postNumberArg = postNumber;
|
|
1930
|
+
if (!workflowInput) {
|
|
1931
|
+
if (workflowArg) {
|
|
1932
|
+
workflowInput = workflowArg;
|
|
1933
|
+
} else if ((opts.id || opts.url) && projectArg && !postNumberArg) {
|
|
1934
|
+
workflowInput = projectArg;
|
|
1935
|
+
projectArg = void 0;
|
|
1936
|
+
} else if (!opts.id && !opts.url && projectArg && postNumberArg && !workflowArg) {
|
|
1937
|
+
if (isLikelyDoorayUrl(projectArg)) {
|
|
1938
|
+
workflowInput = postNumberArg;
|
|
1939
|
+
postNumberArg = void 0;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
if (!workflowInput) {
|
|
1944
|
+
throw new DoorayCliError(
|
|
1945
|
+
"workflow\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional \uB610\uB294 --workflow\uB85C \uC785\uB825\uD558\uC138\uC694.",
|
|
1946
|
+
EXIT_PARAM_ERROR
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1462
1949
|
startSpinner("\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD \uC911...");
|
|
1463
|
-
const projectId = await
|
|
1464
|
-
|
|
1465
|
-
|
|
1950
|
+
const { projectId, postId, postNumber: resolvedPostNumber } = await resolvePostInput(client, {
|
|
1951
|
+
projectArg,
|
|
1952
|
+
postNumberArg,
|
|
1953
|
+
idOpt: opts.id,
|
|
1954
|
+
urlOpt: opts.url
|
|
1955
|
+
});
|
|
1956
|
+
const workflowId = await resolveWorkflow(client, projectId, workflowInput);
|
|
1466
1957
|
await client.setPostWorkflow(projectId, postId, workflowId);
|
|
1467
1958
|
stopSpinner(true, "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBCC0\uACBD \uC644\uB8CC");
|
|
1468
|
-
process.stdout.write(`#${
|
|
1959
|
+
process.stdout.write(`#${resolvedPostNumber} \uC6CC\uD06C\uD50C\uB85C\uC6B0\uAC00 "${workflowInput}"(\uC73C)\uB85C \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
1469
1960
|
`);
|
|
1470
1961
|
});
|
|
1471
1962
|
|
|
1472
1963
|
// src/commands/post/comment/list.ts
|
|
1473
1964
|
var import_commander15 = require("commander");
|
|
1474
|
-
|
|
1965
|
+
|
|
1966
|
+
// src/utils/comment-enrich.ts
|
|
1967
|
+
function enrichCommentCreators(comments, nameMap) {
|
|
1968
|
+
return comments.map((c) => {
|
|
1969
|
+
const id = c.creator?.member?.organizationMemberId;
|
|
1970
|
+
const existing = c.creator?.member?.name;
|
|
1971
|
+
if (existing || !id) return c;
|
|
1972
|
+
const filled = nameMap.get(id);
|
|
1973
|
+
if (!filled) return c;
|
|
1974
|
+
return {
|
|
1975
|
+
...c,
|
|
1976
|
+
creator: {
|
|
1977
|
+
...c.creator,
|
|
1978
|
+
member: { ...c.creator.member, name: filled }
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
});
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// 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) => {
|
|
1475
1986
|
const globalOpts = commentListCommand.optsWithGlobals();
|
|
1476
1987
|
const config = await getConfigOrThrow();
|
|
1477
1988
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1478
1989
|
startSpinner("\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1479
|
-
const projectId = await
|
|
1480
|
-
|
|
1990
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
1991
|
+
projectArg: project,
|
|
1992
|
+
postNumberArg: postNumberStr,
|
|
1993
|
+
idOpt: opts.id,
|
|
1994
|
+
urlOpt: opts.url
|
|
1995
|
+
});
|
|
1481
1996
|
const res = await client.getPostComments(projectId, postId, {
|
|
1482
1997
|
page: Number(opts.page),
|
|
1483
1998
|
size: Number(opts.size)
|
|
1484
1999
|
});
|
|
1485
2000
|
stopSpinner(true, "\uB313\uAE00 \uBAA9\uB85D \uC870\uD68C \uC644\uB8CC");
|
|
1486
|
-
|
|
2001
|
+
let comments = res.result;
|
|
2002
|
+
if (!globalOpts.json) {
|
|
2003
|
+
let nameMap = /* @__PURE__ */ new Map();
|
|
2004
|
+
try {
|
|
2005
|
+
nameMap = await buildMemberNameMap(client, projectId);
|
|
2006
|
+
} catch {
|
|
2007
|
+
}
|
|
2008
|
+
comments = enrichCommentCreators(comments, nameMap);
|
|
2009
|
+
}
|
|
2010
|
+
formatCommentList(comments, globalOpts);
|
|
1487
2011
|
});
|
|
1488
2012
|
|
|
1489
2013
|
// src/commands/post/comment/add.ts
|
|
1490
2014
|
var import_commander16 = require("commander");
|
|
1491
|
-
var
|
|
1492
|
-
async function readStdin3() {
|
|
1493
|
-
if (process.stdin.isTTY) {
|
|
1494
|
-
throw new DoorayCliError(
|
|
1495
|
-
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1496
|
-
EXIT_PARAM_ERROR
|
|
1497
|
-
);
|
|
1498
|
-
}
|
|
1499
|
-
const chunks = [];
|
|
1500
|
-
for await (const chunk of process.stdin) {
|
|
1501
|
-
chunks.push(chunk);
|
|
1502
|
-
}
|
|
1503
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
1504
|
-
}
|
|
1505
|
-
async function resolveBody2(opts) {
|
|
1506
|
-
if (opts.body) {
|
|
1507
|
-
if (opts.body === "-") return readStdin3();
|
|
1508
|
-
return opts.body;
|
|
1509
|
-
}
|
|
1510
|
-
if (opts.bodyFile) {
|
|
1511
|
-
if (opts.bodyFile === "-") return readStdin3();
|
|
1512
|
-
return import_promises7.default.readFile(opts.bodyFile, "utf-8");
|
|
1513
|
-
}
|
|
1514
|
-
return null;
|
|
1515
|
-
}
|
|
1516
|
-
var commentAddCommand = new import_commander16.Command("add").description("\uB313\uAE00 \uCD94\uAC00").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").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) => {
|
|
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) => {
|
|
1517
2016
|
const globalOpts = commentAddCommand.optsWithGlobals();
|
|
1518
2017
|
const config = await getConfigOrThrow();
|
|
1519
2018
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1520
|
-
let bodyContent = await
|
|
2019
|
+
let bodyContent = await readBodyInputOrNull(opts);
|
|
1521
2020
|
if (bodyContent == null) {
|
|
1522
2021
|
bodyContent = await openInEditor("");
|
|
1523
2022
|
if (!bodyContent.trim()) {
|
|
@@ -1526,8 +2025,12 @@ var commentAddCommand = new import_commander16.Command("add").description("\uB31
|
|
|
1526
2025
|
}
|
|
1527
2026
|
}
|
|
1528
2027
|
startSpinner("\uB313\uAE00 \uCD94\uAC00 \uC911...");
|
|
1529
|
-
const projectId = await
|
|
1530
|
-
|
|
2028
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2029
|
+
projectArg: project,
|
|
2030
|
+
postNumberArg: postNumberStr,
|
|
2031
|
+
idOpt: opts.id,
|
|
2032
|
+
urlOpt: opts.url
|
|
2033
|
+
});
|
|
1531
2034
|
const res = await client.createPostComment(projectId, postId, {
|
|
1532
2035
|
body: { mimeType: "text/x-markdown", content: bodyContent }
|
|
1533
2036
|
});
|
|
@@ -1544,37 +2047,55 @@ var commentAddCommand = new import_commander16.Command("add").description("\uB31
|
|
|
1544
2047
|
|
|
1545
2048
|
// src/commands/post/comment/edit.ts
|
|
1546
2049
|
var import_commander17 = require("commander");
|
|
1547
|
-
var
|
|
1548
|
-
|
|
1549
|
-
|
|
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) => {
|
|
2051
|
+
const config = await getConfigOrThrow();
|
|
2052
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2053
|
+
let projectArg;
|
|
2054
|
+
let postNumberArg;
|
|
2055
|
+
let commentId = opts.commentId;
|
|
2056
|
+
if (opts.id || opts.url) {
|
|
2057
|
+
if (arg2 || arg3) {
|
|
2058
|
+
throw new DoorayCliError(
|
|
2059
|
+
"--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uB313\uAE00 ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --comment-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
2060
|
+
EXIT_PARAM_ERROR
|
|
2061
|
+
);
|
|
2062
|
+
}
|
|
2063
|
+
commentId = commentId ?? arg1;
|
|
2064
|
+
} else if (arg3) {
|
|
2065
|
+
projectArg = arg1;
|
|
2066
|
+
postNumberArg = arg2;
|
|
2067
|
+
commentId = commentId ?? arg3;
|
|
2068
|
+
} else if (arg1 && !arg2) {
|
|
2069
|
+
projectArg = arg1;
|
|
2070
|
+
if (!commentId) {
|
|
2071
|
+
throw new DoorayCliError(
|
|
2072
|
+
"URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --comment-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2073
|
+
EXIT_PARAM_ERROR
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
} else {
|
|
2077
|
+
projectArg = arg1;
|
|
2078
|
+
postNumberArg = arg2;
|
|
2079
|
+
if (!commentId) {
|
|
2080
|
+
throw new DoorayCliError(
|
|
2081
|
+
"<comment-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --comment-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
2082
|
+
EXIT_PARAM_ERROR
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (!commentId) {
|
|
1550
2087
|
throw new DoorayCliError(
|
|
1551
|
-
"
|
|
2088
|
+
"<comment-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
1552
2089
|
EXIT_PARAM_ERROR
|
|
1553
2090
|
);
|
|
1554
2091
|
}
|
|
1555
|
-
const chunks = [];
|
|
1556
|
-
for await (const chunk of process.stdin) {
|
|
1557
|
-
chunks.push(chunk);
|
|
1558
|
-
}
|
|
1559
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
1560
|
-
}
|
|
1561
|
-
async function resolveBody3(opts) {
|
|
1562
|
-
if (opts.body) {
|
|
1563
|
-
if (opts.body === "-") return readStdin4();
|
|
1564
|
-
return opts.body;
|
|
1565
|
-
}
|
|
1566
|
-
if (opts.bodyFile) {
|
|
1567
|
-
if (opts.bodyFile === "-") return readStdin4();
|
|
1568
|
-
return import_promises8.default.readFile(opts.bodyFile, "utf-8");
|
|
1569
|
-
}
|
|
1570
|
-
return null;
|
|
1571
|
-
}
|
|
1572
|
-
var commentEditCommand = new import_commander17.Command("edit").description("\uB313\uAE00 \uC218\uC815 ($EDITOR \uB610\uB294 --body \uC635\uC158)").argument("<project>", "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uB610\uB294 ID").argument("<post-number>", "\uC5C5\uBB34 \uBC88\uD638").argument("<comment-id>", "\uB313\uAE00 ID").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 (project, postNumberStr, commentId, opts) => {
|
|
1573
|
-
const config = await getConfigOrThrow();
|
|
1574
|
-
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1575
2092
|
startSpinner("\uB313\uAE00 \uC870\uD68C \uC911...");
|
|
1576
|
-
const projectId = await
|
|
1577
|
-
|
|
2093
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2094
|
+
projectArg,
|
|
2095
|
+
postNumberArg,
|
|
2096
|
+
idOpt: opts.id,
|
|
2097
|
+
urlOpt: opts.url
|
|
2098
|
+
});
|
|
1578
2099
|
const comments = await client.getPostComments(projectId, postId);
|
|
1579
2100
|
const comment = comments.result.find((c) => c.id === commentId);
|
|
1580
2101
|
stopSpinner(true, "\uB313\uAE00 \uC870\uD68C \uC644\uB8CC");
|
|
@@ -1583,7 +2104,7 @@ var commentEditCommand = new import_commander17.Command("edit").description("\uB
|
|
|
1583
2104
|
`);
|
|
1584
2105
|
process.exit(1);
|
|
1585
2106
|
}
|
|
1586
|
-
let edited = await
|
|
2107
|
+
let edited = await readBodyInputOrNull(opts);
|
|
1587
2108
|
if (edited == null) {
|
|
1588
2109
|
const original = comment.body.content;
|
|
1589
2110
|
edited = await openInEditor(original);
|
|
@@ -1603,12 +2124,55 @@ var commentEditCommand = new import_commander17.Command("edit").description("\uB
|
|
|
1603
2124
|
|
|
1604
2125
|
// src/commands/post/comment/delete.ts
|
|
1605
2126
|
var import_commander18 = require("commander");
|
|
1606
|
-
var commentDeleteCommand = new import_commander18.Command("delete").description("\uB313\uAE00 \uC0AD\uC81C").argument("
|
|
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) => {
|
|
1607
2128
|
const config = await getConfigOrThrow();
|
|
1608
2129
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2130
|
+
let projectArg;
|
|
2131
|
+
let postNumberArg;
|
|
2132
|
+
let commentId = opts.commentId;
|
|
2133
|
+
if (opts.id || opts.url) {
|
|
2134
|
+
if (arg2 || arg3) {
|
|
2135
|
+
throw new DoorayCliError(
|
|
2136
|
+
"--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uB313\uAE00 ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --comment-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
2137
|
+
EXIT_PARAM_ERROR
|
|
2138
|
+
);
|
|
2139
|
+
}
|
|
2140
|
+
commentId = commentId ?? arg1;
|
|
2141
|
+
} else if (arg3) {
|
|
2142
|
+
projectArg = arg1;
|
|
2143
|
+
postNumberArg = arg2;
|
|
2144
|
+
commentId = commentId ?? arg3;
|
|
2145
|
+
} else if (arg1 && !arg2) {
|
|
2146
|
+
projectArg = arg1;
|
|
2147
|
+
if (!commentId) {
|
|
2148
|
+
throw new DoorayCliError(
|
|
2149
|
+
"URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --comment-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2150
|
+
EXIT_PARAM_ERROR
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
} else {
|
|
2154
|
+
projectArg = arg1;
|
|
2155
|
+
postNumberArg = arg2;
|
|
2156
|
+
if (!commentId) {
|
|
2157
|
+
throw new DoorayCliError(
|
|
2158
|
+
"<comment-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --comment-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
2159
|
+
EXIT_PARAM_ERROR
|
|
2160
|
+
);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
if (!commentId) {
|
|
2164
|
+
throw new DoorayCliError(
|
|
2165
|
+
"<comment-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2166
|
+
EXIT_PARAM_ERROR
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
1609
2169
|
startSpinner("\uB313\uAE00 \uC0AD\uC81C \uC911...");
|
|
1610
|
-
const projectId = await
|
|
1611
|
-
|
|
2170
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2171
|
+
projectArg,
|
|
2172
|
+
postNumberArg,
|
|
2173
|
+
idOpt: opts.id,
|
|
2174
|
+
urlOpt: opts.url
|
|
2175
|
+
});
|
|
1612
2176
|
await client.deletePostComment(projectId, postId, commentId);
|
|
1613
2177
|
stopSpinner(true, "\uB313\uAE00 \uC0AD\uC81C \uC644\uB8CC");
|
|
1614
2178
|
process.stdout.write(`\uB313\uAE00\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${commentId}
|
|
@@ -1622,13 +2186,17 @@ function formatSize(bytes) {
|
|
|
1622
2186
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
1623
2187
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
1624
2188
|
}
|
|
1625
|
-
var fileListCommand = new import_commander19.Command("list").description("\uC5C5\uBB34 \uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C").argument("
|
|
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) => {
|
|
1626
2190
|
const globalOpts = fileListCommand.optsWithGlobals();
|
|
1627
2191
|
const config = await getConfigOrThrow();
|
|
1628
2192
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1629
2193
|
startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1630
|
-
const projectId = await
|
|
1631
|
-
|
|
2194
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2195
|
+
projectArg: project,
|
|
2196
|
+
postNumberArg: postNumberStr,
|
|
2197
|
+
idOpt: opts.id,
|
|
2198
|
+
urlOpt: opts.url
|
|
2199
|
+
});
|
|
1632
2200
|
const res = await client.getPostFiles(projectId, postId);
|
|
1633
2201
|
stopSpinner(true, `\uCCA8\uBD80\uD30C\uC77C ${res.result.length}\uAC1C`);
|
|
1634
2202
|
output(globalOpts, {
|
|
@@ -1647,17 +2215,57 @@ var fileListCommand = new import_commander19.Command("list").description("\uC5C5
|
|
|
1647
2215
|
|
|
1648
2216
|
// src/commands/post/file/download.ts
|
|
1649
2217
|
var import_commander20 = require("commander");
|
|
1650
|
-
var
|
|
2218
|
+
var import_promises8 = require("fs/promises");
|
|
1651
2219
|
var import_node_path4 = require("path");
|
|
1652
|
-
var fileDownloadCommand = new import_commander20.Command("download").description("\uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("
|
|
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) => {
|
|
1653
2221
|
const config = await getConfigOrThrow();
|
|
1654
2222
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2223
|
+
let projectArg;
|
|
2224
|
+
let postNumberArg;
|
|
2225
|
+
let fileId = opts.fileId;
|
|
2226
|
+
if (opts.id || opts.url) {
|
|
2227
|
+
if (arg2 || arg3) {
|
|
2228
|
+
throw new DoorayCliError(
|
|
2229
|
+
"--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
2230
|
+
EXIT_PARAM_ERROR
|
|
2231
|
+
);
|
|
2232
|
+
}
|
|
2233
|
+
fileId = fileId ?? arg1;
|
|
2234
|
+
} else if (arg3) {
|
|
2235
|
+
projectArg = arg1;
|
|
2236
|
+
postNumberArg = arg2;
|
|
2237
|
+
fileId = fileId ?? arg3;
|
|
2238
|
+
} else if (arg1 && !arg2) {
|
|
2239
|
+
projectArg = arg1;
|
|
2240
|
+
if (!fileId) {
|
|
2241
|
+
throw new DoorayCliError(
|
|
2242
|
+
"URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --file-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2243
|
+
EXIT_PARAM_ERROR
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
} else {
|
|
2247
|
+
projectArg = arg1;
|
|
2248
|
+
postNumberArg = arg2;
|
|
2249
|
+
if (!fileId) {
|
|
2250
|
+
throw new DoorayCliError(
|
|
2251
|
+
"<file-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
2252
|
+
EXIT_PARAM_ERROR
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
if (!fileId) {
|
|
2257
|
+
throw new DoorayCliError("\uD30C\uC77C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
|
|
2258
|
+
}
|
|
1655
2259
|
startSpinner("\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
|
|
1656
|
-
const projectId = await
|
|
1657
|
-
|
|
2260
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2261
|
+
projectArg,
|
|
2262
|
+
postNumberArg,
|
|
2263
|
+
idOpt: opts.id,
|
|
2264
|
+
urlOpt: opts.url
|
|
2265
|
+
});
|
|
1658
2266
|
const { buffer, fileName } = await client.downloadPostFile(projectId, postId, fileId);
|
|
1659
2267
|
const outputPath = (0, import_node_path4.join)(opts.output, fileName);
|
|
1660
|
-
await (0,
|
|
2268
|
+
await (0, import_promises8.writeFile)(outputPath, Buffer.from(buffer));
|
|
1661
2269
|
stopSpinner(true, "\uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC");
|
|
1662
2270
|
process.stdout.write(`${outputPath}
|
|
1663
2271
|
`);
|
|
@@ -1665,32 +2273,36 @@ var fileDownloadCommand = new import_commander20.Command("download").description
|
|
|
1665
2273
|
|
|
1666
2274
|
// src/commands/post/file/download-all.ts
|
|
1667
2275
|
var import_commander21 = require("commander");
|
|
1668
|
-
var
|
|
2276
|
+
var import_promises9 = require("fs/promises");
|
|
1669
2277
|
var import_node_path5 = require("path");
|
|
1670
|
-
var fileDownloadAllCommand = new import_commander21.Command("download-all").description("\uC5C5\uBB34\uC758 \uBAA8\uB4E0 \uCCA8\uBD80\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC").argument("
|
|
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) => {
|
|
1671
2279
|
const config = await getConfigOrThrow();
|
|
1672
2280
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1673
2281
|
const spinner = startSpinner("\uCCA8\uBD80\uD30C\uC77C \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
1674
|
-
const projectId = await
|
|
1675
|
-
|
|
2282
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2283
|
+
projectArg: project,
|
|
2284
|
+
postNumberArg: postNumberStr,
|
|
2285
|
+
idOpt: opts.id,
|
|
2286
|
+
urlOpt: opts.url
|
|
2287
|
+
});
|
|
1676
2288
|
const res = await client.getPostFiles(projectId, postId);
|
|
1677
2289
|
if (res.result.length === 0) {
|
|
1678
2290
|
stopSpinner(true, "\uCCA8\uBD80\uD30C\uC77C \uC5C6\uC74C");
|
|
1679
2291
|
process.stdout.write("\uCCA8\uBD80\uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n");
|
|
1680
2292
|
return;
|
|
1681
2293
|
}
|
|
1682
|
-
await (0,
|
|
2294
|
+
await (0, import_promises9.mkdir)(opts.output, { recursive: true });
|
|
1683
2295
|
const downloaded = [];
|
|
1684
2296
|
for (const file of res.result) {
|
|
1685
2297
|
spinner.text = `\uB2E4\uC6B4\uB85C\uB4DC \uC911: ${file.name} (${downloaded.length + 1}/${res.result.length})`;
|
|
1686
2298
|
const { buffer, fileName } = await client.downloadPostFile(projectId, postId, file.id);
|
|
1687
2299
|
const outputPath = (0, import_node_path5.join)(opts.output, fileName);
|
|
1688
|
-
await (0,
|
|
2300
|
+
await (0, import_promises9.writeFile)(outputPath, Buffer.from(buffer));
|
|
1689
2301
|
downloaded.push(outputPath);
|
|
1690
2302
|
}
|
|
1691
2303
|
stopSpinner(true, `${downloaded.length}\uAC1C \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC644\uB8CC`);
|
|
1692
|
-
for (const
|
|
1693
|
-
process.stdout.write(`${
|
|
2304
|
+
for (const path3 of downloaded) {
|
|
2305
|
+
process.stdout.write(`${path3}
|
|
1694
2306
|
`);
|
|
1695
2307
|
}
|
|
1696
2308
|
});
|
|
@@ -1698,13 +2310,53 @@ var fileDownloadAllCommand = new import_commander21.Command("download-all").desc
|
|
|
1698
2310
|
// src/commands/post/file/upload.ts
|
|
1699
2311
|
var import_commander22 = require("commander");
|
|
1700
2312
|
var import_node_path6 = require("path");
|
|
1701
|
-
var fileUploadCommand = new import_commander22.Command("upload").description("\uCCA8\uBD80\uD30C\uC77C \uC5C5\uB85C\uB4DC").argument("
|
|
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) => {
|
|
1702
2314
|
const globalOpts = fileUploadCommand.optsWithGlobals();
|
|
1703
2315
|
const config = await getConfigOrThrow();
|
|
1704
2316
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2317
|
+
let projectArg;
|
|
2318
|
+
let postNumberArg;
|
|
2319
|
+
let filePath = opts.file;
|
|
2320
|
+
if (opts.id || opts.url) {
|
|
2321
|
+
if (arg2 || arg3) {
|
|
2322
|
+
throw new DoorayCliError(
|
|
2323
|
+
"--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C \uACBD\uB85C \uC678 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
2324
|
+
EXIT_PARAM_ERROR
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
filePath = filePath ?? arg1;
|
|
2328
|
+
} else if (arg3) {
|
|
2329
|
+
projectArg = arg1;
|
|
2330
|
+
postNumberArg = arg2;
|
|
2331
|
+
filePath = filePath ?? arg3;
|
|
2332
|
+
} else if (arg1 && !arg2) {
|
|
2333
|
+
projectArg = arg1;
|
|
2334
|
+
if (!filePath) {
|
|
2335
|
+
throw new DoorayCliError(
|
|
2336
|
+
"URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --file \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2337
|
+
EXIT_PARAM_ERROR
|
|
2338
|
+
);
|
|
2339
|
+
}
|
|
2340
|
+
} else {
|
|
2341
|
+
projectArg = arg1;
|
|
2342
|
+
postNumberArg = arg2;
|
|
2343
|
+
if (!filePath) {
|
|
2344
|
+
throw new DoorayCliError(
|
|
2345
|
+
"<file-path>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
2346
|
+
EXIT_PARAM_ERROR
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
if (!filePath) {
|
|
2351
|
+
throw new DoorayCliError("\uD30C\uC77C \uACBD\uB85C\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
|
|
2352
|
+
}
|
|
1705
2353
|
startSpinner("\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC911...");
|
|
1706
|
-
const projectId = await
|
|
1707
|
-
|
|
2354
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2355
|
+
projectArg,
|
|
2356
|
+
postNumberArg,
|
|
2357
|
+
idOpt: opts.id,
|
|
2358
|
+
urlOpt: opts.url
|
|
2359
|
+
});
|
|
1708
2360
|
const res = await client.uploadPostFile(projectId, postId, filePath);
|
|
1709
2361
|
stopSpinner(true, "\uC5C5\uB85C\uB4DC \uC644\uB8CC");
|
|
1710
2362
|
if (globalOpts.json) {
|
|
@@ -1720,12 +2372,52 @@ var fileUploadCommand = new import_commander22.Command("upload").description("\u
|
|
|
1720
2372
|
|
|
1721
2373
|
// src/commands/post/file/delete.ts
|
|
1722
2374
|
var import_commander23 = require("commander");
|
|
1723
|
-
var fileDeleteCommand = new import_commander23.Command("delete").description("\uCCA8\uBD80\uD30C\uC77C \uC0AD\uC81C").argument("
|
|
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) => {
|
|
1724
2376
|
const config = await getConfigOrThrow();
|
|
1725
2377
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2378
|
+
let projectArg;
|
|
2379
|
+
let postNumberArg;
|
|
2380
|
+
let fileId = opts.fileId;
|
|
2381
|
+
if (opts.id || opts.url) {
|
|
2382
|
+
if (arg2 || arg3) {
|
|
2383
|
+
throw new DoorayCliError(
|
|
2384
|
+
"--id/--url \uBAA8\uB4DC\uC5D0\uC11C\uB294 \uD30C\uC77C ID \uC678 \uCD94\uAC00 positional \uC778\uC790\uB97C \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. --file-id \uC635\uC158 \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
2385
|
+
EXIT_PARAM_ERROR
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
fileId = fileId ?? arg1;
|
|
2389
|
+
} else if (arg3) {
|
|
2390
|
+
projectArg = arg1;
|
|
2391
|
+
postNumberArg = arg2;
|
|
2392
|
+
fileId = fileId ?? arg3;
|
|
2393
|
+
} else if (arg1 && !arg2) {
|
|
2394
|
+
projectArg = arg1;
|
|
2395
|
+
if (!fileId) {
|
|
2396
|
+
throw new DoorayCliError(
|
|
2397
|
+
"URL/--id \uBAA8\uB4DC\uC5D0\uC11C\uB294 --file-id \uC635\uC158\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
|
|
2398
|
+
EXIT_PARAM_ERROR
|
|
2399
|
+
);
|
|
2400
|
+
}
|
|
2401
|
+
} else {
|
|
2402
|
+
projectArg = arg1;
|
|
2403
|
+
postNumberArg = arg2;
|
|
2404
|
+
if (!fileId) {
|
|
2405
|
+
throw new DoorayCliError(
|
|
2406
|
+
"<file-id>\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. positional 3\uBC88\uC9F8 \uB610\uB294 --file-id \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
2407
|
+
EXIT_PARAM_ERROR
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
if (!fileId) {
|
|
2412
|
+
throw new DoorayCliError("\uD30C\uC77C ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.", EXIT_PARAM_ERROR);
|
|
2413
|
+
}
|
|
1726
2414
|
startSpinner("\uD30C\uC77C \uC0AD\uC81C \uC911...");
|
|
1727
|
-
const projectId = await
|
|
1728
|
-
|
|
2415
|
+
const { projectId, postId } = await resolvePostInput(client, {
|
|
2416
|
+
projectArg,
|
|
2417
|
+
postNumberArg,
|
|
2418
|
+
idOpt: opts.id,
|
|
2419
|
+
urlOpt: opts.url
|
|
2420
|
+
});
|
|
1729
2421
|
await client.deletePostFile(projectId, postId, fileId);
|
|
1730
2422
|
stopSpinner(true, "\uC0AD\uC81C \uC644\uB8CC");
|
|
1731
2423
|
process.stdout.write(`\uD30C\uC77C(${fileId})\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
@@ -1807,6 +2499,31 @@ async function resolveWiki(client, projectCode) {
|
|
|
1807
2499
|
}
|
|
1808
2500
|
return project.wikiId;
|
|
1809
2501
|
}
|
|
2502
|
+
async function resolveWikiHomePageId(client, wikiId) {
|
|
2503
|
+
const cached = await getWikis();
|
|
2504
|
+
const fresh = cached && !isExpired(cached.updatedAt, WIKIS_TTL_MS);
|
|
2505
|
+
let wikis;
|
|
2506
|
+
if (fresh) {
|
|
2507
|
+
wikis = cached.data;
|
|
2508
|
+
} else {
|
|
2509
|
+
const res = await client.getWikis({ size: 100 });
|
|
2510
|
+
wikis = res.result.map((w) => ({
|
|
2511
|
+
id: w.id,
|
|
2512
|
+
projectId: w.project.id,
|
|
2513
|
+
name: w.name,
|
|
2514
|
+
homePageId: w.home.pageId
|
|
2515
|
+
}));
|
|
2516
|
+
await setWikis(wikis);
|
|
2517
|
+
}
|
|
2518
|
+
const wiki = wikis.find((w) => w.id === wikiId);
|
|
2519
|
+
if (!wiki?.homePageId) {
|
|
2520
|
+
throw new DoorayCliError(
|
|
2521
|
+
`\uC704\uD0A4\uC758 home \uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (wikiId: ${wikiId})`,
|
|
2522
|
+
EXIT_API_ERROR
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
return wiki.homePageId;
|
|
2526
|
+
}
|
|
1810
2527
|
|
|
1811
2528
|
// src/commands/wiki/pages.ts
|
|
1812
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) => {
|
|
@@ -1835,43 +2552,18 @@ var wikiPageGetCommand = new import_commander26.Command("get").description("\uC7
|
|
|
1835
2552
|
|
|
1836
2553
|
// src/commands/wiki/page-create.ts
|
|
1837
2554
|
var import_commander27 = require("commander");
|
|
1838
|
-
var import_promises11 = __toESM(require("fs/promises"));
|
|
1839
|
-
async function readBody2(opts) {
|
|
1840
|
-
if (opts.bodyFile) {
|
|
1841
|
-
if (opts.bodyFile === "-") {
|
|
1842
|
-
return readStdin5();
|
|
1843
|
-
}
|
|
1844
|
-
return import_promises11.default.readFile(opts.bodyFile, "utf-8");
|
|
1845
|
-
}
|
|
1846
|
-
if (opts.body === "-") {
|
|
1847
|
-
return readStdin5();
|
|
1848
|
-
}
|
|
1849
|
-
return "";
|
|
1850
|
-
}
|
|
1851
|
-
async function readStdin5() {
|
|
1852
|
-
if (process.stdin.isTTY) {
|
|
1853
|
-
throw new DoorayCliError(
|
|
1854
|
-
"stdin\uC5D0\uC11C \uC77D\uC73C\uB824\uBA74 \uD30C\uC774\uD504\uB85C \uB370\uC774\uD130\uB97C \uC804\uB2EC\uD574\uC8FC\uC138\uC694.",
|
|
1855
|
-
EXIT_PARAM_ERROR
|
|
1856
|
-
);
|
|
1857
|
-
}
|
|
1858
|
-
const chunks = [];
|
|
1859
|
-
for await (const chunk of process.stdin) {
|
|
1860
|
-
chunks.push(chunk);
|
|
1861
|
-
}
|
|
1862
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
1863
|
-
}
|
|
1864
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) => {
|
|
1865
2556
|
const globalOpts = wikiPageCreateCommand.optsWithGlobals();
|
|
1866
2557
|
const config = await getConfigOrThrow();
|
|
1867
2558
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1868
|
-
const bodyContent = await
|
|
2559
|
+
const bodyContent = await readBodyInput(opts);
|
|
1869
2560
|
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC911...");
|
|
1870
2561
|
const wikiId = await resolveWiki(client, project);
|
|
2562
|
+
const parentPageId = opts.parent ?? await resolveWikiHomePageId(client, wikiId);
|
|
1871
2563
|
const res = await client.createWikiPage(wikiId, {
|
|
1872
2564
|
subject: opts.title,
|
|
1873
2565
|
body: { mimeType: "text/x-markdown", content: bodyContent },
|
|
1874
|
-
parentPageId
|
|
2566
|
+
parentPageId
|
|
1875
2567
|
});
|
|
1876
2568
|
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC644\uB8CC");
|
|
1877
2569
|
if (globalOpts.json) {
|
|
@@ -1886,34 +2578,126 @@ var wikiPageCreateCommand = new import_commander27.Command("create").description
|
|
|
1886
2578
|
|
|
1887
2579
|
// src/commands/wiki/page-edit.ts
|
|
1888
2580
|
var import_commander28 = require("commander");
|
|
1889
|
-
var wikiPageEditCommand = new import_commander28.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) => {
|
|
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) => {
|
|
1890
2582
|
const config = await getConfigOrThrow();
|
|
1891
2583
|
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
1892
|
-
|
|
2584
|
+
const hasTitle = opts.title != null;
|
|
2585
|
+
const hasBody = opts.body != null || opts.bodyFile != null;
|
|
2586
|
+
const nonInteractive = hasTitle || hasBody;
|
|
2587
|
+
startSpinner("\uC704\uD0A4 \uC815\uBCF4 \uC870\uD68C \uC911...");
|
|
1893
2588
|
const wikiId = await resolveWiki(client, project);
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2589
|
+
if (!nonInteractive) {
|
|
2590
|
+
const res = await client.getWikiPage(wikiId, pageId);
|
|
2591
|
+
const page = res.result;
|
|
2592
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC870\uD68C \uC644\uB8CC");
|
|
2593
|
+
const original = serializeWikiFrontmatter(page);
|
|
2594
|
+
const edited = await openInEditor(original);
|
|
2595
|
+
if (original === edited) {
|
|
2596
|
+
process.stdout.write("\uBCC0\uACBD\uC0AC\uD56D \uC5C6\uC74C\n");
|
|
2597
|
+
return;
|
|
2598
|
+
}
|
|
2599
|
+
const parsed = parseWikiFrontmatter(edited);
|
|
2600
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC911...");
|
|
2601
|
+
await client.updateWikiPage(wikiId, pageId, {
|
|
2602
|
+
subject: parsed.title,
|
|
2603
|
+
body: { mimeType: "text/x-markdown", content: parsed.body }
|
|
2604
|
+
});
|
|
2605
|
+
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC644\uB8CC");
|
|
2606
|
+
process.stdout.write(`\uC704\uD0A4 \uD398\uC774\uC9C0\uAC00 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${pageId}
|
|
2607
|
+
`);
|
|
1901
2608
|
return;
|
|
1902
2609
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2610
|
+
stopSpinner(true, "\uC704\uD0A4 \uC815\uBCF4 \uC870\uD68C \uC644\uB8CC");
|
|
2611
|
+
if (hasTitle && hasBody) {
|
|
2612
|
+
const bodyContent = await readBodyInput(opts);
|
|
2613
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC911...");
|
|
2614
|
+
await client.updateWikiPage(wikiId, pageId, {
|
|
2615
|
+
subject: opts.title,
|
|
2616
|
+
body: { mimeType: "text/x-markdown", content: bodyContent }
|
|
2617
|
+
});
|
|
2618
|
+
} else if (hasTitle) {
|
|
2619
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uC81C\uBAA9 \uC218\uC815 \uC911...");
|
|
2620
|
+
await client.updateWikiPageTitle(wikiId, pageId, { subject: opts.title });
|
|
2621
|
+
} else {
|
|
2622
|
+
const bodyContent = await readBodyInput(opts);
|
|
2623
|
+
startSpinner("\uC704\uD0A4 \uD398\uC774\uC9C0 \uBCF8\uBB38 \uC218\uC815 \uC911...");
|
|
2624
|
+
await client.updateWikiPageContent(wikiId, pageId, {
|
|
2625
|
+
body: { mimeType: "text/x-markdown", content: bodyContent }
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
1909
2628
|
stopSpinner(true, "\uC704\uD0A4 \uD398\uC774\uC9C0 \uC218\uC815 \uC644\uB8CC");
|
|
1910
2629
|
process.stdout.write(`\uC704\uD0A4 \uD398\uC774\uC9C0\uAC00 \uC218\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${pageId}
|
|
1911
2630
|
`);
|
|
1912
2631
|
});
|
|
1913
2632
|
|
|
1914
|
-
// src/commands/
|
|
2633
|
+
// src/commands/member/index.ts
|
|
2634
|
+
var import_commander31 = require("commander");
|
|
2635
|
+
|
|
2636
|
+
// src/commands/member/get.ts
|
|
1915
2637
|
var import_commander29 = require("commander");
|
|
1916
2638
|
|
|
2639
|
+
// src/formatters/member.ts
|
|
2640
|
+
function formatMemberDetail(member, opts) {
|
|
2641
|
+
if (opts.json) {
|
|
2642
|
+
printJson(member);
|
|
2643
|
+
return;
|
|
2644
|
+
}
|
|
2645
|
+
if (opts.quiet) {
|
|
2646
|
+
process.stdout.write(member.id + "\n");
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2649
|
+
const lines = [
|
|
2650
|
+
`\uC774\uB984: ${member.name}`,
|
|
2651
|
+
...member.englishName ? [`\uC601\uBB38\uBA85: ${member.englishName}`] : [],
|
|
2652
|
+
...member.nickname ? [`\uBCC4\uBA85: ${member.nickname}`] : [],
|
|
2653
|
+
...member.userCode ? [`\uC0AC\uBC88/ID: ${member.userCode}`] : [],
|
|
2654
|
+
...member.externalEmailAddress ? [`\uC678\uBD80 \uC774\uBA54\uC77C: ${member.externalEmailAddress}`] : [],
|
|
2655
|
+
`member-id: ${member.id}`
|
|
2656
|
+
];
|
|
2657
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
2658
|
+
}
|
|
2659
|
+
function formatMemberList(rows, opts) {
|
|
2660
|
+
output(opts, {
|
|
2661
|
+
headers: ["ID", "Name", "Role"],
|
|
2662
|
+
rows: rows.map((r) => [r.id, r.name, r.role ?? ""]),
|
|
2663
|
+
raw: rows,
|
|
2664
|
+
ids: rows.map((r) => r.id)
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
// 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) => {
|
|
2670
|
+
const globalOpts = memberGetCommand.optsWithGlobals();
|
|
2671
|
+
const config = await getConfigOrThrow();
|
|
2672
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2673
|
+
const res = await client.getMemberDetail(memberId);
|
|
2674
|
+
formatMemberDetail(res.result, globalOpts);
|
|
2675
|
+
});
|
|
2676
|
+
|
|
2677
|
+
// 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) => {
|
|
2680
|
+
const globalOpts = memberListCommand.optsWithGlobals();
|
|
2681
|
+
const config = await getConfigOrThrow();
|
|
2682
|
+
const client = new DoorayApiClient(config.apiKey, config.baseUrl);
|
|
2683
|
+
startSpinner("\uBA64\uBC84 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
2684
|
+
const projectId = await resolveProject(client, project);
|
|
2685
|
+
const members = await ensureMembers(client, projectId);
|
|
2686
|
+
stopSpinner(true, `${members.length}\uBA85`);
|
|
2687
|
+
formatMemberList(
|
|
2688
|
+
members.map((m) => ({ id: m.organizationMemberId, name: m.name })),
|
|
2689
|
+
globalOpts
|
|
2690
|
+
);
|
|
2691
|
+
});
|
|
2692
|
+
|
|
2693
|
+
// src/commands/member/index.ts
|
|
2694
|
+
var memberCommand = new import_commander31.Command("member").description("Dooray \uBA64\uBC84 \uC870\uD68C");
|
|
2695
|
+
memberCommand.addCommand(memberGetCommand);
|
|
2696
|
+
memberCommand.addCommand(memberListCommand);
|
|
2697
|
+
|
|
2698
|
+
// src/commands/mail/list.ts
|
|
2699
|
+
var import_commander32 = require("commander");
|
|
2700
|
+
|
|
1917
2701
|
// src/api/imapClient.ts
|
|
1918
2702
|
var import_imapflow = require("imapflow");
|
|
1919
2703
|
var import_mailparser = require("mailparser");
|
|
@@ -2020,7 +2804,7 @@ async function getMail(config, uid) {
|
|
|
2020
2804
|
|
|
2021
2805
|
// src/commands/mail/list.ts
|
|
2022
2806
|
var import_chalk5 = __toESM(require("chalk"));
|
|
2023
|
-
var mailListCommand = new
|
|
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) => {
|
|
2024
2808
|
const globalOpts = mailListCommand.optsWithGlobals();
|
|
2025
2809
|
const config = await getConfigOrThrow();
|
|
2026
2810
|
startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
|
|
@@ -2052,9 +2836,9 @@ var mailListCommand = new import_commander29.Command("list").description("\uBA54
|
|
|
2052
2836
|
});
|
|
2053
2837
|
|
|
2054
2838
|
// src/commands/mail/get.ts
|
|
2055
|
-
var
|
|
2839
|
+
var import_commander33 = require("commander");
|
|
2056
2840
|
var import_chalk6 = __toESM(require("chalk"));
|
|
2057
|
-
var mailGetCommand = new
|
|
2841
|
+
var mailGetCommand = new import_commander33.Command("get").description("\uBA54\uC77C \uC0C1\uC138 \uC870\uD68C").argument("<uid>", "\uBA54\uC77C UID").action(async (uid) => {
|
|
2058
2842
|
const globalOpts = mailGetCommand.optsWithGlobals();
|
|
2059
2843
|
const config = await getConfigOrThrow();
|
|
2060
2844
|
startSpinner("\uBA54\uC77C \uC870\uD68C \uC911...");
|
|
@@ -2085,8 +2869,8 @@ ${mail.body}
|
|
|
2085
2869
|
});
|
|
2086
2870
|
|
|
2087
2871
|
// src/commands/mail/send.ts
|
|
2088
|
-
var
|
|
2089
|
-
var
|
|
2872
|
+
var import_commander34 = require("commander");
|
|
2873
|
+
var import_promises10 = require("fs/promises");
|
|
2090
2874
|
|
|
2091
2875
|
// src/api/smtpClient.ts
|
|
2092
2876
|
var import_nodemailer = __toESM(require("nodemailer"));
|
|
@@ -2135,12 +2919,12 @@ async function sendMail(config, opts) {
|
|
|
2135
2919
|
}
|
|
2136
2920
|
|
|
2137
2921
|
// src/commands/mail/send.ts
|
|
2138
|
-
var mailSendCommand = new
|
|
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) => {
|
|
2139
2923
|
const globalOpts = mailSendCommand.optsWithGlobals();
|
|
2140
2924
|
const config = await getConfigOrThrow();
|
|
2141
2925
|
let body = opts.body ?? "";
|
|
2142
2926
|
if (opts.bodyFile) {
|
|
2143
|
-
body = await (0,
|
|
2927
|
+
body = await (0, import_promises10.readFile)(opts.bodyFile, "utf-8");
|
|
2144
2928
|
}
|
|
2145
2929
|
if (!body) {
|
|
2146
2930
|
process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
|
|
@@ -2170,8 +2954,8 @@ var mailSendCommand = new import_commander31.Command("send").description("\uBA54
|
|
|
2170
2954
|
});
|
|
2171
2955
|
|
|
2172
2956
|
// src/commands/mail/reply.ts
|
|
2173
|
-
var
|
|
2174
|
-
var
|
|
2957
|
+
var import_commander35 = require("commander");
|
|
2958
|
+
var import_promises11 = require("fs/promises");
|
|
2175
2959
|
var import_imapflow2 = require("imapflow");
|
|
2176
2960
|
async function getMessageId(config, uid) {
|
|
2177
2961
|
const imap = getImapConfigOrThrow(config);
|
|
@@ -2198,12 +2982,12 @@ async function getMessageId(config, uid) {
|
|
|
2198
2982
|
await client.logout();
|
|
2199
2983
|
}
|
|
2200
2984
|
}
|
|
2201
|
-
var mailReplyCommand = new
|
|
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) => {
|
|
2202
2986
|
const globalOpts = mailReplyCommand.optsWithGlobals();
|
|
2203
2987
|
const config = await getConfigOrThrow();
|
|
2204
2988
|
let body = opts.body ?? "";
|
|
2205
2989
|
if (opts.bodyFile) {
|
|
2206
|
-
body = await (0,
|
|
2990
|
+
body = await (0, import_promises11.readFile)(opts.bodyFile, "utf-8");
|
|
2207
2991
|
}
|
|
2208
2992
|
if (!body) {
|
|
2209
2993
|
process.stderr.write("\uC624\uB958: --body \uB610\uB294 --body-file\uC744 \uC9C0\uC815\uD558\uC138\uC694\n");
|
|
@@ -2239,19 +3023,19 @@ var mailReplyCommand = new import_commander32.Command("reply").description("\uBA
|
|
|
2239
3023
|
});
|
|
2240
3024
|
|
|
2241
3025
|
// src/index.ts
|
|
2242
|
-
var program = new
|
|
2243
|
-
program.name("dooray").description("Dooray REST API CLI").version("0.
|
|
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");
|
|
2244
3028
|
program.hook("preAction", () => {
|
|
2245
3029
|
const opts = program.opts();
|
|
2246
3030
|
if (opts.color === false || process.env.NO_COLOR) {
|
|
2247
3031
|
import_chalk7.default.level = 0;
|
|
2248
3032
|
}
|
|
2249
3033
|
});
|
|
2250
|
-
var projectCommand = new
|
|
3034
|
+
var projectCommand = new import_commander36.Command("project").description("\uD504\uB85C\uC81D\uD2B8 \uAD00\uB828 \uBA85\uB839");
|
|
2251
3035
|
projectCommand.addCommand(projectListCommand);
|
|
2252
3036
|
projectCommand.addCommand(projectMembersCommand);
|
|
2253
3037
|
projectCommand.addCommand(projectWorkflowsCommand);
|
|
2254
|
-
var postCommand = new
|
|
3038
|
+
var postCommand = new import_commander36.Command("post").description("\uC5C5\uBB34 \uAD00\uB828 \uBA85\uB839");
|
|
2255
3039
|
postCommand.addCommand(postListCommand);
|
|
2256
3040
|
postCommand.addCommand(postSearchCommand);
|
|
2257
3041
|
postCommand.addCommand(postGetCommand);
|
|
@@ -2259,34 +3043,35 @@ postCommand.addCommand(postEditCommand);
|
|
|
2259
3043
|
postCommand.addCommand(postCreateCommand);
|
|
2260
3044
|
postCommand.addCommand(postDoneCommand);
|
|
2261
3045
|
postCommand.addCommand(postWorkflowCommand);
|
|
2262
|
-
var commentCommand = new
|
|
3046
|
+
var commentCommand = new import_commander36.Command("comment").description("\uB313\uAE00 \uAD00\uB828 \uBA85\uB839");
|
|
2263
3047
|
commentCommand.addCommand(commentListCommand);
|
|
2264
3048
|
commentCommand.addCommand(commentAddCommand);
|
|
2265
3049
|
commentCommand.addCommand(commentEditCommand);
|
|
2266
3050
|
commentCommand.addCommand(commentDeleteCommand);
|
|
2267
3051
|
postCommand.addCommand(commentCommand);
|
|
2268
|
-
var fileCommand = new
|
|
3052
|
+
var fileCommand = new import_commander36.Command("file").description("\uCCA8\uBD80\uD30C\uC77C \uAD00\uB828 \uBA85\uB839");
|
|
2269
3053
|
fileCommand.addCommand(fileListCommand);
|
|
2270
3054
|
fileCommand.addCommand(fileDownloadCommand);
|
|
2271
3055
|
fileCommand.addCommand(fileDownloadAllCommand);
|
|
2272
3056
|
fileCommand.addCommand(fileUploadCommand);
|
|
2273
3057
|
fileCommand.addCommand(fileDeleteCommand);
|
|
2274
3058
|
postCommand.addCommand(fileCommand);
|
|
2275
|
-
var wikiCommand = new
|
|
3059
|
+
var wikiCommand = new import_commander36.Command("wiki").description("\uC704\uD0A4 \uAD00\uB828 \uBA85\uB839");
|
|
2276
3060
|
wikiCommand.addCommand(wikiListCommand);
|
|
2277
3061
|
wikiCommand.addCommand(wikiPagesCommand);
|
|
2278
|
-
var wikiPageCommand = new
|
|
3062
|
+
var wikiPageCommand = new import_commander36.Command("page").description("\uC704\uD0A4 \uD398\uC774\uC9C0 \uAD00\uB828 \uBA85\uB839");
|
|
2279
3063
|
wikiPageCommand.addCommand(wikiPageGetCommand);
|
|
2280
3064
|
wikiPageCommand.addCommand(wikiPageCreateCommand);
|
|
2281
3065
|
wikiPageCommand.addCommand(wikiPageEditCommand);
|
|
2282
3066
|
wikiCommand.addCommand(wikiPageCommand);
|
|
2283
|
-
var mailCommand = new
|
|
3067
|
+
var mailCommand = new import_commander36.Command("mail").description("\uBA54\uC77C \uAD00\uB828 \uBA85\uB839");
|
|
2284
3068
|
mailCommand.addCommand(mailListCommand);
|
|
2285
3069
|
mailCommand.addCommand(mailGetCommand);
|
|
2286
3070
|
mailCommand.addCommand(mailSendCommand);
|
|
2287
3071
|
mailCommand.addCommand(mailReplyCommand);
|
|
2288
3072
|
program.addCommand(setupCommand);
|
|
2289
3073
|
program.addCommand(configCommand);
|
|
3074
|
+
program.addCommand(memberCommand);
|
|
2290
3075
|
program.addCommand(cacheCommand);
|
|
2291
3076
|
program.addCommand(doctorCommand);
|
|
2292
3077
|
program.addCommand(projectCommand);
|