@rhseung/ps-cli 1.7.4 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  useOpenBrowser
4
- } from "../chunk-GCOFFYJ3.js";
4
+ } from "../chunk-3LR2NGRC.js";
5
5
  import "../chunk-QGMWUOJ3.js";
6
+ import {
7
+ defineFlags
8
+ } from "../chunk-PY6GW22W.js";
6
9
  import {
7
10
  Command,
8
11
  CommandBuilder,
9
12
  CommandDef,
10
13
  resolveProblemContext
11
- } from "../chunk-F4LZ6ENP.js";
14
+ } from "../chunk-JPDN34C7.js";
12
15
  import {
13
16
  __decorateClass
14
17
  } from "../chunk-7MQMPJ3X.js";
@@ -18,17 +21,30 @@ import { StatusMessage, Alert } from "@inkjs/ui";
18
21
  import { Spinner } from "@inkjs/ui";
19
22
  import { Text, Box } from "ink";
20
23
  import { jsx, jsxs } from "react/jsx-runtime";
21
- function OpenView({ problemId, onComplete }) {
24
+ var openFlagsSchema = {
25
+ workbook: {
26
+ type: "number",
27
+ shortFlag: "w",
28
+ description: "\uBB38\uC81C\uC9D1 ID\uB97C \uC9C0\uC815\uD558\uC5EC \uD574\uB2F9 \uBB38\uC81C\uC9D1 \uD398\uC774\uC9C0\uB97C \uC5FD\uB2C8\uB2E4"
29
+ }
30
+ };
31
+ function OpenView({ problemId, workbookId, onComplete }) {
22
32
  const { status, error, url } = useOpenBrowser({
23
33
  problemId,
34
+ workbookId,
24
35
  onComplete
25
36
  });
37
+ const displayId = workbookId !== void 0 ? workbookId : problemId;
38
+ const displayType = workbookId !== void 0 ? "\uBB38\uC81C\uC9D1" : "\uBB38\uC81C";
26
39
  if (status === "loading") {
27
40
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
28
41
  /* @__PURE__ */ jsx(Spinner, { label: "\uBE0C\uB77C\uC6B0\uC800\uB97C \uC5EC\uB294 \uC911..." }),
29
42
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
30
- "\uBB38\uC81C #",
31
- problemId
43
+ displayType,
44
+ " ",
45
+ workbookId !== void 0 ? "ID" : "#",
46
+ ": ",
47
+ displayId
32
48
  ] }) })
33
49
  ] });
34
50
  }
@@ -45,12 +61,21 @@ function OpenView({ problemId, onComplete }) {
45
61
  ] });
46
62
  }
47
63
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", children: [
48
- /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: "\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4!" }),
64
+ /* @__PURE__ */ jsxs(StatusMessage, { variant: "success", children: [
65
+ "\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C ",
66
+ displayType,
67
+ " \uD398\uC774\uC9C0\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4!"
68
+ ] }),
49
69
  /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
50
70
  /* @__PURE__ */ jsxs(Text, { children: [
51
- /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\uBB38\uC81C \uBC88\uD638:" }),
71
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
72
+ displayType,
73
+ " ",
74
+ workbookId !== void 0 ? "ID" : "\uBC88\uD638",
75
+ ":"
76
+ ] }),
52
77
  " ",
53
- problemId
78
+ displayId
54
79
  ] }),
55
80
  /* @__PURE__ */ jsxs(Text, { children: [
56
81
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "URL:" }),
@@ -61,11 +86,26 @@ function OpenView({ problemId, onComplete }) {
61
86
  ] });
62
87
  }
63
88
  var OpenCommand = class extends Command {
64
- async execute(args, _flags) {
89
+ async execute(args, flags) {
90
+ const workbookId = flags.workbook ? parseInt(String(flags.workbook), 10) : null;
91
+ if (workbookId !== null) {
92
+ if (isNaN(workbookId) || workbookId <= 0) {
93
+ console.error("\uC624\uB958: \uC720\uD6A8\uD55C \uBB38\uC81C\uC9D1 ID\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
94
+ console.error(`\uC0AC\uC6A9\uBC95: ps open --workbook <\uBB38\uC81C\uC9D1ID>`);
95
+ console.error(`\uB3C4\uC6C0\uB9D0: ps open --help`);
96
+ process.exit(1);
97
+ return;
98
+ }
99
+ await this.renderView(OpenView, {
100
+ workbookId
101
+ });
102
+ return;
103
+ }
65
104
  const context = await resolveProblemContext(args, { requireId: true });
66
105
  if (context.problemId === null) {
67
106
  console.error("\uC624\uB958: \uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
68
107
  console.error(`\uC0AC\uC6A9\uBC95: ps open <\uBB38\uC81C\uBC88\uD638>`);
108
+ console.error(` ps open --workbook <\uBB38\uC81C\uC9D1ID>`);
69
109
  console.error(`\uB3C4\uC6C0\uB9D0: ps open --help`);
70
110
  console.error(
71
111
  `\uD78C\uD2B8: problems/{\uBB38\uC81C\uBC88\uD638} \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.`
@@ -81,14 +121,18 @@ var OpenCommand = class extends Command {
81
121
  OpenCommand = __decorateClass([
82
122
  CommandDef({
83
123
  name: "open",
84
- description: `\uBC31\uC900 \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC5FD\uB2C8\uB2E4.
124
+ description: `\uBC31\uC900 \uBB38\uC81C \uD398\uC774\uC9C0 \uB610\uB294 \uBB38\uC81C\uC9D1 \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC5FD\uB2C8\uB2E4.
85
125
  - \uBB38\uC81C \uBC88\uD638\uB97C \uC778\uC790\uB85C \uC804\uB2EC\uD558\uAC70\uB098
86
- - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.`,
126
+ - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBB38\uC81C \uBC88\uD638\uB97C \uCD94\uB860\uD569\uB2C8\uB2E4.
127
+ - --workbook \uC635\uC158\uC73C\uB85C \uBB38\uC81C\uC9D1 ID\uB97C \uC9C0\uC815\uD558\uBA74 \uBB38\uC81C\uC9D1 \uD398\uC774\uC9C0\uB97C \uC5FD\uB2C8\uB2E4.`,
87
128
  autoDetectProblemId: true,
88
- requireProblemId: true,
129
+ requireProblemId: false,
130
+ flags: defineFlags(openFlagsSchema),
89
131
  examples: [
90
132
  "open 1000 # 1000\uBC88 \uBB38\uC81C \uC5F4\uAE30",
91
133
  "open # \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589 \uC2DC \uC790\uB3D9 \uCD94\uB860",
134
+ "open --workbook 25052 # \uBB38\uC81C\uC9D1 25052 \uC5F4\uAE30",
135
+ "open -w 25052 # \uBB38\uC81C\uC9D1 25052 \uC5F4\uAE30 (\uB2E8\uCD95 \uC635\uC158)",
92
136
  "open --help # \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC"
93
137
  ]
94
138
  })
@@ -1,21 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSolution
4
- } from "../chunk-OJZLQ6FK.js";
4
+ } from "../chunk-VIHXBCOZ.js";
5
+ import {
6
+ defineFlags
7
+ } from "../chunk-PY6GW22W.js";
5
8
  import {
6
9
  Command,
7
10
  CommandBuilder,
8
11
  CommandDef,
9
12
  resolveLanguage,
10
13
  resolveProblemContext
11
- } from "../chunk-F4LZ6ENP.js";
14
+ } from "../chunk-JPDN34C7.js";
12
15
  import {
13
16
  __decorateClass,
14
17
  getSupportedLanguagesString
15
18
  } from "../chunk-7MQMPJ3X.js";
16
19
 
17
20
  // src/commands/run.tsx
18
- import { readdir } from "fs/promises";
19
21
  import { join } from "path";
20
22
  import { StatusMessage, Alert } from "@inkjs/ui";
21
23
  import { Spinner } from "@inkjs/ui";
@@ -64,6 +66,19 @@ function useRunSolution({
64
66
 
65
67
  // src/commands/run.tsx
66
68
  import { jsx, jsxs } from "react/jsx-runtime";
69
+ var runFlagsSchema = {
70
+ language: {
71
+ type: "string",
72
+ shortFlag: "l",
73
+ description: `\uC5B8\uC5B4 \uC120\uD0DD (\uC9C0\uC815 \uC2DC \uC790\uB3D9 \uAC10\uC9C0 \uBB34\uC2DC)
74
+ \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}`
75
+ },
76
+ input: {
77
+ type: "string",
78
+ shortFlag: "i",
79
+ description: "\uC785\uB825 \uD30C\uC77C \uC9C0\uC815 (\uC608: 1 \uB610\uB294 testcases/1/input.txt)"
80
+ }
81
+ };
67
82
  function RunView({
68
83
  problemDir,
69
84
  language,
@@ -77,6 +92,17 @@ function RunView({
77
92
  onComplete
78
93
  });
79
94
  if (status === "loading") {
95
+ if (!inputFile) {
96
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
97
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\uD45C\uC900 \uC785\uB825 \uB300\uAE30 \uC911" }) }),
98
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
99
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\uC785\uB825\uC744 \uC785\uB825\uD55C \uD6C4, \uB9C8\uC9C0\uB9C9 \uC904\uC5D0\uC11C Enter\uB97C \uB204\uB974\uACE0:" }),
100
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\u2022 macOS/Linux: Ctrl+D" }),
101
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\u2022 Windows: Ctrl+Z (\uADF8\uB9AC\uACE0 Enter)" }),
102
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: '\uC608: "3 4" \uC785\uB825 \u2192 Enter \u2192 Ctrl+D' })
103
+ ] })
104
+ ] });
105
+ }
80
106
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: "\uCF54\uB4DC \uC2E4\uD589 \uC911..." }) });
81
107
  }
82
108
  if (status === "error") {
@@ -87,7 +113,7 @@ function RunView({
87
113
  }
88
114
  if (result) {
89
115
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
90
- /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
116
+ /* @__PURE__ */ jsxs(Box, { children: [
91
117
  /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\uC2E4\uD589 \uACB0\uACFC" }),
92
118
  /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
93
119
  problemDir,
@@ -102,9 +128,13 @@ function RunView({
102
128
  result.exitCode,
103
129
  ")"
104
130
  ] }) : /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: "\uC2E4\uD589 \uC644\uB8CC" }),
131
+ result.input && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
132
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\uC785\uB825:" }),
133
+ /* @__PURE__ */ jsx(Text, { children: result.input.trim() })
134
+ ] }),
105
135
  result.stdout && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
106
136
  /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\uCD9C\uB825:" }),
107
- /* @__PURE__ */ jsx(Text, { children: result.stdout })
137
+ /* @__PURE__ */ jsx(Text, { children: result.stdout.trim() })
108
138
  ] }),
109
139
  result.stderr && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
110
140
  /* @__PURE__ */ jsx(Text, { color: "yellow", dimColor: true, children: "\uC5D0\uB7EC \uCD9C\uB825:" }),
@@ -123,7 +153,20 @@ function RunView({
123
153
  var RunCommand = class extends Command {
124
154
  async execute(args, flags) {
125
155
  const context = await resolveProblemContext(args);
126
- const inputPath = flags.input ? join(context.archiveDir, flags.input) : await this.findInputFile(context.archiveDir);
156
+ let inputPath;
157
+ if (flags.input) {
158
+ const inputValue = flags.input;
159
+ if (/^\d+$/.test(inputValue)) {
160
+ inputPath = join(
161
+ context.archiveDir,
162
+ "testcases",
163
+ inputValue,
164
+ "input.txt"
165
+ );
166
+ } else {
167
+ inputPath = join(context.archiveDir, inputValue);
168
+ }
169
+ }
127
170
  const detectedLanguage = await resolveLanguage(
128
171
  context.archiveDir,
129
172
  flags.language
@@ -134,15 +177,6 @@ var RunCommand = class extends Command {
134
177
  inputFile: inputPath
135
178
  });
136
179
  }
137
- // 입력 파일 찾기: private 메서드
138
- async findInputFile(problemDir) {
139
- const files = await readdir(problemDir);
140
- const inputFile = files.find((f) => f === "input1.txt") || files.find((f) => f === "input.txt");
141
- if (!inputFile) {
142
- throw new Error("input.txt \uB610\uB294 input1.txt \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
143
- }
144
- return join(problemDir, inputFile);
145
- }
146
180
  };
147
181
  RunCommand = __decorateClass([
148
182
  CommandDef({
@@ -150,32 +184,18 @@ RunCommand = __decorateClass([
150
184
  description: `\uCF54\uB4DC\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4 (\uD14C\uC2A4\uD2B8 \uC5C6\uC774).
151
185
  - \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC \uB610\uB294 \uC9C0\uC815\uD55C \uBB38\uC81C \uBC88\uD638\uC758 \uCF54\uB4DC \uC2E4\uD589
152
186
  - solution.* \uD30C\uC77C\uC744 \uC790\uB3D9\uC73C\uB85C \uCC3E\uC544 \uC5B8\uC5B4 \uAC10\uC9C0
153
- - input.txt \uB610\uB294 input1.txt\uB97C \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC0AC\uC6A9
187
+ - --input \uC635\uC158\uC73C\uB85C \uC785\uB825 \uD30C\uC77C \uC9C0\uC815 \uAC00\uB2A5 (\uC608: testcases/1/input.txt)
188
+ - \uC635\uC158 \uC5C6\uC774 \uC2E4\uD589 \uC2DC \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC785\uB825 \uBC1B\uAE30
154
189
  - \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 \uAC80\uC99D \uC5C6\uC774 \uB2E8\uC21C \uC2E4\uD589`,
155
- flags: [
156
- {
157
- name: "language",
158
- options: {
159
- shortFlag: "l",
160
- description: `\uC5B8\uC5B4 \uC120\uD0DD (\uC9C0\uC815 \uC2DC \uC790\uB3D9 \uAC10\uC9C0 \uBB34\uC2DC)
161
- \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}`
162
- }
163
- },
164
- {
165
- name: "input",
166
- options: {
167
- shortFlag: "i",
168
- description: "\uC785\uB825 \uD30C\uC77C \uC9C0\uC815 (\uAE30\uBCF8\uAC12: input.txt \uB610\uB294 input1.txt)"
169
- }
170
- }
171
- ],
190
+ flags: defineFlags(runFlagsSchema),
172
191
  autoDetectProblemId: true,
173
192
  autoDetectLanguage: true,
174
193
  examples: [
175
- "run # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589",
176
- "run 1000 # 1000\uBC88 \uBB38\uC81C \uC2E4\uD589",
177
- "run --language python # Python\uC73C\uB85C \uC2E4\uD589",
178
- "run --input input2.txt # \uD2B9\uC815 \uC785\uB825 \uD30C\uC77C \uC0AC\uC6A9"
194
+ "run # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC2E4\uD589",
195
+ "run 1000 # 1000\uBC88 \uBB38\uC81C \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC2E4\uD589",
196
+ "run --language python # Python\uC73C\uB85C \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC2E4\uD589",
197
+ "run --input 1 # \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 1\uBC88 \uC0AC\uC6A9",
198
+ "run --input testcases/1/input.txt # \uC804\uCCB4 \uACBD\uB85C\uB85C \uC785\uB825 \uD30C\uC77C \uC9C0\uC815"
179
199
  ]
180
200
  })
181
201
  ], RunCommand);
@@ -7,11 +7,14 @@ import {
7
7
  } from "../chunk-4ISG24GW.js";
8
8
  import {
9
9
  getProblem
10
- } from "../chunk-A6STXEAE.js";
10
+ } from "../chunk-QB2R47PW.js";
11
11
  import {
12
12
  useOpenBrowser
13
- } from "../chunk-GCOFFYJ3.js";
13
+ } from "../chunk-3LR2NGRC.js";
14
14
  import "../chunk-QGMWUOJ3.js";
15
+ import {
16
+ defineFlags
17
+ } from "../chunk-PY6GW22W.js";
15
18
  import {
16
19
  Command,
17
20
  CommandBuilder,
@@ -19,7 +22,7 @@ import {
19
22
  getArchiveDirPath,
20
23
  getTierColor,
21
24
  getTierName
22
- } from "../chunk-F4LZ6ENP.js";
25
+ } from "../chunk-JPDN34C7.js";
23
26
  import {
24
27
  __decorateClass
25
28
  } from "../chunk-7MQMPJ3X.js";
@@ -48,20 +51,20 @@ function ProblemSelector({
48
51
  const solvedText = problem.solvedCount ? ` (${problem.solvedCount.toLocaleString()}\uBA85` : "";
49
52
  const triesText = problem.averageTries ? `, \uD3C9\uADE0 ${problem.averageTries}\uD68C` : "";
50
53
  const suffix = solvedText + triesText + (solvedText ? ")" : "");
51
- const solvedMark = problem.isSolved ? " \u2713" : "";
54
+ const solvedMark = problem.isSolved ? ` ${source_default.bold.green("\u2713")}` : "";
52
55
  let tierText = "";
53
56
  if (problem.level) {
54
57
  const tierName = getTierName(problem.level);
55
58
  const tierColor = getTierColor(problem.level);
56
59
  if (typeof tierColor === "string") {
57
- tierText = ` ${source_default.bold.hex(tierColor)(tierName)}`;
60
+ tierText = `${source_default.bold.hex(tierColor)(tierName)} `;
58
61
  } else {
59
- tierText = ` ${tierColor(source_default.bold(tierName))}`;
62
+ tierText = `${tierColor(source_default.bold(tierName))} `;
60
63
  }
61
64
  }
62
65
  const problemText = `${problem.problemId} - ${problem.title}`;
63
66
  options.push({
64
- label: `${tierText} ${problemText}${solvedMark}${suffix}`,
67
+ label: `${tierText}${problemText}${suffix}${solvedMark}`,
65
68
  value: `problem:${problem.problemId}`
66
69
  });
67
70
  });
@@ -180,6 +183,13 @@ async function scrapeWorkbook(workbookId) {
180
183
 
181
184
  // src/commands/search.tsx
182
185
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
186
+ var searchFlagsSchema = {
187
+ workbook: {
188
+ type: "number",
189
+ shortFlag: "w",
190
+ description: "\uBB38\uC81C\uC9D1 ID\uB97C \uC9C0\uC815\uD558\uC5EC \uD574\uB2F9 \uBB38\uC81C\uC9D1\uC758 \uBB38\uC81C \uBAA9\uB85D\uC744 \uD45C\uC2DC"
191
+ }
192
+ };
183
193
  async function enrichProblemsWithTiers(problems) {
184
194
  const BATCH_SIZE = 10;
185
195
  const DELAY_MS = 200;
@@ -191,7 +201,10 @@ async function enrichProblemsWithTiers(problems) {
191
201
  const solvedAcData = await getProblem(problem.problemId);
192
202
  return {
193
203
  ...problem,
194
- level: solvedAcData.level
204
+ level: solvedAcData.level,
205
+ tags: solvedAcData.tags.map(
206
+ (t) => t.displayNames.find((n) => n.language === "ko")?.name || t.key
207
+ )
195
208
  };
196
209
  } catch (error) {
197
210
  console.warn(
@@ -270,7 +283,10 @@ function WorkbookSearchView({
270
283
  ] });
271
284
  }
272
285
  const problemsWithSolvedStatus = problems.map((problem) => {
273
- const problemDirPath = getArchiveDirPath(problem.problemId);
286
+ const problemDirPath = getArchiveDirPath(problem.problemId, process.cwd(), {
287
+ level: problem.level,
288
+ tags: problem.tags
289
+ });
274
290
  const isSolved = existsSync(problemDirPath);
275
291
  return {
276
292
  problemId: problem.problemId,
@@ -360,12 +376,34 @@ function SearchView({ query, onComplete }) {
360
376
  setLoading(true);
361
377
  setError(null);
362
378
  const searchResults = await searchProblems(query, currentPage);
379
+ const enrichedProblems = await enrichProblemsWithTiers(
380
+ searchResults.problems.map((p) => ({
381
+ problemId: p.problemId,
382
+ title: p.title,
383
+ order: 0
384
+ // SearchResult에는 order가 없으므로 0으로 설정
385
+ }))
386
+ );
363
387
  const resultsWithSolvedStatus = searchResults.problems.map(
364
388
  (problem) => {
365
- const problemDirPath = getArchiveDirPath(problem.problemId);
389
+ const enriched = enrichedProblems.find(
390
+ (ep) => ep.problemId === problem.problemId
391
+ );
392
+ const level = enriched?.level ?? problem.level;
393
+ const tags = enriched?.tags ?? problem.tags;
394
+ const problemDirPath = getArchiveDirPath(
395
+ problem.problemId,
396
+ process.cwd(),
397
+ {
398
+ level,
399
+ tags
400
+ }
401
+ );
366
402
  const isSolved = existsSync(problemDirPath);
367
403
  return {
368
404
  ...problem,
405
+ level,
406
+ tags,
369
407
  isSolved
370
408
  };
371
409
  }
@@ -483,14 +521,7 @@ SearchCommand = __decorateClass([
483
521
  - \uBB38\uC81C \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uBB38\uC81C \uD398\uC774\uC9C0\uB97C \uC5FD\uB2C8\uB2E4.
484
522
  - \uD398\uC774\uC9C0\uB124\uC774\uC158\uC744 \uD1B5\uD574 \uC5EC\uB7EC \uD398\uC774\uC9C0\uC758 \uACB0\uACFC\uB97C \uD0D0\uC0C9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
485
523
  - --workbook \uC635\uC158\uC73C\uB85C \uBC31\uC900 \uBB38\uC81C\uC9D1\uC758 \uBB38\uC81C \uBAA9\uB85D\uC744 \uBCFC \uC218 \uC788\uC2B5\uB2C8\uB2E4.`,
486
- flags: [
487
- {
488
- name: "workbook",
489
- options: {
490
- description: "\uBB38\uC81C\uC9D1 ID\uB97C \uC9C0\uC815\uD558\uC5EC \uD574\uB2F9 \uBB38\uC81C\uC9D1\uC758 \uBB38\uC81C \uBAA9\uB85D\uC744 \uD45C\uC2DC"
491
- }
492
- }
493
- ],
524
+ flags: defineFlags(searchFlagsSchema),
494
525
  autoDetectProblemId: false,
495
526
  requireProblemId: false,
496
527
  examples: [
@@ -499,7 +530,8 @@ SearchCommand = __decorateClass([
499
530
  'search "#dp" # DP \uD0DC\uADF8 \uBB38\uC81C \uAC80\uC0C9',
500
531
  'search "tag:dp" # DP \uD0DC\uADF8 \uBB38\uC81C \uAC80\uC0C9 (tag: \uBB38\uBC95)',
501
532
  'search "*g1...g5 #dp" # Gold 1-5 \uD2F0\uC5B4\uC758 DP \uD0DC\uADF8 \uBB38\uC81C \uAC80\uC0C9',
502
- "search --workbook 25052 # \uBB38\uC81C\uC9D1 25052\uC758 \uBB38\uC81C \uBAA9\uB85D \uD45C\uC2DC"
533
+ "search --workbook 25052 # \uBB38\uC81C\uC9D1 25052\uC758 \uBB38\uC81C \uBAA9\uB85D \uD45C\uC2DC",
534
+ "search -w 25052 # \uBB38\uC81C\uC9D1 25052\uC758 \uBB38\uC81C \uBAA9\uB85D \uD45C\uC2DC (\uB2E8\uCD95 \uC635\uC158)"
503
535
  ]
504
536
  })
505
537
  ], SearchCommand);