@rhseung/ps-cli 1.5.0 → 1.6.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,163 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Command,
4
+ CommandBuilder,
5
+ CommandDef,
6
+ findProjectRoot,
7
+ getProblemDirPath,
8
+ getProblemId,
9
+ getSolvingDirPath
10
+ } from "../chunk-RVD22OUQ.js";
11
+ import {
12
+ __decorateClass
13
+ } from "../chunk-7MQMPJ3X.js";
14
+
15
+ // src/commands/solve.tsx
16
+ import { StatusMessage, Alert } from "@inkjs/ui";
17
+ import { Spinner } from "@inkjs/ui";
18
+ import { Box } from "ink";
19
+
20
+ // src/hooks/use-solve.ts
21
+ import { access, readFile, rename } from "fs/promises";
22
+ import { join } from "path";
23
+ import { execa } from "execa";
24
+ import { useEffect, useState } from "react";
25
+ function useSolve({
26
+ problemId,
27
+ onComplete
28
+ }) {
29
+ const [status, setStatus] = useState(
30
+ "loading"
31
+ );
32
+ const [message, setMessage] = useState("\uBB38\uC81C\uB97C \uC544\uCE74\uC774\uBE0C\uD558\uB294 \uC911...");
33
+ const [error, setError] = useState(null);
34
+ useEffect(() => {
35
+ async function solve() {
36
+ try {
37
+ const projectRoot = findProjectRoot();
38
+ if (!projectRoot) {
39
+ throw new Error("\uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
40
+ }
41
+ const solvingDir = getSolvingDirPath(problemId, projectRoot);
42
+ setMessage("solving \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C\uB97C \uD655\uC778\uD558\uB294 \uC911...");
43
+ try {
44
+ await access(solvingDir);
45
+ } catch {
46
+ throw new Error(
47
+ `solving \uB514\uB809\uD1A0\uB9AC\uC5D0 \uBB38\uC81C ${problemId}\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
48
+ );
49
+ }
50
+ setMessage("\uBB38\uC81C \uC815\uBCF4\uB97C \uC77D\uB294 \uC911...");
51
+ const metaPath = join(solvingDir, "meta.json");
52
+ let problemTitle = `\uBB38\uC81C ${problemId}`;
53
+ try {
54
+ const metaContent = await readFile(metaPath, "utf-8");
55
+ const meta = JSON.parse(metaContent);
56
+ if (meta.title) {
57
+ problemTitle = meta.title;
58
+ }
59
+ } catch {
60
+ }
61
+ const problemDir = getProblemDirPath(problemId, projectRoot);
62
+ try {
63
+ await access(problemDir);
64
+ throw new Error(
65
+ `problem \uB514\uB809\uD1A0\uB9AC\uC5D0 \uC774\uBBF8 \uBB38\uC81C ${problemId}\uAC00 \uC874\uC7AC\uD569\uB2C8\uB2E4.`
66
+ );
67
+ } catch (err) {
68
+ if (err instanceof Error && err.message.includes("\uC774\uBBF8")) {
69
+ throw err;
70
+ }
71
+ }
72
+ setMessage("\uBB38\uC81C\uB97C problem \uB514\uB809\uD1A0\uB9AC\uB85C \uC774\uB3D9\uD558\uB294 \uC911...");
73
+ await rename(solvingDir, problemDir);
74
+ setMessage("Git \uCEE4\uBC0B\uC744 \uC2E4\uD589\uD558\uB294 \uC911...");
75
+ try {
76
+ await execa("git", ["add", problemDir], { cwd: projectRoot });
77
+ const commitMessage = `solve: ${problemId} - ${problemTitle}`;
78
+ await execa("git", ["commit", "-m", commitMessage], {
79
+ cwd: projectRoot
80
+ });
81
+ } catch (gitError) {
82
+ console.warn(
83
+ "Git \uCEE4\uBC0B \uC2E4\uD328:",
84
+ gitError instanceof Error ? gitError.message : String(gitError)
85
+ );
86
+ }
87
+ setStatus("success");
88
+ setMessage(`\uBB38\uC81C ${problemId}\uB97C \uC544\uCE74\uC774\uBE0C\uD588\uC2B5\uB2C8\uB2E4: ${problemDir}`);
89
+ setTimeout(() => {
90
+ onComplete?.();
91
+ }, 2e3);
92
+ } catch (err) {
93
+ setStatus("error");
94
+ setError(err instanceof Error ? err.message : String(err));
95
+ setTimeout(() => {
96
+ onComplete?.();
97
+ }, 2e3);
98
+ }
99
+ }
100
+ void solve();
101
+ }, [problemId, onComplete]);
102
+ return {
103
+ status,
104
+ message,
105
+ error
106
+ };
107
+ }
108
+
109
+ // src/commands/solve.tsx
110
+ import { jsx, jsxs } from "react/jsx-runtime";
111
+ function SolveView({ problemId, onComplete }) {
112
+ const { status, message, error } = useSolve({
113
+ problemId,
114
+ onComplete
115
+ });
116
+ if (status === "loading") {
117
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsx(Spinner, { label: message }) });
118
+ }
119
+ if (status === "error") {
120
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: /* @__PURE__ */ jsxs(Alert, { variant: "error", children: [
121
+ "\uC624\uB958 \uBC1C\uC0DD: ",
122
+ error
123
+ ] }) });
124
+ }
125
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx(StatusMessage, { variant: "success", children: message }) });
126
+ }
127
+ var SolveCommand = class extends Command {
128
+ async execute(args, _) {
129
+ const problemId = getProblemId(args);
130
+ if (problemId === null) {
131
+ console.error("\uC624\uB958: \uBB38\uC81C \uBC88\uD638\uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694.");
132
+ console.error(`\uC0AC\uC6A9\uBC95: ps solve <\uBB38\uC81C\uBC88\uD638>`);
133
+ console.error(`\uB3C4\uC6C0\uB9D0: ps solve --help`);
134
+ console.error(
135
+ `\uD78C\uD2B8: solving/{\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.`
136
+ );
137
+ process.exit(1);
138
+ return;
139
+ }
140
+ await this.renderView(SolveView, {
141
+ problemId
142
+ });
143
+ }
144
+ };
145
+ SolveCommand = __decorateClass([
146
+ CommandDef({
147
+ name: "solve",
148
+ description: `\uBB38\uC81C\uB97C \uC544\uCE74\uC774\uBE0C\uD558\uACE0 Git \uCEE4\uBC0B\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.
149
+ - solving \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C\uB97C \uCC3E\uC544 problem \uB514\uB809\uD1A0\uB9AC\uB85C \uC774\uB3D9
150
+ - Git add \uBC0F commit \uC2E4\uD589 (\uCEE4\uBC0B \uBA54\uC2DC\uC9C0: "solve: {\uBB38\uC81C\uBC88\uD638} - {\uBB38\uC81C\uC774\uB984}")`,
151
+ autoDetectProblemId: true,
152
+ requireProblemId: false,
153
+ examples: [
154
+ "solve 1000",
155
+ "solve # \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uBB38\uC81C \uBC88\uD638 \uC790\uB3D9 \uAC10\uC9C0"
156
+ ]
157
+ })
158
+ ], SolveCommand);
159
+ var solve_default = CommandBuilder.fromClass(SolveCommand);
160
+ export {
161
+ SolveCommand,
162
+ solve_default as default
163
+ };
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getUserStats
4
- } from "../chunk-A6STXEAE.js";
3
+ source_default
4
+ } from "../chunk-ASMT3CRD.js";
5
5
  import {
6
6
  calculateTierProgress,
7
7
  getNextTierMinRating,
8
8
  getTierColor,
9
9
  getTierName,
10
- source_default
11
- } from "../chunk-HDNNR5OY.js";
10
+ getUserStats
11
+ } from "../chunk-NH36IFWR.js";
12
12
  import {
13
13
  Command,
14
14
  CommandBuilder,
15
15
  CommandDef,
16
16
  getSolvedAcHandle
17
- } from "../chunk-7SVCS23X.js";
17
+ } from "../chunk-RVD22OUQ.js";
18
18
  import {
19
19
  __decorateClass
20
20
  } from "../chunk-7MQMPJ3X.js";
@@ -11,7 +11,7 @@ import {
11
11
  getProblemId,
12
12
  resolveLanguage,
13
13
  resolveProblemContext
14
- } from "../chunk-7SVCS23X.js";
14
+ } from "../chunk-RVD22OUQ.js";
15
15
  import {
16
16
  __decorateClass,
17
17
  getSupportedLanguagesString
@@ -9,7 +9,7 @@ import {
9
9
  getProblemId,
10
10
  resolveLanguage,
11
11
  resolveProblemContext
12
- } from "../chunk-7SVCS23X.js";
12
+ } from "../chunk-RVD22OUQ.js";
13
13
  import {
14
14
  __decorateClass,
15
15
  getSupportedLanguagesString
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhseung/ps-cli",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "백준(BOJ) 문제 해결을 위한 통합 CLI 도구",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/services/solved-api.ts
4
- var BASE_URL = "https://solved.ac/api/v3";
5
- var USER_AGENT = "ps-cli/1.0.0";
6
- async function fetchWithRetry(url, options = {}, maxRetries = 3) {
7
- let lastError = null;
8
- for (let attempt = 0; attempt < maxRetries; attempt++) {
9
- try {
10
- const response = await fetch(url, {
11
- ...options,
12
- headers: {
13
- "User-Agent": USER_AGENT,
14
- ...options.headers
15
- }
16
- });
17
- if (response.status === 429) {
18
- const retryAfter = response.headers.get("Retry-After");
19
- const waitTime = retryAfter ? parseInt(retryAfter, 10) * 1e3 : (attempt + 1) * 1e3;
20
- await new Promise((resolve) => setTimeout(resolve, waitTime));
21
- continue;
22
- }
23
- if (!response.ok) {
24
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
25
- }
26
- return response;
27
- } catch (error) {
28
- lastError = error instanceof Error ? error : new Error(String(error));
29
- if (attempt < maxRetries - 1) {
30
- await new Promise(
31
- (resolve) => setTimeout(resolve, (attempt + 1) * 1e3)
32
- );
33
- }
34
- }
35
- }
36
- throw lastError || new Error("Request failed after retries");
37
- }
38
- async function getProblem(problemId) {
39
- const url = `${BASE_URL}/problem/show?problemId=${problemId}`;
40
- const response = await fetchWithRetry(url);
41
- const data = await response.json();
42
- return data;
43
- }
44
- async function getUserStats(handle) {
45
- const url = `${BASE_URL}/user/show?handle=${handle}`;
46
- const response = await fetchWithRetry(url);
47
- const data = await response.json();
48
- return data;
49
- }
50
-
51
- export {
52
- getProblem,
53
- getUserStats
54
- };