@rhseung/ps-cli 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,57 +1,79 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- getAutoOpenEditor,
4
- getBojSessionCookie,
5
- getCodeOpen,
6
- getDefaultLanguage,
7
- getEditor,
8
- getSolvedAcHandle,
9
- setAutoOpenEditor,
10
- setBojSessionCookie,
11
- setCodeOpen,
12
- setDefaultLanguage,
13
- setEditor,
14
- setSolvedAcHandle
15
- } from "../chunk-KFQFQJYT.js";
16
2
  import {
17
3
  getSupportedLanguages,
18
4
  getSupportedLanguagesString
19
5
  } from "../chunk-TQXMB7XV.js";
6
+ import {
7
+ getAutoOpenEditor,
8
+ getDefaultLanguage,
9
+ getEditor,
10
+ getProblemDir,
11
+ getSolvedAcHandle
12
+ } from "../chunk-CIG2LEJC.js";
20
13
  import "../chunk-FYS2JH42.js";
21
14
 
22
15
  // src/commands/config.tsx
16
+ import React from "react";
23
17
  import { render, Text, Box } from "ink";
18
+ import { StatusMessage, Select, TextInput, Alert } from "@inkjs/ui";
19
+ import { readFile, writeFile, unlink } from "fs/promises";
20
+ import { join } from "path";
21
+ import { existsSync } from "fs";
24
22
  import { jsx, jsxs } from "react/jsx-runtime";
23
+ function getProjectConfigPath() {
24
+ return join(process.cwd(), ".ps-cli.json");
25
+ }
26
+ async function readProjectConfig() {
27
+ const configPath = getProjectConfigPath();
28
+ if (!existsSync(configPath)) {
29
+ return null;
30
+ }
31
+ try {
32
+ const content = await readFile(configPath, "utf-8");
33
+ return JSON.parse(content);
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ async function writeProjectConfig(config) {
39
+ const configPath = getProjectConfigPath();
40
+ await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
41
+ }
25
42
  function getConfigHelp() {
26
43
  return `
27
44
  \uC0AC\uC6A9\uBC95:
28
- $ ps config <\uD0A4> [\uAC12]
29
- $ ps config <\uD0A4> --get
30
- $ ps config --list
45
+ $ ps config get [\uD0A4]
46
+ $ ps config set [\uD0A4]
47
+ $ ps config list
48
+ $ ps config clear
31
49
 
32
50
  \uC124\uBA85:
33
- \uC0AC\uC6A9\uC790 \uC124\uC815\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
34
- \uC124\uC815\uC740 ~/.config/ps-cli/config.json\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.
51
+ \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uD30C\uC77C(.ps-cli.json)\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
52
+ \uC124\uC815\uC740 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC758 .ps-cli.json \uD30C\uC77C\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.
53
+
54
+ \uBA85\uB839\uC5B4:
55
+ get [\uD0A4] \uC124\uC815 \uAC12 \uC870\uD68C (\uD0A4 \uC5C6\uC73C\uBA74 \uB300\uD654\uD615 \uC120\uD0DD)
56
+ set [\uD0A4] \uC124\uC815 \uAC12 \uC124\uC815 (\uD0A4 \uC5C6\uC73C\uBA74 \uB300\uD654\uD615 \uC120\uD0DD)
57
+ list \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C
58
+ clear .ps-cli.json \uD30C\uC77C \uC0AD\uC81C
35
59
 
36
60
  \uC124\uC815 \uD0A4:
37
- boj-session-cookie BOJ \uC138\uC158 \uCFE0\uD0A4
38
61
  default-language \uAE30\uBCF8 \uC5B8\uC5B4 (${getSupportedLanguagesString()})
39
- code-open \uCF54\uB4DC \uACF5\uAC1C \uC5EC\uBD80 (true/false)
40
62
  editor \uC5D0\uB514\uD130 \uBA85\uB839\uC5B4 (\uC608: code, vim, nano)
41
63
  auto-open-editor fetch \uD6C4 \uC790\uB3D9\uC73C\uB85C \uC5D0\uB514\uD130 \uC5F4\uAE30 (true/false)
42
64
  solved-ac-handle Solved.ac \uD578\uB4E4 (stats \uBA85\uB839\uC5B4\uC6A9)
65
+ problem-dir \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8\uAC12: problems, "." \uB610\uB294 ""\uB294 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8)
43
66
 
44
67
  \uC635\uC158:
45
- --get \uC124\uC815 \uAC12 \uC870\uD68C
46
- --list \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C
47
68
  --help, -h \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
48
69
 
49
70
  \uC608\uC81C:
50
- $ ps config boj-session-cookie "boj_session=xxx"
51
- $ ps config default-language python
52
- $ ps config solved-ac-handle myhandle
53
- $ ps config solved-ac-handle --get
54
- $ ps config --list
71
+ $ ps config get # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC870\uD68C
72
+ $ ps config get default-language # default-language \uAC12 \uC870\uD68C
73
+ $ ps config set # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC124\uC815
74
+ $ ps config set editor cursor # editor\uB97C cursor\uB85C \uC124\uC815
75
+ $ ps config list # \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C
76
+ $ ps config clear # .ps-cli.json \uD30C\uC77C \uC0AD\uC81C
55
77
  `;
56
78
  }
57
79
  var configHelp = getConfigHelp();
@@ -60,42 +82,113 @@ function ConfigCommand({
60
82
  value,
61
83
  get,
62
84
  list,
85
+ clear,
63
86
  onComplete
64
87
  }) {
88
+ const [config, setConfig] = React.useState(null);
89
+ const [loading, setLoading] = React.useState(true);
90
+ const [cleared, setCleared] = React.useState(false);
91
+ const [saved, setSaved] = React.useState(false);
92
+ React.useEffect(() => {
93
+ async function loadConfig() {
94
+ const projectConfig = await readProjectConfig();
95
+ setConfig(projectConfig);
96
+ setLoading(false);
97
+ }
98
+ void loadConfig();
99
+ }, []);
100
+ React.useEffect(() => {
101
+ if (clear && !cleared) {
102
+ void (async () => {
103
+ const configPath = getProjectConfigPath();
104
+ if (existsSync(configPath)) {
105
+ await unlink(configPath);
106
+ }
107
+ setCleared(true);
108
+ })();
109
+ }
110
+ }, [clear, cleared]);
111
+ React.useEffect(() => {
112
+ if (configKey && value !== void 0 && !saved) {
113
+ void (async () => {
114
+ const currentConfig = await readProjectConfig() ?? {};
115
+ let updatedConfig = { ...currentConfig };
116
+ switch (configKey) {
117
+ case "default-language": {
118
+ const supportedLanguages = getSupportedLanguages();
119
+ if (!supportedLanguages.includes(value)) {
120
+ console.error(
121
+ `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC5B8\uC5B4\uC785\uB2C8\uB2E4: ${value}
122
+ \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}`
123
+ );
124
+ process.exit(1);
125
+ }
126
+ updatedConfig.defaultLanguage = value;
127
+ break;
128
+ }
129
+ case "editor":
130
+ updatedConfig.editor = value;
131
+ break;
132
+ case "auto-open-editor":
133
+ updatedConfig.autoOpenEditor = value === "true";
134
+ break;
135
+ case "solved-ac-handle":
136
+ updatedConfig.solvedAcHandle = value;
137
+ break;
138
+ case "problem-dir":
139
+ updatedConfig.problemDir = value;
140
+ break;
141
+ default:
142
+ console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
143
+ process.exit(1);
144
+ }
145
+ await writeProjectConfig(updatedConfig);
146
+ setSaved(true);
147
+ })();
148
+ }
149
+ }, [configKey, value, saved]);
150
+ if (loading) {
151
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StatusMessage, { variant: "info", children: "\uC124\uC815\uC744 \uBD88\uB7EC\uC624\uB294 \uC911..." }) });
152
+ }
153
+ if (clear) {
154
+ if (!cleared) {
155
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StatusMessage, { variant: "info", children: ".ps-cli.json \uD30C\uC77C\uC744 \uC0AD\uC81C\uD558\uB294 \uC911..." }) });
156
+ }
157
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Alert, { variant: "success", children: ".ps-cli.json \uD30C\uC77C\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4." }) });
158
+ }
65
159
  if (list) {
66
- const bojCookie = getBojSessionCookie();
67
- const defaultLang = getDefaultLanguage();
68
- const codeOpen = getCodeOpen();
69
- const editor = getEditor();
70
- const autoOpen = getAutoOpenEditor();
71
- const handle = getSolvedAcHandle();
160
+ const defaultLang = config?.defaultLanguage ?? getDefaultLanguage();
161
+ const editor = config?.editor ?? getEditor();
162
+ const autoOpen = config?.autoOpenEditor ?? getAutoOpenEditor();
163
+ const handle = config?.solvedAcHandle ?? getSolvedAcHandle();
164
+ const problemDir = config?.problemDir ?? getProblemDir();
72
165
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
73
- /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "\uD604\uC7AC \uC124\uC815:" }) }),
74
- /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
75
- /* @__PURE__ */ jsxs(Text, { children: [
76
- "boj-session-cookie:",
77
- " ",
78
- /* @__PURE__ */ jsx(Text, { color: bojCookie ? "green" : "gray", children: bojCookie ? "\uC124\uC815\uB428" : "\uC124\uC815 \uC548 \uB428" })
79
- ] }),
80
- /* @__PURE__ */ jsxs(Text, { children: [
81
- "default-language: ",
166
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2699\uFE0F \uD604\uC7AC \uC124\uC815 (.ps-cli.json)" }) }),
167
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
168
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
169
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "default-language:" }),
170
+ /* @__PURE__ */ jsx(Text, { children: " " }),
82
171
  /* @__PURE__ */ jsx(Text, { bold: true, children: defaultLang })
83
172
  ] }),
84
- /* @__PURE__ */ jsxs(Text, { children: [
85
- "code-open: ",
86
- /* @__PURE__ */ jsx(Text, { bold: true, children: codeOpen ? "true" : "false" })
87
- ] }),
88
- /* @__PURE__ */ jsxs(Text, { children: [
89
- "editor: ",
173
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
174
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "editor:" }),
175
+ /* @__PURE__ */ jsx(Text, { children: " " }),
90
176
  /* @__PURE__ */ jsx(Text, { bold: true, children: editor })
91
177
  ] }),
92
- /* @__PURE__ */ jsxs(Text, { children: [
93
- "auto-open-editor: ",
94
- /* @__PURE__ */ jsx(Text, { bold: true, children: autoOpen ? "true" : "false" })
178
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
179
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "auto-open-editor:" }),
180
+ /* @__PURE__ */ jsx(Text, { children: " " }),
181
+ /* @__PURE__ */ jsx(Text, { bold: true, color: autoOpen ? "green" : "gray", children: autoOpen ? "true" : "false" })
182
+ ] }),
183
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
184
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "solved-ac-handle:" }),
185
+ /* @__PURE__ */ jsx(Text, { children: " " }),
186
+ /* @__PURE__ */ jsx(Text, { bold: true, color: handle ? "cyan" : "gray", children: handle || "\uC124\uC815 \uC548 \uB428" })
95
187
  ] }),
96
- /* @__PURE__ */ jsxs(Text, { children: [
97
- "solved-ac-handle: ",
98
- /* @__PURE__ */ jsx(Text, { bold: true, children: handle || "\uC124\uC815 \uC548 \uB428" })
188
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
189
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "problem-dir:" }),
190
+ /* @__PURE__ */ jsx(Text, { children: " " }),
191
+ /* @__PURE__ */ jsx(Text, { bold: true, children: problemDir })
99
192
  ] })
100
193
  ] })
101
194
  ] });
@@ -103,72 +196,46 @@ function ConfigCommand({
103
196
  if (get && configKey) {
104
197
  let configValue;
105
198
  switch (configKey) {
106
- case "boj-session-cookie":
107
- configValue = getBojSessionCookie();
108
- break;
109
199
  case "default-language":
110
- configValue = getDefaultLanguage();
111
- break;
112
- case "code-open":
113
- configValue = getCodeOpen() ? "true" : "false";
200
+ configValue = config?.defaultLanguage ?? getDefaultLanguage();
114
201
  break;
115
202
  case "editor":
116
- configValue = getEditor();
203
+ configValue = config?.editor ?? getEditor();
117
204
  break;
118
205
  case "auto-open-editor":
119
- configValue = getAutoOpenEditor() ? "true" : "false";
206
+ configValue = config?.autoOpenEditor !== void 0 ? String(config.autoOpenEditor) : String(getAutoOpenEditor());
120
207
  break;
121
208
  case "solved-ac-handle":
122
- configValue = getSolvedAcHandle();
209
+ configValue = config?.solvedAcHandle ?? getSolvedAcHandle();
210
+ break;
211
+ case "problem-dir":
212
+ configValue = config?.problemDir ?? getProblemDir();
123
213
  break;
124
214
  default:
125
215
  console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
126
216
  process.exit(1);
127
217
  }
128
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: configValue || "(\uC124\uC815 \uC548 \uB428)" }) });
218
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { children: [
219
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
220
+ configKey,
221
+ ":"
222
+ ] }),
223
+ /* @__PURE__ */ jsx(Text, { children: " " }),
224
+ /* @__PURE__ */ jsx(Text, { bold: true, color: configValue ? "cyan" : "gray", children: configValue || "(\uC124\uC815 \uC548 \uB428)" })
225
+ ] }) });
129
226
  }
130
227
  if (configKey && value !== void 0) {
131
- switch (configKey) {
132
- case "boj-session-cookie":
133
- setBojSessionCookie(value);
134
- break;
135
- case "default-language":
136
- const supportedLanguages = getSupportedLanguages();
137
- if (!supportedLanguages.includes(value)) {
138
- console.error(
139
- `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC5B8\uC5B4\uC785\uB2C8\uB2E4: ${value}
140
- \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}`
141
- );
142
- process.exit(1);
143
- }
144
- setDefaultLanguage(value);
145
- break;
146
- case "code-open":
147
- setCodeOpen(value === "true");
148
- break;
149
- case "editor":
150
- setEditor(value);
151
- break;
152
- case "auto-open-editor":
153
- setAutoOpenEditor(value === "true");
154
- break;
155
- case "solved-ac-handle":
156
- setSolvedAcHandle(value);
157
- break;
158
- default:
159
- console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
160
- process.exit(1);
228
+ if (!saved) {
229
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StatusMessage, { variant: "info", children: "\uC124\uC815\uC744 \uC800\uC7A5\uD558\uB294 \uC911..." }) });
161
230
  }
162
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "green", children: [
163
- "\u2713 \uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ",
164
- configKey,
165
- " = ",
166
- value
167
- ] }) });
231
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
232
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "success", children: "\uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4" }) }),
233
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: value }) })
234
+ ] });
168
235
  }
169
236
  return null;
170
237
  }
171
- async function configCommand(configKey, value, get, list) {
238
+ async function configCommand(configKey, value, get, list, clear) {
172
239
  return new Promise((resolve) => {
173
240
  const { unmount } = render(
174
241
  /* @__PURE__ */ jsx(
@@ -178,6 +245,7 @@ async function configCommand(configKey, value, get, list) {
178
245
  value,
179
246
  get,
180
247
  list,
248
+ clear,
181
249
  onComplete: () => {
182
250
  unmount();
183
251
  resolve();
@@ -191,34 +259,189 @@ async function configCommand(configKey, value, get, list) {
191
259
  }, 100);
192
260
  });
193
261
  }
262
+ var CONFIG_KEYS = [
263
+ { label: "default-language", value: "default-language" },
264
+ { label: "editor", value: "editor" },
265
+ { label: "auto-open-editor", value: "auto-open-editor" },
266
+ { label: "solved-ac-handle", value: "solved-ac-handle" },
267
+ { label: "problem-dir", value: "problem-dir" }
268
+ ];
269
+ function ConfigKeySelector({ onSelect }) {
270
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
271
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u2699\uFE0F \uC124\uC815 \uAD00\uB9AC" }) }),
272
+ /* @__PURE__ */ jsx(Alert, { variant: "info", children: "\uC124\uC815 \uD0A4\uB97C \uC120\uD0DD\uD558\uC138\uC694" }),
273
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
274
+ Select,
275
+ {
276
+ options: CONFIG_KEYS,
277
+ onChange: (value) => {
278
+ onSelect(value);
279
+ }
280
+ }
281
+ ) })
282
+ ] });
283
+ }
284
+ async function selectConfigKey() {
285
+ return new Promise((resolve) => {
286
+ const { unmount } = render(
287
+ /* @__PURE__ */ jsx(
288
+ ConfigKeySelector,
289
+ {
290
+ onSelect: (key) => {
291
+ unmount();
292
+ resolve(key);
293
+ }
294
+ }
295
+ )
296
+ );
297
+ });
298
+ }
299
+ function ConfigValueInput({
300
+ configKey,
301
+ onSubmit
302
+ }) {
303
+ const getPlaceholder = () => {
304
+ switch (configKey) {
305
+ case "default-language":
306
+ return `\uC5B8\uC5B4 \uC785\uB825 (${getSupportedLanguagesString()})`;
307
+ case "editor":
308
+ return "\uC5D0\uB514\uD130 \uBA85\uB839\uC5B4 \uC785\uB825";
309
+ case "auto-open-editor":
310
+ return "true \uB610\uB294 false \uC785\uB825";
311
+ case "solved-ac-handle":
312
+ return "Solved.ac \uD578\uB4E4 \uC785\uB825";
313
+ case "problem-dir":
314
+ return "\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C \uC785\uB825";
315
+ default:
316
+ return "\uAC12 \uC785\uB825";
317
+ }
318
+ };
319
+ const getDescription = () => {
320
+ switch (configKey) {
321
+ case "default-language":
322
+ return `\uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}`;
323
+ case "editor":
324
+ return "\uC608: code, cursor, vim, nano";
325
+ case "auto-open-editor":
326
+ return "fetch \uD6C4 \uC790\uB3D9\uC73C\uB85C \uC5D0\uB514\uD130\uB97C \uC5F4\uC9C0 \uC5EC\uBD80";
327
+ case "solved-ac-handle":
328
+ return "Solved.ac \uC0AC\uC6A9\uC790 \uD578\uB4E4";
329
+ case "problem-dir":
330
+ return '\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uAE30\uBCF8\uAC12: "problems", \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8: ".")';
331
+ default:
332
+ return "";
333
+ }
334
+ };
335
+ const getSuggestions = () => {
336
+ switch (configKey) {
337
+ case "default-language":
338
+ return getSupportedLanguages();
339
+ case "editor":
340
+ return ["code", "cursor", "vim", "nano"];
341
+ case "auto-open-editor":
342
+ return ["true", "false"];
343
+ case "problem-dir":
344
+ return ["problems", ".", ""];
345
+ default:
346
+ return [];
347
+ }
348
+ };
349
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
350
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "info", children: "\uAC12\uC744 \uC785\uB825\uD558\uC138\uC694" }) }),
351
+ getDescription() && /* @__PURE__ */ jsx(Box, { marginTop: 1, marginBottom: 0, children: /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: getDescription() }) }),
352
+ /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(
353
+ TextInput,
354
+ {
355
+ placeholder: getPlaceholder(),
356
+ suggestions: getSuggestions(),
357
+ onSubmit: (value) => {
358
+ onSubmit(value);
359
+ }
360
+ }
361
+ ) })
362
+ ] });
363
+ }
364
+ async function inputConfigValue(configKey) {
365
+ return new Promise((resolve) => {
366
+ const { unmount } = render(
367
+ /* @__PURE__ */ jsx(
368
+ ConfigValueInput,
369
+ {
370
+ configKey,
371
+ onSubmit: (value) => {
372
+ unmount();
373
+ resolve(value);
374
+ }
375
+ }
376
+ )
377
+ );
378
+ });
379
+ }
194
380
  async function configExecute(args, flags) {
195
381
  if (flags.help) {
196
382
  console.log(getConfigHelp().trim());
197
383
  process.exit(0);
198
384
  return;
199
385
  }
200
- if (flags.list) {
386
+ const command = args[0];
387
+ if (command === "clear") {
388
+ await configCommand(void 0, void 0, false, false, true);
389
+ return;
390
+ }
391
+ if (command === "list" || flags.list) {
201
392
  await configCommand(void 0, void 0, false, true);
202
393
  return;
203
394
  }
204
- const key = args[0];
205
- const value = args[1];
206
- if (!key) {
207
- console.error("\uC624\uB958: \uC124\uC815 \uD0A4\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
208
- console.error(`\uC0AC\uC6A9\uBC95: ps config <\uD0A4> [\uAC12]`);
209
- console.error(`\uB3C4\uC6C0\uB9D0: ps config --help`);
210
- process.exit(1);
395
+ if (command === "get") {
396
+ const key = args[1];
397
+ if (key) {
398
+ await configCommand(key, void 0, true, false);
399
+ } else {
400
+ const selectedKey = await selectConfigKey();
401
+ if (!selectedKey) {
402
+ process.exit(0);
403
+ return;
404
+ }
405
+ await configCommand(selectedKey, void 0, true, false);
406
+ }
407
+ return;
408
+ }
409
+ if (command === "set") {
410
+ const key = args[1];
411
+ if (key) {
412
+ const inputValue = await inputConfigValue(key);
413
+ if (!inputValue) {
414
+ process.exit(0);
415
+ return;
416
+ }
417
+ await configCommand(key, inputValue, false, false);
418
+ } else {
419
+ const selectedKey = await selectConfigKey();
420
+ if (!selectedKey) {
421
+ process.exit(0);
422
+ return;
423
+ }
424
+ const inputValue = await inputConfigValue(selectedKey);
425
+ if (!inputValue) {
426
+ process.exit(0);
427
+ return;
428
+ }
429
+ await configCommand(selectedKey, inputValue, false, false);
430
+ }
431
+ return;
211
432
  }
212
- if (flags.get) {
213
- await configCommand(key, void 0, true, false);
214
- } else if (value !== void 0) {
215
- await configCommand(key, value, false, false);
216
- } else {
217
- console.error("\uC624\uB958: \uC124\uC815 \uAC12\uC744 \uC785\uB825\uD558\uAC70\uB098 --get \uC635\uC158\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.");
218
- console.error(`\uC0AC\uC6A9\uBC95: ps config <\uD0A4> <\uAC12>`);
219
- console.error(`\uC0AC\uC6A9\uBC95: ps config <\uD0A4> --get`);
433
+ if (!command) {
434
+ console.error("\uC624\uB958: \uBA85\uB839\uC5B4\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
435
+ console.error("\uC0AC\uC6A9\uBC95: ps config <\uBA85\uB839\uC5B4>");
436
+ console.error("\uBA85\uB839\uC5B4: get, set, list, clear");
437
+ console.error("\uB3C4\uC6C0\uB9D0: ps config --help");
220
438
  process.exit(1);
439
+ return;
221
440
  }
441
+ console.error(`\uC624\uB958: \uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4: ${command}`);
442
+ console.error("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBA85\uB839\uC5B4: get, set, list, clear");
443
+ console.error("\uB3C4\uC6C0\uB9D0: ps config --help");
444
+ process.exit(1);
222
445
  }
223
446
  var configCommandDef = {
224
447
  name: "config",
@@ -7,25 +7,24 @@ import {
7
7
  source_default
8
8
  } from "../chunk-2E4VSP6O.js";
9
9
  import {
10
- getAutoOpenEditor,
11
- getEditor
12
- } from "../chunk-KFQFQJYT.js";
13
- import {
10
+ getProblemDirPath,
14
11
  getProblemId
15
- } from "../chunk-OOTPZD7O.js";
12
+ } from "../chunk-BM3ZMA4K.js";
16
13
  import {
17
14
  getLanguageConfig,
18
15
  getSupportedLanguages,
19
16
  getSupportedLanguagesString
20
17
  } from "../chunk-TQXMB7XV.js";
21
18
  import {
22
- LoadingSpinner
23
- } from "../chunk-IJLJBKLK.js";
19
+ getAutoOpenEditor,
20
+ getEditor
21
+ } from "../chunk-CIG2LEJC.js";
24
22
  import "../chunk-FYS2JH42.js";
25
23
 
26
24
  // src/commands/fetch.tsx
27
25
  import { useState, useEffect } from "react";
28
- import { render, Text as Text2, Box as Box2 } from "ink";
26
+ import { render, Box as Box2 } from "ink";
27
+ import { StatusMessage, Alert } from "@inkjs/ui";
29
28
 
30
29
  // src/services/scraper.ts
31
30
  import * as cheerio from "cheerio";
@@ -290,7 +289,7 @@ function getProjectRoot() {
290
289
  return join(__dirname, "../..");
291
290
  }
292
291
  async function generateProblemFiles(problem, language = "python") {
293
- const problemDir = join(process.cwd(), "problems", problem.id.toString());
292
+ const problemDir = getProblemDirPath(problem.id);
294
293
  await mkdir(problemDir, { recursive: true });
295
294
  const langConfig = getLanguageConfig(language);
296
295
  const projectRoot = getProjectRoot();
@@ -430,6 +429,7 @@ function ProblemDashboard({ problem }) {
430
429
  }
431
430
 
432
431
  // src/commands/fetch.tsx
432
+ import { Spinner } from "@inkjs/ui";
433
433
  import { execaCommand } from "execa";
434
434
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
435
435
  function FetchCommand({
@@ -515,19 +515,19 @@ function FetchCommand({
515
515
  }, [problemId, language, onComplete]);
516
516
  if (status === "loading") {
517
517
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
518
- /* @__PURE__ */ jsx2(LoadingSpinner, { message }),
518
+ /* @__PURE__ */ jsx2(Spinner, { label: message }),
519
519
  problem && /* @__PURE__ */ jsx2(ProblemDashboard, { problem })
520
520
  ] });
521
521
  }
522
522
  if (status === "error") {
523
- return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: /* @__PURE__ */ jsxs2(Text2, { color: "red", children: [
524
- "\u2717 \uC624\uB958 \uBC1C\uC0DD: ",
523
+ return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: /* @__PURE__ */ jsxs2(Alert, { variant: "error", children: [
524
+ "\uC624\uB958 \uBC1C\uC0DD: ",
525
525
  error
526
526
  ] }) });
527
527
  }
528
528
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: "100%", children: [
529
529
  problem && /* @__PURE__ */ jsx2(Box2, { alignSelf: "flex-start", children: /* @__PURE__ */ jsx2(ProblemDashboard, { problem }) }),
530
- /* @__PURE__ */ jsx2(Text2, { color: "green", children: message })
530
+ /* @__PURE__ */ jsx2(StatusMessage, { variant: "success", children: message })
531
531
  ] });
532
532
  }
533
533
  async function fetchCommand(problemId, language) {