@rhseung/ps-cli 1.9.8 → 1.10.2

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,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getLanguageConfig
4
- } from "./chunk-Q5NECGFA.js";
4
+ } from "./chunk-AHE4QHJD.js";
5
5
 
6
6
  // src/services/runner.ts
7
7
  import { readFile } from "fs/promises";
8
8
  import { join } from "path";
9
9
  import { createInterface } from "readline";
10
- import { execa, execaCommand } from "execa";
10
+ import { execaCommand } from "execa";
11
11
  async function readStdin() {
12
12
  return new Promise((resolve) => {
13
13
  const lines = [];
@@ -49,7 +49,7 @@ async function runSolution({
49
49
  timeout: timeoutMs
50
50
  });
51
51
  }
52
- const child = execa(langConfig.runCommand, [solutionPath], {
52
+ const child = execaCommand(`${langConfig.runCommand} ${solutionPath}`, {
53
53
  cwd: problemDir,
54
54
  ...input !== void 0 ? { input } : { stdin: "inherit" },
55
55
  timeout: timeoutMs
@@ -12,7 +12,7 @@ import {
12
12
  getSolvingDirPath,
13
13
  logger,
14
14
  resolveProblemContext
15
- } from "./chunk-Q5NECGFA.js";
15
+ } from "./chunk-AHE4QHJD.js";
16
16
 
17
17
  // src/commands/archive.tsx
18
18
  import { StatusMessage, Alert, Spinner } from "@inkjs/ui";
@@ -13,7 +13,7 @@ import {
13
13
  getSupportedLanguagesString,
14
14
  resolveLanguage,
15
15
  resolveProblemContext
16
- } from "./chunk-Q5NECGFA.js";
16
+ } from "./chunk-AHE4QHJD.js";
17
17
 
18
18
  // src/commands/submit.tsx
19
19
  import { Badge, StatusMessage, Alert, Spinner } from "@inkjs/ui";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger
4
- } from "./chunk-Q5NECGFA.js";
4
+ } from "./chunk-AHE4QHJD.js";
5
5
 
6
6
  // src/services/scraper.ts
7
7
  import * as cheerio from "cheerio";
@@ -2,13 +2,14 @@
2
2
  import {
3
3
  getProblem,
4
4
  scrapeProblem
5
- } from "./chunk-YCFY6UCA.js";
5
+ } from "./chunk-S7IL7OXF.js";
6
6
  import {
7
7
  Command,
8
8
  CommandBuilder,
9
9
  CommandDef,
10
10
  __decorateClass,
11
11
  defineFlags,
12
+ findProjectRoot,
12
13
  getAutoOpenEditor,
13
14
  getEditor,
14
15
  getIncludeTag,
@@ -22,7 +23,7 @@ import {
22
23
  logger,
23
24
  parseTimeLimitToMs,
24
25
  resolveProblemContext
25
- } from "./chunk-Q5NECGFA.js";
26
+ } from "./chunk-AHE4QHJD.js";
26
27
 
27
28
  // src/commands/fetch.tsx
28
29
  import { StatusMessage, Alert, Spinner } from "@inkjs/ui";
@@ -109,19 +110,39 @@ async function generateProblemFiles(problem, language = "python") {
109
110
  await mkdir(problemDir, { recursive: true });
110
111
  const langConfig = getLanguageConfig(language);
111
112
  const projectRoot = getProjectRoot();
112
- const templatePath = join(projectRoot, "templates", langConfig.templateFile);
113
+ const userProjectRoot = findProjectRoot(process.cwd());
113
114
  const solutionPath = join(problemDir, `solution.${langConfig.extension}`);
114
- try {
115
- const templateContent = await readFile(templatePath, "utf-8");
116
- await writeFile(solutionPath, templateContent, "utf-8");
117
- } catch {
118
- await writeFile(
119
- solutionPath,
120
- `// Problem ${problem.id}: ${problem.title}
121
- `,
122
- "utf-8"
115
+ let templateContent = "";
116
+ let templateFound = false;
117
+ if (userProjectRoot) {
118
+ const localTemplatePath = join(
119
+ userProjectRoot,
120
+ ".ps-cli",
121
+ "templates",
122
+ langConfig.templateFile
123
123
  );
124
+ if (existsSync(localTemplatePath)) {
125
+ try {
126
+ templateContent = await readFile(localTemplatePath, "utf-8");
127
+ templateFound = true;
128
+ } catch {
129
+ }
130
+ }
131
+ }
132
+ if (!templateFound) {
133
+ const templatePath = join(
134
+ projectRoot,
135
+ "templates",
136
+ langConfig.templateFile
137
+ );
138
+ try {
139
+ templateContent = await readFile(templatePath, "utf-8");
140
+ } catch {
141
+ templateContent = `// Problem ${problem.id}: ${problem.title}
142
+ `;
143
+ }
124
144
  }
145
+ await writeFile(solutionPath, templateContent, "utf-8");
125
146
  const testcasesDir = join(problemDir, "testcases");
126
147
  for (let i = 0; i < problem.testCases.length; i++) {
127
148
  const testCase = problem.testCases[i];
@@ -3,8 +3,8 @@ import {
3
3
  ArchiveCommand,
4
4
  ArchiveView,
5
5
  archive_default
6
- } from "../chunk-457JZK3K.js";
7
- import "../chunk-Q5NECGFA.js";
6
+ } from "../chunk-HCUVCES6.js";
7
+ import "../chunk-AHE4QHJD.js";
8
8
  export {
9
9
  ArchiveCommand,
10
10
  ArchiveView,
@@ -4,38 +4,64 @@ import {
4
4
  CommandBuilder,
5
5
  CommandDef,
6
6
  __decorateClass,
7
+ findProjectRoot,
7
8
  getConfigMetadata,
8
9
  icons,
9
10
  logger
10
- } from "../chunk-Q5NECGFA.js";
11
+ } from "../chunk-AHE4QHJD.js";
11
12
 
12
13
  // src/commands/config.tsx
13
- import { StatusMessage, Select, TextInput, Alert } from "@inkjs/ui";
14
+ import { StatusMessage, Select, TextInput, Alert, Badge } from "@inkjs/ui";
14
15
  import { render, Text, Box } from "ink";
15
16
 
16
17
  // src/hooks/use-config.ts
17
- import { existsSync } from "fs";
18
- import { readFile, writeFile, unlink } from "fs/promises";
18
+ import { existsSync, mkdirSync } from "fs";
19
+ import { readFile, writeFile, unlink, rm } from "fs/promises";
19
20
  import { join } from "path";
20
21
  import { useEffect, useState } from "react";
22
+ import { parse, stringify } from "yaml";
21
23
  function getProjectConfigPath() {
22
- return join(process.cwd(), ".ps-cli.json");
24
+ const root = findProjectRoot();
25
+ if (!root) return null;
26
+ return join(root, ".ps-cli", "config.yaml");
23
27
  }
24
28
  async function readProjectConfig() {
25
29
  const configPath = getProjectConfigPath();
26
- if (!existsSync(configPath)) {
30
+ if (!configPath || !existsSync(configPath)) {
27
31
  return null;
28
32
  }
29
33
  try {
30
34
  const content = await readFile(configPath, "utf-8");
31
- return JSON.parse(content);
35
+ return parse(content);
32
36
  } catch {
33
37
  return null;
34
38
  }
35
39
  }
36
40
  async function writeProjectConfig(config) {
37
41
  const configPath = getProjectConfigPath();
38
- await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
42
+ if (!configPath) {
43
+ const root = process.cwd();
44
+ const psCliDir = join(root, ".ps-cli");
45
+ if (!existsSync(psCliDir)) {
46
+ mkdirSync(psCliDir, { recursive: true });
47
+ }
48
+ const newConfigPath = join(psCliDir, "config.yaml");
49
+ await writeFile(newConfigPath, stringify(config), "utf-8");
50
+ return;
51
+ }
52
+ await writeFile(configPath, stringify(config), "utf-8");
53
+ }
54
+ function setDeep(obj, path, value) {
55
+ const keys = path.split(".");
56
+ let current = obj;
57
+ for (let i = 0; i < keys.length - 1; i++) {
58
+ const key = keys[i];
59
+ if (!(key in current) || typeof current[key] !== "object") {
60
+ current[key] = {};
61
+ }
62
+ current = current[key];
63
+ }
64
+ current[keys[keys.length - 1]] = value;
39
65
  }
40
66
  function useConfig({
41
67
  configKey,
@@ -60,9 +86,16 @@ function useConfig({
60
86
  useEffect(() => {
61
87
  if (clear && !cleared) {
62
88
  void (async () => {
63
- const configPath = getProjectConfigPath();
64
- if (existsSync(configPath)) {
65
- await unlink(configPath);
89
+ const root = findProjectRoot();
90
+ if (root) {
91
+ const psCliDir = join(root, ".ps-cli");
92
+ if (existsSync(psCliDir)) {
93
+ await rm(psCliDir, { recursive: true, force: true });
94
+ }
95
+ const legacyPath = join(root, ".ps-cli.json");
96
+ if (existsSync(legacyPath)) {
97
+ await unlink(legacyPath);
98
+ }
66
99
  }
67
100
  setCleared(true);
68
101
  })();
@@ -79,7 +112,8 @@ function useConfig({
79
112
  console.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
80
113
  process.exit(1);
81
114
  }
82
- const property = item.property;
115
+ const path = item.path;
116
+ let finalValue = value;
83
117
  if (item.type === "boolean") {
84
118
  if (value !== "true" && value !== "false") {
85
119
  console.error(
@@ -87,7 +121,7 @@ function useConfig({
87
121
  );
88
122
  process.exit(1);
89
123
  }
90
- Object.assign(updatedConfig, { [property]: value === "true" });
124
+ finalValue = value === "true";
91
125
  } else if (item.type === "select" && item.suggestions) {
92
126
  if (!item.suggestions.includes(value)) {
93
127
  console.error(
@@ -96,10 +130,12 @@ function useConfig({
96
130
  );
97
131
  process.exit(1);
98
132
  }
99
- Object.assign(updatedConfig, { [property]: value });
100
- } else {
101
- Object.assign(updatedConfig, { [property]: value });
102
133
  }
134
+ setDeep(
135
+ updatedConfig,
136
+ path,
137
+ finalValue
138
+ );
103
139
  await writeProjectConfig(updatedConfig);
104
140
  setSaved(true);
105
141
  })();
@@ -117,25 +153,25 @@ function useConfig({
117
153
  import { jsx, jsxs } from "react/jsx-runtime";
118
154
  function getConfigHelp() {
119
155
  const metadata = getConfigMetadata();
120
- const keysHelp = metadata.map((m) => ` ${m.key.padEnd(23)} ${m.label}`).join("\n");
156
+ const keysHelp = metadata.map((m) => ` ${m.key.padEnd(25)} ${m.label}`).join("\n");
121
157
  return `
122
158
  \uC0AC\uC6A9\uBC95:
123
159
  $ ps config get [\uD0A4]
124
- $ ps config set [\uD0A4]
160
+ $ ps config set [\uD0A4] [\uAC12]
125
161
  $ ps config list
126
162
  $ ps config clear
127
163
 
128
164
  \uC124\uBA85:
129
- \uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uD30C\uC77C(.ps-cli.json)\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
130
- \uC124\uC815\uC740 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC758 .ps-cli.json \uD30C\uC77C\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.
165
+ \uD504\uB85C\uC81D\uD2B8 \uC124\uC815(.ps-cli/config.yaml)\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
166
+ \uC124\uC815\uC740 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC758 .ps-cli \uB514\uB809\uD1A0\uB9AC \uB0B4\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.
131
167
 
132
168
  \uBA85\uB839\uC5B4:
133
169
  get [\uD0A4] \uC124\uC815 \uAC12 \uC870\uD68C (\uD0A4 \uC5C6\uC73C\uBA74 \uB300\uD654\uD615 \uC120\uD0DD)
134
- set [\uD0A4] \uC124\uC815 \uAC12 \uC124\uC815 (\uD0A4 \uC5C6\uC73C\uBA74 \uB300\uD654\uD615 \uC120\uD0DD)
170
+ set [\uD0A4] [\uAC12] \uC124\uC815 \uAC12 \uC124\uC815 (\uC778\uC790 \uC5C6\uC73C\uBA74 \uB300\uD654\uD615 \uC120\uD0DD)
135
171
  list \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C
136
- clear .ps-cli.json \uD30C\uC77C \uC0AD\uC81C
172
+ clear .ps-cli \uD3F4\uB354 \uBC0F \uC124\uC815 \uC0AD\uC81C
137
173
 
138
- \uC124\uC815 \uD0A4:
174
+ \uC124\uC815 \uD0A4 \uC608\uC2DC:
139
175
  ${keysHelp}
140
176
 
141
177
  \uC635\uC158:
@@ -143,18 +179,14 @@ ${keysHelp}
143
179
 
144
180
  \uC608\uC81C:
145
181
  $ ps config get # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC870\uD68C
146
- $ ps config get default-language # default-language \uAC12 \uC870\uD68C
147
- $ ps config set # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC124\uC815
148
- $ ps config set editor cursor # editor\uB97C cursor\uB85C \uC124\uC815
182
+ $ ps config get general.default-language # \uAE30\uBCF8 \uC5B8\uC5B4 \uC124\uC815 \uC870\uD68C
183
+ $ ps config set editor.command cursor # \uC5D0\uB514\uD130\uB97C cursor\uB85C \uC124\uC815
149
184
  $ ps config list # \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C
150
- $ ps config clear # .ps-cli.json \uD30C\uC77C \uC0AD\uC81C
185
+ $ ps config clear # \uBAA8\uB4E0 \uC124\uC815 \uBC0F \uD15C\uD50C\uB9BF \uC0AD\uC81C
151
186
  `;
152
187
  }
153
188
  var configHelp = getConfigHelp();
154
- var CONFIG_KEYS = getConfigMetadata().map((m) => ({
155
- label: m.key,
156
- value: m.key
157
- }));
189
+ var METADATA = getConfigMetadata();
158
190
  function ConfigView({
159
191
  configKey,
160
192
  value,
@@ -176,41 +208,66 @@ function ConfigView({
176
208
  }
177
209
  if (clear) {
178
210
  if (!cleared) {
179
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StatusMessage, { variant: "info", children: ".ps-cli.json \uD30C\uC77C\uC744 \uC0AD\uC81C\uD558\uB294 \uC911..." }) });
211
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(StatusMessage, { variant: "info", children: ".ps-cli \uD3F4\uB354\uB97C \uC0AD\uC81C\uD558\uB294 \uC911..." }) });
180
212
  }
181
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Alert, { variant: "success", children: ".ps-cli.json \uD30C\uC77C\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4." }) });
213
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Alert, { variant: "success", children: ".ps-cli \uD3F4\uB354\uC640 \uBAA8\uB4E0 \uC124\uC815\uC774 \uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4." }) });
182
214
  }
183
215
  if (list) {
184
- const metadata = getConfigMetadata();
216
+ const groups = {};
217
+ METADATA.forEach((m) => {
218
+ const group = m.key.split(".")[0];
219
+ if (!groups[group]) groups[group] = [];
220
+ groups[group].push(m);
221
+ });
222
+ const getNestedValue = (obj, path) => {
223
+ if (!obj) return void 0;
224
+ return path.split(".").reduce((acc, part) => {
225
+ if (acc && typeof acc === "object" && part in acc) {
226
+ return acc[part];
227
+ }
228
+ return void 0;
229
+ }, obj);
230
+ };
185
231
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
186
232
  /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
187
233
  icons.config,
188
- " \uD604\uC7AC \uC124\uC815 (.ps-cli.json)"
234
+ " \uD604\uC7AC \uC124\uC815 (.ps-cli/config.yaml)"
189
235
  ] }) }),
190
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: metadata.map((m) => {
191
- const val = config ? config[m.property] : void 0;
192
- const displayValue = val !== void 0 ? String(val) : "(\uC124\uC815 \uC548 \uB428)";
193
- const isBool = m.type === "boolean";
194
- const valColor = isBool ? val === true ? "green" : "gray" : val ? "cyan" : "gray";
195
- return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
196
- /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
197
- m.key,
198
- ":"
199
- ] }),
200
- /* @__PURE__ */ jsx(Text, { children: " " }),
201
- /* @__PURE__ */ jsx(Text, { bold: true, color: valColor, children: displayValue })
202
- ] }, m.key);
203
- }) })
236
+ Object.entries(groups).map(([groupName, items]) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
237
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Badge, { color: "blue", children: groupName.toUpperCase() }) }),
238
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingLeft: 2, marginTop: 1, children: items.map((m) => {
239
+ const val = getNestedValue(config, m.path);
240
+ const displayValue = val !== void 0 ? String(val) : "(\uC124\uC815 \uC548 \uB428)";
241
+ const isBool = m.type === "boolean";
242
+ const valColor = isBool ? val === true ? "green" : "gray" : val ? "cyan" : "gray";
243
+ return /* @__PURE__ */ jsxs(Box, { marginBottom: 0, children: [
244
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
245
+ m.key.split(".").slice(1).join("."),
246
+ ":"
247
+ ] }),
248
+ /* @__PURE__ */ jsx(Text, { children: " " }),
249
+ /* @__PURE__ */ jsx(Text, { bold: true, color: valColor, children: displayValue })
250
+ ] }, m.key);
251
+ }) })
252
+ ] }, groupName))
204
253
  ] });
205
254
  }
206
255
  if (get && configKey) {
207
- const metadata = getConfigMetadata();
208
- const item = metadata.find((m) => m.key === configKey);
256
+ const item = METADATA.find((m) => m.key === configKey);
209
257
  if (!item) {
210
258
  logger.error(`\uC54C \uC218 \uC5C6\uB294 \uC124\uC815 \uD0A4: ${configKey}`);
211
259
  process.exit(1);
212
260
  }
213
- const val = config ? config[item.property] : void 0;
261
+ const getNestedValue = (obj, path) => {
262
+ if (!obj) return void 0;
263
+ return path.split(".").reduce((acc, part) => {
264
+ if (acc && typeof acc === "object" && part in acc) {
265
+ return acc[part];
266
+ }
267
+ return void 0;
268
+ }, obj);
269
+ };
270
+ const val = getNestedValue(config, item.path);
214
271
  const displayValue = val !== void 0 ? String(val) : "(\uC124\uC815 \uC548 \uB428)";
215
272
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { children: [
216
273
  /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
@@ -218,7 +275,7 @@ function ConfigView({
218
275
  ":"
219
276
  ] }),
220
277
  /* @__PURE__ */ jsx(Text, { children: " " }),
221
- /* @__PURE__ */ jsx(Text, { bold: true, color: val ? "cyan" : "gray", children: displayValue })
278
+ /* @__PURE__ */ jsx(Text, { bold: true, color: val !== void 0 ? "cyan" : "gray", children: displayValue })
222
279
  ] }) });
223
280
  }
224
281
  if (configKey && value !== void 0) {
@@ -227,7 +284,13 @@ function ConfigView({
227
284
  }
228
285
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
229
286
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "success", children: "\uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4" }) }),
230
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: value }) })
287
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, paddingLeft: 2, children: [
288
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
289
+ configKey,
290
+ " \u2192 "
291
+ ] }),
292
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: value })
293
+ ] })
231
294
  ] });
232
295
  }
233
296
  return null;
@@ -236,15 +299,11 @@ var ConfigCommand = class extends Command {
236
299
  async execute(args, flags) {
237
300
  const command = args[0];
238
301
  if (command === "clear") {
239
- await this.renderView(ConfigView, {
240
- clear: true
241
- });
302
+ await this.renderView(ConfigView, { clear: true });
242
303
  return;
243
304
  }
244
305
  if (command === "list" || flags.list) {
245
- await this.renderView(ConfigView, {
246
- list: true
247
- });
306
+ await this.renderView(ConfigView, { list: true });
248
307
  return;
249
308
  }
250
309
  if (command === "get") {
@@ -255,10 +314,9 @@ var ConfigCommand = class extends Command {
255
314
  get: true
256
315
  });
257
316
  } else {
258
- const selectedKey = await this.selectConfigKey();
317
+ const selectedKey = await this.selectConfigKeyInteractive();
259
318
  if (!selectedKey) {
260
319
  process.exit(0);
261
- return;
262
320
  }
263
321
  await this.renderView(ConfigView, {
264
322
  configKey: selectedKey,
@@ -269,27 +327,24 @@ var ConfigCommand = class extends Command {
269
327
  }
270
328
  if (command === "set") {
271
329
  const key = args[1];
272
- if (key) {
330
+ const value = args[2];
331
+ if (key && value !== void 0) {
332
+ await this.renderView(ConfigView, {
333
+ configKey: key,
334
+ value
335
+ });
336
+ } else if (key) {
273
337
  const inputValue = await this.inputConfigValue(key);
274
- if (!inputValue) {
275
- process.exit(0);
276
- return;
277
- }
338
+ if (inputValue === null) process.exit(0);
278
339
  await this.renderView(ConfigView, {
279
340
  configKey: key,
280
341
  value: inputValue
281
342
  });
282
343
  } else {
283
- const selectedKey = await this.selectConfigKey();
284
- if (!selectedKey) {
285
- process.exit(0);
286
- return;
287
- }
344
+ const selectedKey = await this.selectConfigKeyInteractive();
345
+ if (!selectedKey) process.exit(0);
288
346
  const inputValue = await this.inputConfigValue(selectedKey);
289
- if (!inputValue) {
290
- process.exit(0);
291
- return;
292
- }
347
+ if (inputValue === null) process.exit(0);
293
348
  await this.renderView(ConfigView, {
294
349
  configKey: selectedKey,
295
350
  value: inputValue
@@ -301,29 +356,62 @@ var ConfigCommand = class extends Command {
301
356
  logger.error("\uBA85\uB839\uC5B4\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
302
357
  console.log("\uB3C4\uC6C0\uB9D0: ps config --help");
303
358
  process.exit(1);
304
- return;
305
359
  }
306
360
  logger.error(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839\uC5B4: ${command}`);
307
361
  console.log("\uB3C4\uC6C0\uB9D0: ps config --help");
308
362
  process.exit(1);
309
363
  }
310
- // 설정 키 선택: private 메서드
311
- async selectConfigKey() {
364
+ async selectConfigKeyInteractive() {
365
+ const groups = Array.from(
366
+ new Set(METADATA.map((m) => m.key.split(".")[0]))
367
+ );
368
+ const selectedGroup = await new Promise((resolve) => {
369
+ const { unmount } = render(
370
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
371
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
372
+ icons.config,
373
+ " \uC124\uC815 \uADF8\uB8F9 \uC120\uD0DD"
374
+ ] }) }),
375
+ /* @__PURE__ */ jsx(
376
+ Select,
377
+ {
378
+ options: groups.map((g) => ({ label: g.toUpperCase(), value: g })),
379
+ onChange: (val) => {
380
+ unmount();
381
+ resolve(val);
382
+ }
383
+ }
384
+ )
385
+ ] })
386
+ );
387
+ });
388
+ if (!selectedGroup) return null;
389
+ const groupItems = METADATA.filter(
390
+ (m) => m.key.startsWith(selectedGroup + ".")
391
+ );
312
392
  return new Promise((resolve) => {
313
393
  const { unmount } = render(
314
- /* @__PURE__ */ jsx(
315
- this.ConfigKeySelector,
316
- {
317
- onSelect: (key) => {
318
- unmount();
319
- resolve(key);
394
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
395
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
396
+ icons.config,
397
+ " [",
398
+ selectedGroup.toUpperCase(),
399
+ "] \uC124\uC815 \uD0A4 \uC120\uD0DD"
400
+ ] }) }),
401
+ /* @__PURE__ */ jsx(
402
+ Select,
403
+ {
404
+ options: groupItems.map((m) => ({ label: m.label, value: m.key })),
405
+ onChange: (val) => {
406
+ unmount();
407
+ resolve(val);
408
+ }
320
409
  }
321
- }
322
- )
410
+ )
411
+ ] })
323
412
  );
324
413
  });
325
414
  }
326
- // 설정 값 입력: private 메서드
327
415
  async inputConfigValue(configKey) {
328
416
  return new Promise((resolve) => {
329
417
  const { unmount } = render(
@@ -340,36 +428,17 @@ var ConfigCommand = class extends Command {
340
428
  );
341
429
  });
342
430
  }
343
- // 설정 키 선택 컴포넌트: 클래스 내부에 정의
344
- ConfigKeySelector = ({
345
- onSelect
346
- }) => {
347
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
348
- /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
349
- icons.config,
350
- " \uC124\uC815 \uAD00\uB9AC"
351
- ] }) }),
352
- /* @__PURE__ */ jsx(Alert, { variant: "info", children: "\uC124\uC815 \uD0A4\uB97C \uC120\uD0DD\uD558\uC138\uC694" }),
353
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
354
- Select,
355
- {
356
- options: CONFIG_KEYS,
357
- onChange: (value) => {
358
- onSelect(value);
359
- }
360
- }
361
- ) })
362
- ] });
363
- };
364
- // 설정 값 입력 컴포넌트: 클래스 내부에 정의
365
431
  ConfigValueInput = ({
366
432
  configKey,
367
433
  onSubmit
368
434
  }) => {
369
- const metadata = getConfigMetadata();
370
- const item = metadata.find((m) => m.key === configKey);
435
+ const item = METADATA.find((m) => m.key === configKey);
371
436
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
372
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "info", children: "\uAC12\uC744 \uC785\uB825\uD558\uC138\uC694" }) }),
437
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Alert, { variant: "info", children: [
438
+ "\uAC12\uC744 \uC785\uB825\uD558\uC138\uC694 [",
439
+ configKey,
440
+ "]"
441
+ ] }) }),
373
442
  item && /* @__PURE__ */ jsx(Box, { marginTop: 1, marginBottom: 0, children: /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: item.description }) }),
374
443
  /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(
375
444
  TextInput,
@@ -387,16 +456,15 @@ var ConfigCommand = class extends Command {
387
456
  ConfigCommand = __decorateClass([
388
457
  CommandDef({
389
458
  name: "config",
390
- description: `\uD504\uB85C\uC81D\uD2B8 \uC124\uC815 \uD30C\uC77C(.ps-cli.json)\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
391
- \uC124\uC815\uC740 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC758 .ps-cli.json \uD30C\uC77C\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.`,
459
+ description: `\uD504\uB85C\uC81D\uD2B8 \uC124\uC815(.ps-cli/config.yaml)\uC744 \uAD00\uB9AC\uD569\uB2C8\uB2E4.
460
+ \uC124\uC815\uC740 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uC758 .ps-cli \uB514\uB809\uD1A0\uB9AC \uB0B4\uC5D0 \uC800\uC7A5\uB429\uB2C8\uB2E4.`,
392
461
  autoDetectProblemId: false,
393
462
  examples: [
394
463
  "config get # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC870\uD68C",
395
- "config get default-language # default-language \uAC12 \uC870\uD68C",
396
- "config set # \uB300\uD654\uD615\uC73C\uB85C \uD0A4 \uC120\uD0DD \uD6C4 \uAC12 \uC124\uC815",
397
- "config set editor cursor # editor\uB97C cursor\uB85C \uC124\uC815",
464
+ "config get general.default-language # \uAE30\uBCF8 \uC5B8\uC5B4 \uC124\uC815 \uC870\uD68C",
465
+ "config set editor.command cursor # \uC5D0\uB514\uD130\uB97C cursor\uB85C \uC124\uC815",
398
466
  "config list # \uBAA8\uB4E0 \uC124\uC815 \uC870\uD68C",
399
- "config clear # .ps-cli.json \uD30C\uC77C \uC0AD\uC81C"
467
+ "config clear # \uBAA8\uB4E0 \uC124\uC815 \uBC0F \uD15C\uD50C\uB9BF \uC0AD\uC81C"
400
468
  ]
401
469
  })
402
470
  ], ConfigCommand);
@@ -3,9 +3,9 @@ import {
3
3
  FetchCommand,
4
4
  FetchView,
5
5
  fetch_default
6
- } from "../chunk-M4LNYKJF.js";
7
- import "../chunk-YCFY6UCA.js";
8
- import "../chunk-Q5NECGFA.js";
6
+ } from "../chunk-XUDGIZ2U.js";
7
+ import "../chunk-S7IL7OXF.js";
8
+ import "../chunk-AHE4QHJD.js";
9
9
  export {
10
10
  FetchCommand,
11
11
  FetchView,