@rhseung/ps-cli 1.0.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,191 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runSolution
4
+ } from "../chunk-EIFFWFLS.js";
5
+ import {
6
+ detectProblemIdFromPath,
7
+ getProblemId
8
+ } from "../chunk-OOTPZD7O.js";
9
+ import {
10
+ detectLanguageFromFile,
11
+ getSupportedLanguages,
12
+ getSupportedLanguagesString
13
+ } from "../chunk-TQXMB7XV.js";
14
+ import {
15
+ LoadingSpinner
16
+ } from "../chunk-IJLJBKLK.js";
17
+ import "../chunk-FYS2JH42.js";
18
+
19
+ // src/commands/run.tsx
20
+ import { useEffect, useState } from "react";
21
+ import { render, Box, Text } from "ink";
22
+ import { readdir } from "fs/promises";
23
+ import { join } from "path";
24
+ import { jsx, jsxs } from "react/jsx-runtime";
25
+ function RunCommand({
26
+ problemDir,
27
+ language,
28
+ inputFile,
29
+ onComplete
30
+ }) {
31
+ const [status, setStatus] = useState(
32
+ "loading"
33
+ );
34
+ const [result, setResult] = useState(null);
35
+ const [error, setError] = useState(null);
36
+ useEffect(() => {
37
+ void runSolution({
38
+ problemDir,
39
+ language,
40
+ inputPath: inputFile,
41
+ timeoutMs: 1e4
42
+ // 10초 타임아웃
43
+ }).then((runResult) => {
44
+ setResult(runResult);
45
+ setStatus("ready");
46
+ setTimeout(() => {
47
+ onComplete();
48
+ }, 100);
49
+ }).catch((err) => {
50
+ setError(err instanceof Error ? err.message : String(err));
51
+ setStatus("error");
52
+ setTimeout(() => {
53
+ onComplete();
54
+ }, 2e3);
55
+ });
56
+ }, [problemDir, language, inputFile, onComplete]);
57
+ 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
+ ] });
62
+ }
63
+ 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
+ ] });
68
+ }
69
+ if (result) {
70
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
71
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
72
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "\uC2E4\uD589 \uACB0\uACFC" }),
73
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
74
+ problemDir,
75
+ " \u2022 ",
76
+ language,
77
+ result.timedOut && " \u2022 \uD0C0\uC784\uC544\uC6C3"
78
+ ] })
79
+ ] }),
80
+ /* @__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: ",
83
+ result.exitCode,
84
+ ")"
85
+ ] }) : /* @__PURE__ */ jsx(Text, { color: "green", children: "\u2713 \uC2E4\uD589 \uC644\uB8CC" }),
86
+ result.stdout && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
87
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "\uCD9C\uB825:" }),
88
+ /* @__PURE__ */ jsx(Text, { children: result.stdout })
89
+ ] }),
90
+ result.stderr && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
91
+ /* @__PURE__ */ jsx(Text, { color: "yellow", dimColor: true, children: "\uC5D0\uB7EC \uCD9C\uB825:" }),
92
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: result.stderr })
93
+ ] }),
94
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
95
+ "\uC2E4\uD589 \uC2DC\uAC04: ",
96
+ result.durationMs,
97
+ "ms"
98
+ ] }) })
99
+ ] })
100
+ ] });
101
+ }
102
+ return null;
103
+ }
104
+ async function findInputFile(problemDir) {
105
+ const files = await readdir(problemDir);
106
+ const inputFile = files.find((f) => f === "input1.txt") || files.find((f) => f === "input.txt");
107
+ if (!inputFile) {
108
+ throw new Error("input.txt \uB610\uB294 input1.txt \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
109
+ }
110
+ return join(problemDir, inputFile);
111
+ }
112
+ async function runCommand(problemId, language, inputFile) {
113
+ const currentPathProblemId = detectProblemIdFromPath(process.cwd());
114
+ const problemDir = problemId && currentPathProblemId !== problemId ? join(process.cwd(), "problems", String(problemId)) : process.cwd();
115
+ const inputPath = inputFile ? join(problemDir, inputFile) : await findInputFile(problemDir);
116
+ const files = await readdir(problemDir);
117
+ const solutionFile = files.find((f) => f.startsWith("solution."));
118
+ if (!solutionFile) {
119
+ throw new Error("solution.* \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
120
+ }
121
+ const detectedLanguage = language ?? detectLanguageFromFile(solutionFile);
122
+ if (!detectedLanguage) {
123
+ throw new Error(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC5B8\uC5B4\uC785\uB2C8\uB2E4: ${solutionFile}`);
124
+ }
125
+ return new Promise((resolve) => {
126
+ const { unmount } = render(
127
+ /* @__PURE__ */ jsx(
128
+ RunCommand,
129
+ {
130
+ problemDir,
131
+ language: detectedLanguage,
132
+ inputFile: inputPath,
133
+ onComplete: () => {
134
+ unmount();
135
+ resolve();
136
+ }
137
+ }
138
+ )
139
+ );
140
+ });
141
+ }
142
+ var runHelp = `
143
+ \uC0AC\uC6A9\uBC95:
144
+ $ ps run [\uBB38\uC81C\uBC88\uD638] [\uC635\uC158]
145
+
146
+ \uC124\uBA85:
147
+ \uCF54\uB4DC\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4 (\uD14C\uC2A4\uD2B8 \uC5C6\uC774).
148
+ - \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC \uB610\uB294 \uC9C0\uC815\uD55C \uBB38\uC81C \uBC88\uD638\uC758 \uCF54\uB4DC \uC2E4\uD589
149
+ - solution.* \uD30C\uC77C\uC744 \uC790\uB3D9\uC73C\uB85C \uCC3E\uC544 \uC5B8\uC5B4 \uAC10\uC9C0
150
+ - input.txt \uB610\uB294 input1.txt\uB97C \uD45C\uC900 \uC785\uB825\uC73C\uB85C \uC0AC\uC6A9
151
+ - \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 \uAC80\uC99D \uC5C6\uC774 \uB2E8\uC21C \uC2E4\uD589
152
+
153
+ \uC635\uC158:
154
+ --language, -l \uC5B8\uC5B4 \uC120\uD0DD (\uC9C0\uC815 \uC2DC \uC790\uB3D9 \uAC10\uC9C0 \uBB34\uC2DC)
155
+ \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}
156
+ --input, -i \uC785\uB825 \uD30C\uC77C \uC9C0\uC815 (\uAE30\uBCF8\uAC12: input.txt \uB610\uB294 input1.txt)
157
+
158
+ \uC608\uC81C:
159
+ $ ps run # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC2E4\uD589
160
+ $ ps run 1000 # 1000\uBC88 \uBB38\uC81C \uC2E4\uD589
161
+ $ ps run --language python # Python\uC73C\uB85C \uC2E4\uD589
162
+ $ ps run --input input2.txt # \uD2B9\uC815 \uC785\uB825 \uD30C\uC77C \uC0AC\uC6A9
163
+ `;
164
+ async function runExecute(args, flags) {
165
+ if (flags.help) {
166
+ console.log(runHelp.trim());
167
+ process.exit(0);
168
+ return;
169
+ }
170
+ const problemId = getProblemId(args);
171
+ const validLanguages = getSupportedLanguages();
172
+ const language = flags.language;
173
+ if (flags.language && language && !validLanguages.includes(language)) {
174
+ console.error(
175
+ `\uC624\uB958: \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC5B8\uC5B4\uC785\uB2C8\uB2E4. (${getSupportedLanguagesString()})`
176
+ );
177
+ process.exit(1);
178
+ }
179
+ await runCommand(problemId, language, flags.input);
180
+ }
181
+ var runCommandDef = {
182
+ name: "run",
183
+ help: runHelp,
184
+ execute: runExecute
185
+ };
186
+ var run_default = runCommandDef;
187
+ export {
188
+ run_default as default,
189
+ runExecute,
190
+ runHelp
191
+ };
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getTierColor,
4
+ getTierName,
5
+ getUserStats,
6
+ source_default
7
+ } from "../chunk-2E4VSP6O.js";
8
+ import {
9
+ getSolvedAcHandle
10
+ } from "../chunk-KFQFQJYT.js";
11
+ import {
12
+ LoadingSpinner
13
+ } from "../chunk-IJLJBKLK.js";
14
+ import "../chunk-FYS2JH42.js";
15
+
16
+ // src/commands/stats.tsx
17
+ import { useEffect, useState } from "react";
18
+ import { render, Box, Text } from "ink";
19
+ import gradient from "gradient-string";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ function StatsCommand({ handle, onComplete }) {
22
+ const [status, setStatus] = useState(
23
+ "loading"
24
+ );
25
+ const [user, setUser] = useState(null);
26
+ const [error, setError] = useState(null);
27
+ useEffect(() => {
28
+ void getUserStats(handle).then((userData) => {
29
+ setUser(userData);
30
+ setStatus("success");
31
+ setTimeout(() => {
32
+ onComplete();
33
+ }, 5e3);
34
+ }).catch((err) => {
35
+ setError(err instanceof Error ? err.message : String(err));
36
+ setStatus("error");
37
+ setTimeout(() => {
38
+ onComplete();
39
+ }, 3e3);
40
+ });
41
+ }, [handle, onComplete]);
42
+ if (status === "loading") {
43
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(LoadingSpinner, { message: "\uD1B5\uACC4\uB97C \uBD88\uB7EC\uC624\uB294 \uC911..." }) });
44
+ }
45
+ 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: ",
48
+ error
49
+ ] }) });
50
+ }
51
+ if (user) {
52
+ const tierName = getTierName(user.tier);
53
+ const tierDisplay = user.tier === 31 ? gradient([
54
+ { r: 255, g: 124, b: 168 },
55
+ { r: 180, g: 145, b: 255 },
56
+ { r: 124, g: 249, b: 255 }
57
+ ])(tierName) : source_default.hex(getTierColor(user.tier))(tierName);
58
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
59
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
60
+ "\u2728 ",
61
+ user.handle
62
+ ] }) }),
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
+ /* @__PURE__ */ jsx(
69
+ Box,
70
+ {
71
+ flexDirection: "column",
72
+ borderStyle: "round",
73
+ borderColor: "gray",
74
+ alignSelf: "flex-start",
75
+ children: /* @__PURE__ */ jsxs(Box, { paddingX: 1, paddingY: 0, flexDirection: "column", children: [
76
+ /* @__PURE__ */ jsxs(Text, { children: [
77
+ "\uD574\uACB0\uD55C \uBB38\uC81C:",
78
+ " ",
79
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: user.solvedCount.toLocaleString() }),
80
+ "\uAC1C"
81
+ ] }),
82
+ /* @__PURE__ */ jsxs(Text, { children: [
83
+ "\uD074\uB798\uC2A4: ",
84
+ /* @__PURE__ */ jsx(Text, { bold: true, children: user.class })
85
+ ] }),
86
+ user.maxStreak > 0 && /* @__PURE__ */ jsxs(Text, { children: [
87
+ "\uCD5C\uB300 \uC5F0\uC18D \uD574\uACB0:",
88
+ " ",
89
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: user.maxStreak }),
90
+ "\uC77C"
91
+ ] }),
92
+ /* @__PURE__ */ jsxs(Text, { children: [
93
+ "\uC21C\uC704: ",
94
+ /* @__PURE__ */ jsx(Text, { bold: true, children: user.rank.toLocaleString() }),
95
+ "\uC704"
96
+ ] })
97
+ ] })
98
+ }
99
+ )
100
+ ] });
101
+ }
102
+ return null;
103
+ }
104
+ async function statsCommand(handle) {
105
+ return new Promise((resolve) => {
106
+ const { unmount } = render(
107
+ /* @__PURE__ */ jsx(
108
+ StatsCommand,
109
+ {
110
+ handle,
111
+ onComplete: () => {
112
+ unmount();
113
+ resolve();
114
+ }
115
+ }
116
+ )
117
+ );
118
+ });
119
+ }
120
+ var statsHelp = `
121
+ \uC0AC\uC6A9\uBC95:
122
+ $ ps stats [\uD578\uB4E4] [\uC635\uC158]
123
+
124
+ \uC124\uBA85:
125
+ Solved.ac\uC5D0\uC11C \uC0AC\uC6A9\uC790 \uD1B5\uACC4\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.
126
+ - \uD2F0\uC5B4, \uB808\uC774\uD305, \uD574\uACB0\uD55C \uBB38\uC81C \uC218 \uB4F1 \uD45C\uC2DC
127
+ - \uADF8\uB77C\uB370\uC774\uC158\uC73C\uB85C \uC2DC\uAC01\uC801\uC73C\uB85C \uD45C\uC2DC
128
+
129
+ \uC635\uC158:
130
+ --handle, -h Solved.ac \uD578\uB4E4 (\uC124\uC815\uC5D0 \uC800\uC7A5\uB41C \uAC12 \uC0AC\uC6A9 \uAC00\uB2A5)
131
+
132
+ \uC608\uC81C:
133
+ $ ps stats myhandle
134
+ $ ps stats --handle myhandle
135
+ `;
136
+ async function statsExecute(args, flags) {
137
+ if (flags.help) {
138
+ console.log(statsHelp.trim());
139
+ process.exit(0);
140
+ return;
141
+ }
142
+ let handle = args[0] || flags.handle;
143
+ if (!handle) {
144
+ handle = getSolvedAcHandle();
145
+ }
146
+ if (!handle) {
147
+ console.error("\uC624\uB958: Solved.ac \uD578\uB4E4\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694.");
148
+ console.error(`\uC0AC\uC6A9\uBC95: ps stats <\uD578\uB4E4>`);
149
+ console.error(`\uB3C4\uC6C0\uB9D0: ps stats --help`);
150
+ console.error(`\uD78C\uD2B8: \uC124\uC815\uC5D0 \uD578\uB4E4\uC744 \uC800\uC7A5\uD558\uBA74 \uB9E4\uBC88 \uC785\uB825\uD560 \uD544\uC694\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`);
151
+ process.exit(1);
152
+ }
153
+ await statsCommand(handle);
154
+ }
155
+ var statsCommandDef = {
156
+ name: "stats",
157
+ help: statsHelp,
158
+ execute: statsExecute
159
+ };
160
+ var stats_default = statsCommandDef;
161
+ export {
162
+ stats_default as default,
163
+ statsExecute,
164
+ statsHelp
165
+ };