@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.
@@ -0,0 +1,438 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getSupportedLanguages
4
+ } from "../chunk-TQXMB7XV.js";
5
+ import {
6
+ getAutoOpenEditor,
7
+ getDefaultLanguage,
8
+ getEditor,
9
+ getProblemDir,
10
+ getSolvedAcHandle
11
+ } from "../chunk-CIG2LEJC.js";
12
+ import "../chunk-FYS2JH42.js";
13
+
14
+ // src/commands/init.tsx
15
+ import { useState, useEffect } from "react";
16
+ import { render, Text, Box } from "ink";
17
+ import { mkdir, readFile, writeFile, access } from "fs/promises";
18
+ import { join } from "path";
19
+ import {
20
+ Select,
21
+ TextInput,
22
+ StatusMessage,
23
+ Alert,
24
+ ConfirmInput
25
+ } from "@inkjs/ui";
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ function InitCommand({ onComplete }) {
28
+ const [currentStep, setCurrentStep] = useState("problem-dir");
29
+ const [completedSteps, setCompletedSteps] = useState([]);
30
+ const [confirmExit, setConfirmExit] = useState(false);
31
+ const [initialized, setInitialized] = useState(false);
32
+ const [problemDir, setProblemDirValue] = useState(getProblemDir());
33
+ const [language, setLanguage] = useState(getDefaultLanguage());
34
+ const [editor, setEditorValue] = useState(getEditor());
35
+ const [autoOpen, setAutoOpen] = useState(getAutoOpenEditor());
36
+ const [handle, setHandle] = useState(getSolvedAcHandle() || "");
37
+ const [handleInputMode, setHandleInputMode] = useState(false);
38
+ const [created, setCreated] = useState([]);
39
+ const [cancelled, setCancelled] = useState(false);
40
+ useEffect(() => {
41
+ const handleSigInt = () => {
42
+ if (confirmExit) {
43
+ setCancelled(true);
44
+ setCurrentStep("cancelled");
45
+ setTimeout(() => {
46
+ onComplete();
47
+ }, 500);
48
+ return;
49
+ }
50
+ setConfirmExit(true);
51
+ };
52
+ process.on("SIGINT", handleSigInt);
53
+ return () => {
54
+ process.off("SIGINT", handleSigInt);
55
+ };
56
+ }, [confirmExit, onComplete]);
57
+ useEffect(() => {
58
+ async function loadProjectConfig() {
59
+ try {
60
+ const cwd = process.cwd();
61
+ const projectConfigPath = join(cwd, ".ps-cli.json");
62
+ await access(projectConfigPath);
63
+ const configContent = await readFile(projectConfigPath, "utf-8");
64
+ const projectConfig = JSON.parse(configContent);
65
+ if (projectConfig.problemDir)
66
+ setProblemDirValue(projectConfig.problemDir);
67
+ if (projectConfig.defaultLanguage)
68
+ setLanguage(projectConfig.defaultLanguage);
69
+ if (projectConfig.editor) setEditorValue(projectConfig.editor);
70
+ if (projectConfig.autoOpenEditor !== void 0)
71
+ setAutoOpen(projectConfig.autoOpenEditor);
72
+ if (projectConfig.solvedAcHandle)
73
+ setHandle(projectConfig.solvedAcHandle);
74
+ } catch (err) {
75
+ } finally {
76
+ setInitialized(true);
77
+ }
78
+ }
79
+ loadProjectConfig();
80
+ }, []);
81
+ function getStepLabel(step) {
82
+ switch (step) {
83
+ case "problem-dir":
84
+ return "\uBB38\uC81C \uB514\uB809\uD1A0\uB9AC \uC124\uC815";
85
+ case "language":
86
+ return "\uAE30\uBCF8 \uC5B8\uC5B4 \uC124\uC815";
87
+ case "editor":
88
+ return "\uC5D0\uB514\uD130 \uC124\uC815";
89
+ case "auto-open":
90
+ return "\uC790\uB3D9 \uC5D0\uB514\uD130 \uC5F4\uAE30";
91
+ case "handle":
92
+ return "Solved.ac \uD578\uB4E4 (\uC120\uD0DD)";
93
+ default:
94
+ return "";
95
+ }
96
+ }
97
+ function moveToNextStep(selectedValue, stepLabel) {
98
+ setCompletedSteps((prev) => [
99
+ ...prev,
100
+ { label: stepLabel, value: selectedValue }
101
+ ]);
102
+ const stepOrder = [
103
+ "problem-dir",
104
+ "language",
105
+ "editor",
106
+ "auto-open",
107
+ "handle",
108
+ "done"
109
+ ];
110
+ const currentIndex = stepOrder.indexOf(currentStep);
111
+ if (currentIndex < stepOrder.length - 1) {
112
+ const nextStep = stepOrder[currentIndex + 1];
113
+ setCurrentStep(nextStep);
114
+ if (nextStep === "done") {
115
+ void executeInit();
116
+ }
117
+ }
118
+ }
119
+ function getStepValue(step) {
120
+ switch (step) {
121
+ case "problem-dir":
122
+ return problemDir === "." ? "\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8" : problemDir;
123
+ case "language":
124
+ return language;
125
+ case "editor":
126
+ return editor;
127
+ case "auto-open":
128
+ return autoOpen ? "\uC608" : "\uC544\uB2C8\uC624";
129
+ case "handle":
130
+ return handle || "(\uC2A4\uD0B5)";
131
+ default:
132
+ return "";
133
+ }
134
+ }
135
+ async function executeInit() {
136
+ try {
137
+ const cwd = process.cwd();
138
+ const projectConfigPath = join(cwd, ".ps-cli.json");
139
+ const projectConfig = {
140
+ problemDir,
141
+ defaultLanguage: language,
142
+ editor,
143
+ autoOpenEditor: autoOpen,
144
+ solvedAcHandle: handle || void 0
145
+ };
146
+ await writeFile(
147
+ projectConfigPath,
148
+ JSON.stringify(projectConfig, null, 2),
149
+ "utf-8"
150
+ );
151
+ setCreated((prev) => [...prev, ".ps-cli.json"]);
152
+ if (problemDir !== "." && problemDir !== "") {
153
+ const problemDirPath = join(cwd, problemDir);
154
+ try {
155
+ await mkdir(problemDirPath, { recursive: true });
156
+ setCreated((prev) => [...prev, `${problemDir}/`]);
157
+ } catch (err) {
158
+ const error = err;
159
+ if (error.code !== "EEXIST") {
160
+ throw err;
161
+ }
162
+ }
163
+ const gitignorePath = join(cwd, ".gitignore");
164
+ const gitignorePattern = `${problemDir}/`;
165
+ try {
166
+ const gitignoreContent = await readFile(gitignorePath, "utf-8");
167
+ if (!gitignoreContent.includes(gitignorePattern)) {
168
+ const updatedContent = gitignoreContent.trim() + (gitignoreContent.trim() ? "\n" : "") + `
169
+ # ps-cli \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC
170
+ ${gitignorePattern}
171
+ `;
172
+ await writeFile(gitignorePath, updatedContent, "utf-8");
173
+ setCreated((prev) => [...prev, ".gitignore \uC5C5\uB370\uC774\uD2B8"]);
174
+ }
175
+ } catch (err) {
176
+ const error = err;
177
+ if (error.code === "ENOENT") {
178
+ await writeFile(
179
+ gitignorePath,
180
+ `# ps-cli \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC
181
+ ${gitignorePattern}
182
+ `,
183
+ "utf-8"
184
+ );
185
+ setCreated((prev) => [...prev, ".gitignore \uC0DD\uC131"]);
186
+ } else {
187
+ console.warn(".gitignore \uC5C5\uB370\uC774\uD2B8 \uC2E4\uD328:", error.message);
188
+ }
189
+ }
190
+ }
191
+ setTimeout(() => {
192
+ onComplete();
193
+ }, 3e3);
194
+ } catch (err) {
195
+ const error = err;
196
+ console.error("\uCD08\uAE30\uD654 \uC911 \uC624\uB958 \uBC1C\uC0DD:", error.message);
197
+ setCancelled(true);
198
+ setCurrentStep("cancelled");
199
+ setTimeout(() => {
200
+ onComplete();
201
+ }, 2e3);
202
+ }
203
+ }
204
+ function renderQuestionCard(title, children) {
205
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
206
+ /* @__PURE__ */ jsx(Alert, { variant: "info", children: title }),
207
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children })
208
+ ] });
209
+ }
210
+ function renderStepContent() {
211
+ if (cancelled || currentStep === "cancelled") {
212
+ return /* @__PURE__ */ jsx(Alert, { variant: "error", children: "\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4." });
213
+ }
214
+ if (confirmExit) {
215
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
216
+ /* @__PURE__ */ jsx(Alert, { variant: "error", children: "\uC815\uB9D0 \uC885\uB8CC\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }),
217
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
218
+ ConfirmInput,
219
+ {
220
+ onConfirm: () => {
221
+ setCancelled(true);
222
+ setCurrentStep("cancelled");
223
+ setConfirmExit(false);
224
+ setTimeout(() => {
225
+ onComplete();
226
+ }, 500);
227
+ },
228
+ onCancel: () => {
229
+ setConfirmExit(false);
230
+ }
231
+ }
232
+ ) })
233
+ ] });
234
+ }
235
+ switch (currentStep) {
236
+ case "problem-dir": {
237
+ const options = [
238
+ { label: "problems", value: "problems" },
239
+ { label: ". (\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8)", value: "." }
240
+ ];
241
+ return renderQuestionCard(
242
+ getStepLabel(currentStep),
243
+ /* @__PURE__ */ jsx(
244
+ Select,
245
+ {
246
+ options,
247
+ onChange: (value) => {
248
+ setProblemDirValue(value);
249
+ const displayValue = value === "." ? "\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8" : value;
250
+ moveToNextStep(displayValue, getStepLabel(currentStep));
251
+ }
252
+ }
253
+ )
254
+ );
255
+ }
256
+ case "language": {
257
+ const supportedLanguages = getSupportedLanguages();
258
+ const options = supportedLanguages.map((lang) => ({
259
+ label: lang,
260
+ value: lang
261
+ }));
262
+ return renderQuestionCard(
263
+ getStepLabel(currentStep),
264
+ /* @__PURE__ */ jsx(
265
+ Select,
266
+ {
267
+ options,
268
+ onChange: (value) => {
269
+ setLanguage(value);
270
+ moveToNextStep(value, getStepLabel(currentStep));
271
+ }
272
+ }
273
+ )
274
+ );
275
+ }
276
+ case "editor": {
277
+ const options = [
278
+ { label: "code", value: "code" },
279
+ { label: "cursor", value: "cursor" },
280
+ { label: "vim", value: "vim" },
281
+ { label: "nano", value: "nano" }
282
+ ];
283
+ return renderQuestionCard(
284
+ getStepLabel(currentStep),
285
+ /* @__PURE__ */ jsx(
286
+ Select,
287
+ {
288
+ options,
289
+ onChange: (value) => {
290
+ setEditorValue(value);
291
+ moveToNextStep(value, getStepLabel(currentStep));
292
+ }
293
+ }
294
+ )
295
+ );
296
+ }
297
+ case "auto-open": {
298
+ const options = [
299
+ { label: "\uC608", value: "true" },
300
+ { label: "\uC544\uB2C8\uC624", value: "false" }
301
+ ];
302
+ return renderQuestionCard(
303
+ getStepLabel(currentStep),
304
+ /* @__PURE__ */ jsx(
305
+ Select,
306
+ {
307
+ options,
308
+ onChange: (value) => {
309
+ setAutoOpen(value === "true");
310
+ moveToNextStep(
311
+ value === "true" ? "\uC608" : "\uC544\uB2C8\uC624",
312
+ getStepLabel(currentStep)
313
+ );
314
+ }
315
+ }
316
+ )
317
+ );
318
+ }
319
+ case "handle": {
320
+ if (handleInputMode) {
321
+ return renderQuestionCard(
322
+ getStepLabel(currentStep),
323
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
324
+ TextInput,
325
+ {
326
+ placeholder: "\uD578\uB4E4 \uC785\uB825",
327
+ onSubmit: (value) => {
328
+ setHandle(value);
329
+ setHandleInputMode(false);
330
+ moveToNextStep(value || "(\uC2A4\uD0B5)", getStepLabel(currentStep));
331
+ }
332
+ }
333
+ ) })
334
+ );
335
+ }
336
+ const options = [
337
+ { label: "\uC124\uC815", value: "set" },
338
+ { label: "\uC2A4\uD0B5", value: "skip" }
339
+ ];
340
+ return renderQuestionCard(
341
+ getStepLabel(currentStep),
342
+ /* @__PURE__ */ jsx(
343
+ Select,
344
+ {
345
+ options,
346
+ onChange: (value) => {
347
+ if (value === "skip") {
348
+ setHandle("");
349
+ moveToNextStep("(\uC2A4\uD0B5)", getStepLabel(currentStep));
350
+ } else {
351
+ setHandleInputMode(true);
352
+ }
353
+ }
354
+ }
355
+ )
356
+ );
357
+ }
358
+ case "done": {
359
+ const createdItemsText = created.length > 0 ? `
360
+ \uC0DD\uC131\uB41C \uD56D\uBAA9:
361
+ ${created.map((item) => `\u2022 ${item}`).join("\n")}` : "";
362
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
363
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Alert, { variant: "success", children: [
364
+ "\uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 \uC644\uB8CC",
365
+ createdItemsText
366
+ ] }) }),
367
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
368
+ "\uC774\uC81C",
369
+ " ",
370
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "ps help" }),
371
+ " ",
372
+ "\uBA85\uB839\uC5B4\uB97C \uD1B5\uD574 \uB354 \uC790\uC138\uD55C \uC815\uBCF4\uB97C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
373
+ ] }) })
374
+ ] });
375
+ }
376
+ default:
377
+ return null;
378
+ }
379
+ }
380
+ if (!initialized) {
381
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "\uB85C\uB529 \uC911..." }) });
382
+ }
383
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
384
+ /* @__PURE__ */ jsx(Box, { marginBottom: completedSteps.length > 0 ? 1 : 0, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\u{1F680} ps-cli \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654" }) }),
385
+ completedSteps.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: completedSteps.map((step, idx) => /* @__PURE__ */ jsxs(StatusMessage, { variant: "success", children: [
386
+ step.label,
387
+ ": ",
388
+ step.value
389
+ ] }, idx)) }),
390
+ renderStepContent()
391
+ ] });
392
+ }
393
+ async function initCommand() {
394
+ return new Promise((resolve) => {
395
+ const { unmount } = render(
396
+ /* @__PURE__ */ jsx(
397
+ InitCommand,
398
+ {
399
+ onComplete: () => {
400
+ unmount();
401
+ resolve();
402
+ }
403
+ }
404
+ )
405
+ );
406
+ });
407
+ }
408
+ var initHelp = `
409
+ \uC0AC\uC6A9\uBC95:
410
+ $ ps init
411
+
412
+ \uC124\uBA85:
413
+ \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uB97C ps-cli \uD504\uB85C\uC81D\uD2B8\uB85C \uB300\uD654\uD615\uC73C\uB85C \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.
414
+ - \uB2E8\uACC4\uBCC4\uB85C \uC124\uC815\uC744 \uBB3C\uC5B4\uBD05\uB2C8\uB2E4
415
+ - \uBB38\uC81C \uB514\uB809\uD1A0\uB9AC, \uAE30\uBCF8 \uC5B8\uC5B4, \uC5D0\uB514\uD130 \uB4F1\uC744 \uC124\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4
416
+
417
+ \uC608\uC81C:
418
+ $ ps init
419
+ `;
420
+ async function initExecute(args, flags) {
421
+ if (flags.help) {
422
+ console.log(initHelp.trim());
423
+ process.exit(0);
424
+ return;
425
+ }
426
+ await initCommand();
427
+ }
428
+ var initCommandDef = {
429
+ name: "init",
430
+ help: initHelp,
431
+ execute: initExecute
432
+ };
433
+ var init_default = initCommandDef;
434
+ export {
435
+ init_default as default,
436
+ initExecute,
437
+ initHelp
438
+ };
@@ -4,23 +4,24 @@ import {
4
4
  } from "../chunk-EIFFWFLS.js";
5
5
  import {
6
6
  detectProblemIdFromPath,
7
+ getProblemDirPath,
7
8
  getProblemId
8
- } from "../chunk-OOTPZD7O.js";
9
+ } from "../chunk-BM3ZMA4K.js";
9
10
  import {
10
11
  detectLanguageFromFile,
11
12
  getSupportedLanguages,
12
13
  getSupportedLanguagesString
13
14
  } from "../chunk-TQXMB7XV.js";
14
- import {
15
- LoadingSpinner
16
- } from "../chunk-IJLJBKLK.js";
15
+ import "../chunk-CIG2LEJC.js";
17
16
  import "../chunk-FYS2JH42.js";
18
17
 
19
18
  // src/commands/run.tsx
20
19
  import { useEffect, useState } from "react";
21
20
  import { render, Box, Text } from "ink";
21
+ import { StatusMessage, Alert } from "@inkjs/ui";
22
22
  import { readdir } from "fs/promises";
23
23
  import { join } from "path";
24
+ import { Spinner } from "@inkjs/ui";
24
25
  import { jsx, jsxs } from "react/jsx-runtime";
25
26
  function RunCommand({
26
27
  problemDir,
@@ -55,16 +56,13 @@ function RunCommand({
55
56
  });
56
57
  }, [problemDir, language, inputFile, onComplete]);
57
58
  if (status === "loading") {
58
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
59
- /* @__PURE__ */ jsx(Text, { children: "\uCF54\uB4DC \uC2E4\uD589 \uC911..." }),
60
- /* @__PURE__ */ jsx(LoadingSpinner, {})
61
- ] });
59
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: "\uCF54\uB4DC \uC2E4\uD589 \uC911..." }) });
62
60
  }
63
61
  if (status === "error") {
64
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
65
- /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 \uC2E4\uD589 \uC2E4\uD328" }),
66
- error && /* @__PURE__ */ jsx(Text, { color: "gray", children: error })
67
- ] });
62
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
63
+ "\uC2E4\uD589 \uC2E4\uD328",
64
+ error ? `: ${error}` : ""
65
+ ] }) });
68
66
  }
69
67
  if (result) {
70
68
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
@@ -78,11 +76,11 @@ function RunCommand({
78
76
  ] })
79
77
  ] }),
80
78
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
81
- result.timedOut ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u23F1 \uC2E4\uD589 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4." }) : result.exitCode !== 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
82
- "\u2717 \uD504\uB85C\uADF8\uB7A8\uC774 \uBE44\uC815\uC0C1 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (exit code: ",
79
+ result.timedOut ? /* @__PURE__ */ jsx(StatusMessage, { variant: "warning", children: "\uC2E4\uD589 \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4." }) : result.exitCode !== 0 ? /* @__PURE__ */ jsxs(StatusMessage, { variant: "error", children: [
80
+ "\uD504\uB85C\uADF8\uB7A8\uC774 \uBE44\uC815\uC0C1 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (exit code: ",
83
81
  result.exitCode,
84
82
  ")"
85
- ] }) : /* @__PURE__ */ jsx(Text, { color: "green", children: "\u2713 \uC2E4\uD589 \uC644\uB8CC" }),
83
+ ] }) : /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: "\uC2E4\uD589 \uC644\uB8CC" }),
86
84
  result.stdout && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
87
85
  /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\uCD9C\uB825:" }),
88
86
  /* @__PURE__ */ jsx(Text, { children: result.stdout })
@@ -111,7 +109,7 @@ async function findInputFile(problemDir) {
111
109
  }
112
110
  async function runCommand(problemId, language, inputFile) {
113
111
  const currentPathProblemId = detectProblemIdFromPath(process.cwd());
114
- const problemDir = problemId && currentPathProblemId !== problemId ? join(process.cwd(), "problems", String(problemId)) : process.cwd();
112
+ const problemDir = problemId && currentPathProblemId !== problemId ? getProblemDirPath(problemId) : process.cwd();
115
113
  const inputPath = inputFile ? join(problemDir, inputFile) : await findInputFile(problemDir);
116
114
  const files = await readdir(problemDir);
117
115
  const solutionFile = files.find((f) => f.startsWith("solution."));
@@ -7,15 +7,14 @@ import {
7
7
  } from "../chunk-2E4VSP6O.js";
8
8
  import {
9
9
  getSolvedAcHandle
10
- } from "../chunk-KFQFQJYT.js";
11
- import {
12
- LoadingSpinner
13
- } from "../chunk-IJLJBKLK.js";
10
+ } from "../chunk-CIG2LEJC.js";
14
11
  import "../chunk-FYS2JH42.js";
15
12
 
16
13
  // src/commands/stats.tsx
17
14
  import { useEffect, useState } from "react";
18
15
  import { render, Box, Text } from "ink";
16
+ import { Alert } from "@inkjs/ui";
17
+ import { Spinner } from "@inkjs/ui";
19
18
  import gradient from "gradient-string";
20
19
  import { jsx, jsxs } from "react/jsx-runtime";
21
20
  function StatsCommand({ handle, onComplete }) {
@@ -40,11 +39,11 @@ function StatsCommand({ handle, onComplete }) {
40
39
  });
41
40
  }, [handle, onComplete]);
42
41
  if (status === "loading") {
43
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(LoadingSpinner, { message: "\uD1B5\uACC4\uB97C \uBD88\uB7EC\uC624\uB294 \uC911..." }) });
42
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: "\uD1B5\uACC4\uB97C \uBD88\uB7EC\uC624\uB294 \uC911..." }) });
44
43
  }
45
44
  if (status === "error") {
46
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
47
- "\u2717 \uD1B5\uACC4\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ",
45
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
46
+ "\uD1B5\uACC4\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ",
48
47
  error
49
48
  ] }) });
50
49
  }
@@ -60,11 +59,6 @@ function StatsCommand({ handle, onComplete }) {
60
59
  "\u2728 ",
61
60
  user.handle
62
61
  ] }) }),
63
- /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
64
- tierDisplay,
65
- " ",
66
- /* @__PURE__ */ jsx(Text, { bold: true, children: user.rating.toLocaleString() })
67
- ] }) }),
68
62
  /* @__PURE__ */ jsx(
69
63
  Box,
70
64
  {
@@ -73,6 +67,11 @@ function StatsCommand({ handle, onComplete }) {
73
67
  borderColor: "gray",
74
68
  alignSelf: "flex-start",
75
69
  children: /* @__PURE__ */ jsxs(Box, { paddingX: 1, paddingY: 0, flexDirection: "column", children: [
70
+ /* @__PURE__ */ jsxs(Text, { children: [
71
+ tierDisplay,
72
+ " ",
73
+ /* @__PURE__ */ jsx(Text, { bold: true, children: user.rating.toLocaleString() })
74
+ ] }),
76
75
  /* @__PURE__ */ jsxs(Text, { children: [
77
76
  "\uD574\uACB0\uD55C \uBB38\uC81C:",
78
77
  " ",
@@ -1,12 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- getBojSessionCookie,
4
- getCodeOpen
5
- } from "../chunk-KFQFQJYT.js";
6
2
  import {
7
3
  detectProblemIdFromPath,
4
+ getProblemDirPath,
8
5
  getProblemId
9
- } from "../chunk-OOTPZD7O.js";
6
+ } from "../chunk-BM3ZMA4K.js";
10
7
  import {
11
8
  detectLanguageFromFile,
12
9
  getLanguageConfig,
@@ -14,13 +11,15 @@ import {
14
11
  getSupportedLanguagesString
15
12
  } from "../chunk-TQXMB7XV.js";
16
13
  import {
17
- LoadingSpinner
18
- } from "../chunk-IJLJBKLK.js";
14
+ getBojSessionCookie,
15
+ getCodeOpen
16
+ } from "../chunk-CIG2LEJC.js";
19
17
  import "../chunk-FYS2JH42.js";
20
18
 
21
19
  // src/commands/submit.tsx
22
20
  import { useState, useEffect } from "react";
23
21
  import { render, Text, Box } from "ink";
22
+ import { Badge, StatusMessage, Alert } from "@inkjs/ui";
24
23
  import { readdir } from "fs/promises";
25
24
  import { join } from "path";
26
25
  import { readFile } from "fs/promises";
@@ -307,6 +306,7 @@ async function submitSolution({
307
306
  }
308
307
 
309
308
  // src/commands/submit.tsx
309
+ import { Spinner } from "@inkjs/ui";
310
310
  import { jsx, jsxs } from "react/jsx-runtime";
311
311
  function SubmitCommand({
312
312
  problemId,
@@ -354,46 +354,28 @@ function SubmitCommand({
354
354
  submit();
355
355
  }, [problemId, language, sourcePath, dryRun, onComplete]);
356
356
  if (status === "loading") {
357
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(LoadingSpinner, { message }) });
357
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: message }) });
358
358
  }
359
359
  if (status === "error") {
360
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
361
- "\u2717 \uC81C\uCD9C \uC2E4\uD328: ",
360
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
361
+ "\uC81C\uCD9C \uC2E4\uD328: ",
362
362
  error
363
363
  ] }) });
364
364
  }
365
365
  if (result) {
366
- const statusColor = result.status === "AC" ? "green" : result.status === "WA" || result.status === "CE" || result.status === "RE" ? "red" : result.status === "TLE" || result.status === "MLE" ? "yellow" : "cyan";
366
+ const badgeColor = result.status === "AC" ? "green" : result.status === "WA" || result.status === "CE" || result.status === "RE" ? "red" : result.status === "TLE" || result.status === "MLE" ? "yellow" : "blue";
367
+ const statusVariant = result.status === "AC" ? "success" : result.status === "WA" || result.status === "CE" || result.status === "RE" ? "error" : result.status === "TLE" || result.status === "MLE" ? "warning" : "info";
368
+ const resultDetails = [
369
+ `\uBB38\uC81C: ${result.problemId}`,
370
+ `\uC5B8\uC5B4: ${result.language}`,
371
+ result.time !== null && result.time !== void 0 ? `\uC2DC\uAC04: ${result.time}ms` : null,
372
+ result.memory !== null && result.memory !== void 0 ? `\uBA54\uBAA8\uB9AC: ${result.memory}KB` : null
373
+ ].filter(Boolean).join(" | ");
367
374
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
368
375
  /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\uC81C\uCD9C \uACB0\uACFC" }) }),
369
376
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
370
- /* @__PURE__ */ jsxs(Text, { children: [
371
- "\uBB38\uC81C: ",
372
- /* @__PURE__ */ jsx(Text, { bold: true, children: result.problemId })
373
- ] }),
374
- /* @__PURE__ */ jsxs(Text, { children: [
375
- "\uC5B8\uC5B4: ",
376
- /* @__PURE__ */ jsx(Text, { bold: true, children: result.language })
377
- ] }),
378
- /* @__PURE__ */ jsxs(Text, { children: [
379
- "\uC0C1\uD0DC:",
380
- " ",
381
- /* @__PURE__ */ jsx(Text, { color: statusColor, bold: true, children: result.status })
382
- ] }),
383
- result.time !== null && result.time !== void 0 && /* @__PURE__ */ jsxs(Text, { children: [
384
- "\uC2DC\uAC04: ",
385
- /* @__PURE__ */ jsxs(Text, { bold: true, children: [
386
- result.time,
387
- "ms"
388
- ] })
389
- ] }),
390
- result.memory !== null && result.memory !== void 0 && /* @__PURE__ */ jsxs(Text, { children: [
391
- "\uBA54\uBAA8\uB9AC: ",
392
- /* @__PURE__ */ jsxs(Text, { bold: true, children: [
393
- result.memory,
394
- "KB"
395
- ] })
396
- ] }),
377
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Badge, { color: badgeColor, children: result.status }) }),
378
+ /* @__PURE__ */ jsx(StatusMessage, { variant: statusVariant, children: resultDetails }),
397
379
  result.message && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: result.message }) })
398
380
  ] })
399
381
  ] });
@@ -410,7 +392,7 @@ async function detectSolutionFile(problemDir) {
410
392
  }
411
393
  async function submitCommand(problemId, language, dryRun = false) {
412
394
  const currentPathProblemId = detectProblemIdFromPath(process.cwd());
413
- const problemDir = currentPathProblemId === problemId ? process.cwd() : join(process.cwd(), "problems", String(problemId));
395
+ const problemDir = currentPathProblemId === problemId ? process.cwd() : getProblemDirPath(problemId);
414
396
  const sourcePath = await detectSolutionFile(problemDir);
415
397
  const detectedLanguage = language ?? detectLanguageFromFile(sourcePath);
416
398
  if (!detectedLanguage) {