@rhseung/ps-cli 1.7.0 → 1.7.1

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.
package/README.md CHANGED
@@ -1,342 +1,179 @@
1
1
  # ps-cli
2
2
 
3
- 백준(BOJ) 문제 해결을 위한 통합 CLI 도구입니다. Ink 기반의 인터랙티브 터미널 UI로 문제 가져오기, 로컬 테스트, 제출까지 지원하는 개발 환경을 제공합니다.
3
+ 백준 문제 해결을 위한 CLI 도구입니다.
4
4
 
5
5
  ## 설치
6
6
 
7
- ### npm 사용
8
-
9
7
  ```bash
10
8
  npm install -g @rhseung/ps-cli
11
- ```
12
-
13
- ### bun 사용
14
-
15
- ```bash
9
+ # 또는
16
10
  bun install -g @rhseung/ps-cli
17
11
  ```
18
12
 
19
- 또는 `bunx`를 사용하여 직접 실행:
13
+ ## 빠른 시작
20
14
 
21
15
  ```bash
22
- bunx @rhseung/ps-cli fetch 1000
23
- ```
24
-
25
- ## 요구사항
16
+ # 1. 프로젝트 초기화
17
+ ps init
26
18
 
27
- - Node.js >= 18.0.0
19
+ # 2. 문제 가져오기
20
+ ps fetch 1000
28
21
 
29
- ## 주요 기능
22
+ # 3. 코드 작성 후 테스트
23
+ ps test
30
24
 
31
- - **문제 가져오기**: Solved.ac API와 BOJ 크롤링을 통한 문제 정보 및 예제 데이터 자동 생성
32
- - **로컬 테스트**: 여러 언어(JS/TS, Python, C++) 지원 및 자동 테스트 실행
33
- - **제출**: BOJ 자동 제출 및 결과 확인
34
- - **통계**: Solved.ac API를 활용한 사용자 통계 조회
35
- - **Watch 모드**: 파일 저장 시 자동 테스트 실행
25
+ # 4. 제출
26
+ ps submit
27
+ ```
36
28
 
37
29
  ## 명령어
38
30
 
39
31
  ### `init` - 프로젝트 초기화
40
32
 
41
- 현재 디렉토리를 ps-cli 프로젝트로 초기화합니다.
42
-
43
- ```bash
44
- ps init
45
- ```
46
-
47
- **기능:**
48
-
49
- - `problems/` 디렉토리 생성
50
- - `.gitignore`에 `problems/` 추가 (이미 있으면 스킵)
51
-
52
- **예제:**
33
+ 프로젝트를 초기화하고 설정을 구성합니다.
53
34
 
54
35
  ```bash
55
- # 프로젝트 폴더에서 초기화
56
- mkdir my-algorithm-problems
57
- cd my-algorithm-problems
58
36
  ps init
59
-
60
- # 이제 문제를 가져올 수 있습니다
61
- ps fetch 1000
62
37
  ```
63
38
 
64
39
  ### `fetch` - 문제 가져오기
65
40
 
66
41
  백준 문제를 가져와서 로컬에 파일을 생성합니다.
67
42
 
68
- ```bash
69
- ps fetch <문제번호> [옵션]
70
- ```
71
-
72
- **기능:**
73
-
74
- - Solved.ac API와 BOJ 크롤링을 통해 문제 정보 수집
75
- - 문제 설명, 입출력 형식, 예제 입출력 파일 자동 생성
76
- - 선택한 언어의 솔루션 템플릿 파일 생성
77
- - README.md에 문제 정보, 통계, 태그 등 포함
78
-
79
- **옵션:**
80
-
81
- - `--language, -l`: 언어 선택 (python, javascript, typescript, cpp)
82
- - 기본값: python
83
-
84
- **예제:**
85
-
86
43
  ```bash
87
44
  ps fetch 1000
88
45
  ps fetch 1000 --language python
89
- ps fetch 1000 -l cpp
90
46
  ```
91
47
 
92
- ### `test` - 로컬 테스트 실행
93
-
94
- 예제 입출력 기반으로 로컬 테스트를 실행합니다.
95
-
96
- ```bash
97
- ps test [문제번호] [옵션]
98
- ```
99
-
100
- **기능:**
101
-
102
- - 현재 디렉토리 또는 지정한 문제 번호의 테스트 실행
103
- - `solution.*` 파일을 자동으로 찾아 언어 감지
104
- - `input*.txt`와 `output*.txt` 파일을 기반으로 테스트
105
- - 문제의 시간 제한을 자동으로 적용
106
- - `--watch` 옵션으로 파일 변경 시 자동 재테스트
48
+ ### `test` - 로컬 테스트
107
49
 
108
- **옵션:**
109
-
110
- - `--language, -l`: 언어 선택 (지정 시 자동 감지 무시)
111
- - `--watch, -w`: watch 모드 (파일 변경 시 자동 재테스트)
112
-
113
- **예제:**
50
+ 예제 입출력으로 테스트를 실행합니다.
114
51
 
115
52
  ```bash
116
- ps test # 현재 디렉토리에서 테스트
117
- ps test 1000 # 1000번 문제 테스트
118
- ps test --watch # watch 모드로 테스트
119
- ps test 1000 --watch # 1000번 문제를 watch 모드로 테스트
53
+ ps test
54
+ ps test 1000
55
+ ps test --watch # 파일 변경 시 자동 재테스트
120
56
  ```
121
57
 
122
58
  ### `run` - 코드 실행
123
59
 
124
- 코드를 실행합니다 (테스트 없이).
60
+ 테스트 없이 코드를 실행합니다.
125
61
 
126
62
  ```bash
127
- ps run [문제번호] [옵션]
63
+ ps run
64
+ ps run 1000
128
65
  ```
129
66
 
130
- **기능:**
131
-
132
- - 현재 디렉토리 또는 지정한 문제 번호의 코드 실행
133
- - `solution.*` 파일을 자동으로 찾아 언어 감지
134
- - `input.txt` 또는 `input1.txt`를 표준 입력으로 사용
135
- - 테스트 케이스 검증 없이 단순 실행
136
-
137
- **옵션:**
67
+ ### `submit` - 제출
138
68
 
139
- - `--language, -l`: 언어 선택 (지정 자동 감지 무시)
140
- - `--input, -i`: 입력 파일 지정 (기본값: input.txt 또는 input1.txt)
141
-
142
- **예제:**
69
+ 백준 제출 페이지를 열고 소스 코드를 클립보드에 복사합니다.
143
70
 
144
71
  ```bash
145
- ps run # 현재 디렉토리에서 실행
146
- ps run 1000 # 1000번 문제 실행
147
- ps run --language python # Python으로 실행
148
- ps run --input input2.txt # 특정 입력 파일 사용
72
+ ps submit
73
+ ps submit 1000
149
74
  ```
150
75
 
151
- ### `submit` - BOJ 제출
76
+ ### `solve` - 아카이빙
152
77
 
153
- 현재 문제의 솔루션 파일을 BOJ에 제출합니다.
78
+ solving 디렉토리의 문제를 problem 디렉토리로 이동하고 Git 커밋을 생성합니다.
154
79
 
155
80
  ```bash
156
- ps submit [문제번호] [옵션]
81
+ ps solve 1000
157
82
  ```
158
83
 
159
- **기능:**
160
-
161
- - 현재 디렉토리 또는 지정한 문제 번호의 솔루션 파일 제출
162
- - `solution.*` 파일을 자동으로 찾아 언어 감지
163
- - 제출 후 채점 결과를 자동으로 확인
164
-
165
- **옵션:**
166
-
167
- - `--language, -l`: 언어 선택 (지정 시 자동 감지 무시)
168
- - `--dry-run`: 실제 제출 없이 검증만 수행
169
-
170
- **예제:**
84
+ ### `open` - 문제 페이지 열기
171
85
 
172
- ```bash
173
- ps submit # 현재 디렉토리에서 제출
174
- ps submit 1000 # 1000번 문제 제출
175
- ps submit --language python # Python으로 제출
176
- ps submit --dry-run # 제출 전 검증만 수행
177
- ```
178
-
179
- **참고:** 제출 기능을 사용하려면 먼저 BOJ 세션 쿠키를 설정해야 합니다:
86
+ 백준 문제 페이지를 브라우저로 엽니다.
180
87
 
181
88
  ```bash
182
- ps config boj-session-cookie "boj_session=your_session_cookie"
89
+ ps open 1000
183
90
  ```
184
91
 
185
- ### `stats` - 사용자 통계 조회
92
+ ### `search` - 문제 검색
186
93
 
187
- Solved.ac에서 사용자 통계를 조회합니다.
94
+ solved.ac에서 문제를 검색합니다.
188
95
 
189
96
  ```bash
190
- ps stats [핸들] [옵션]
97
+ ps search "*g1...g5"
98
+ ps search --workbook 12345
191
99
  ```
192
100
 
193
- **기능:**
194
-
195
- - 티어, 레이팅, 해결한 문제 수 등 표시
196
- - 그라데이션으로 시각적으로 표시
197
-
198
- **옵션:**
199
-
200
- - `--handle, -h`: Solved.ac 핸들 (설정에 저장된 값 사용 가능)
101
+ ### `stats` - 통계 조회
201
102
 
202
- **예제:**
103
+ Solved.ac 사용자 통계를 조회합니다.
203
104
 
204
105
  ```bash
106
+ ps stats
205
107
  ps stats myhandle
206
- ps stats --handle myhandle
207
- ```
208
-
209
- **참고:** 핸들을 설정에 저장하면 매번 입력할 필요가 없습니다:
210
-
211
- ```bash
212
- ps config solved-ac-handle myhandle
213
- ps stats # 설정된 핸들 사용
214
108
  ```
215
109
 
216
110
  ### `config` - 설정 관리
217
111
 
218
- 사용자 설정을 관리합니다.
219
-
220
- ```bash
221
- ps config <키> [값]
222
- ps config <키> --get
223
- ps config --list
224
- ```
225
-
226
- **설정 키:**
227
-
228
- - `boj-session-cookie`: BOJ 세션 쿠키 (제출 기능용)
229
- - `default-language`: 기본 언어 (python, javascript, typescript, cpp)
230
- - `code-open`: 코드 공개 여부 (true/false)
231
- - `editor`: 에디터 명령어 (예: code, vim, nano)
232
- - `auto-open-editor`: fetch 후 자동으로 에디터 열기 (true/false)
233
- - `solved-ac-handle`: Solved.ac 핸들 (stats 명령어용)
234
- - `problem-dir`: 문제 디렉토리 경로 (기본값: `problems`, `"."` 또는 `""`는 프로젝트 루트에 직접 저장)
235
-
236
- **옵션:**
237
-
238
- - `--get`: 설정 값 조회
239
- - `--list`: 모든 설정 조회
240
- - `--help, -h`: 도움말 표시
241
-
242
- **예제:**
243
-
244
- ```bash
245
- ps config boj-session-cookie "boj_session=xxx"
246
- ps config default-language python
247
- ps config solved-ac-handle myhandle
248
- ps config solved-ac-handle --get
249
- ps config --list
250
- ```
251
-
252
- ### `help` - 도움말 표시
253
-
254
- 도움말을 표시합니다.
112
+ 프로젝트 설정을 관리합니다.
255
113
 
256
114
  ```bash
257
- ps help
258
- ps --help
259
- ps <명령어> --help
115
+ ps config list
116
+ ps config set default-language python
117
+ ps config get archive-strategy
260
118
  ```
261
119
 
262
- ## 기술 스택
263
-
264
- - **Ink**: React 기반 터미널 UI
265
- - **TypeScript**: 타입 안전성
266
- - **Meow**: CLI 인자 파싱
267
- - **Execa**: 프로세스 실행
268
- - **Cheerio**: HTML 파싱
269
- - **tsup**: 빌드 도구
270
-
271
- ## 사용 예제
272
-
273
- ### 전체 워크플로우
274
-
275
- ```bash
276
- # 1. 프로젝트 초기화 (최초 1회)
277
- ps init
278
-
279
- # 2. 문제 가져오기
280
- ps fetch 1000 --language python
281
-
282
- # 3. 문제 디렉토리로 이동
283
- cd problems/1000
284
-
285
- # 4. 코드 작성 (solution.py 편집)
120
+ ## 설정
286
121
 
287
- # 5. 로컬 테스트
288
- ps test
289
-
290
- # 6. Watch 모드로 개발 (파일 저장 시 자동 테스트)
291
- ps test --watch
122
+ 프로젝트 루트의 `.ps-cli.json` 파일에 저장됩니다.
292
123
 
293
- # 7. 단일 입력으로 실행 테스트
294
- ps run
124
+ ### 주요 설정
295
125
 
296
- # 8. BOJ에 제출
297
- ps submit
298
- ```
126
+ - `default-language`: 기본 언어 (python, javascript, typescript, cpp)
127
+ - `editor`: 에디터 명령어 (code, cursor, vim 등)
128
+ - `auto-open-editor`: fetch 후 자동으로 에디터 열기 (true/false)
129
+ - `solved-ac-handle`: Solved.ac 핸들
130
+ - `problem-dir`: 아카이브된 문제 디렉토리 (기본값: problems)
131
+ - `solving-dir`: 푸는 중인 문제 디렉토리 (기본값: solving)
132
+ - `archive-strategy`: 아카이빙 전략
299
133
 
300
- ### 설정 예제
134
+ ### 아카이빙 전략
301
135
 
302
- ```bash
303
- # BOJ 세션 쿠키 설정 (제출 기능용)
304
- ps config boj-session-cookie "boj_session=your_cookie_here"
136
+ 문제가 많아질 때를 대비해 아카이빙 전략을 선택할 수 있습니다:
305
137
 
306
- # 기본 언어 설정
307
- ps config default-language python
138
+ - `flat`: 평면적으로 나열 (기본값)
308
139
 
309
- # Solved.ac 핸들 설정
310
- ps config solved-ac-handle myhandle
140
+ ```txt
141
+ problems/1000/
142
+ problems/1001/
143
+ ```
311
144
 
312
- # fetch 자동으로 VS Code 열기
313
- ps config editor code
314
- ps config auto-open-editor true
145
+ - `by-range`: 1000번대별로 묶기
315
146
 
316
- # 문제 디렉토리 설정
317
- ps config problem-dir "problems" # problems 디렉토리 사용 (기본값)
318
- ps config problem-dir "." # 프로젝트 루트에 직접 저장
319
- ps config problem-dir "solutions" # solutions 디렉토리 사용
320
- ```
147
+ ```txt
148
+ problems/01000/1000/
149
+ problems/01000/1001/
150
+ problems/02000/2000/
151
+ ```
321
152
 
322
- ### 문제 디렉토리 설정
153
+ - `by-tier`: 티어별로 묶기
323
154
 
324
- `problem-dir` 설정을 통해 문제 파일이 저장되는 위치를 변경할 수 있습니다:
155
+ ```txt
156
+ problems/bronze-v/1000/
157
+ problems/silver-i/1001/
158
+ ```
325
159
 
326
- - **기본값 (`problems`)**: `problems/{문제번호}/` 형식으로 저장
327
- - **프로젝트 루트 (`"."` 또는 `""`)**: 프로젝트 루트에 `{문제번호}/` 형식으로 직접 저장
160
+ - `by-tag`: 태그별로 묶기
328
161
 
329
- **예제:**
162
+ ```txt
163
+ problems/구현/1000/
164
+ problems/그래프-이론/1001/
165
+ ```
330
166
 
331
- ```bash
332
- # 프로젝트 루트에 직접 저장하도록 설정
333
- ps config problem-dir "."
167
+ **참고:** solving 디렉토리는 항상 평면적으로 나열됩니다.
334
168
 
335
- # 문제 가져오기 (프로젝트 루트에 1000/ 디렉토리 생성)
336
- ps fetch 1000
169
+ ## 워크플로우
337
170
 
338
- # 결과: ./1000/solution.py, ./1000/input1.txt
339
- ```
171
+ 1. **초기화**: `ps init`으로 프로젝트 설정
172
+ 2. **가져오기**: `ps fetch 1000`으로 문제 가져오기
173
+ 3. **작성**: `solving/1000/`에서 코드 작성
174
+ 4. **테스트**: `ps test`로 로컬 테스트
175
+ 5. **제출**: `ps submit`으로 제출
176
+ 6. **아카이빙**: `ps solve`로 problem 디렉토리로 이동
340
177
 
341
178
  ## 라이선스
342
179
 
@@ -260,17 +260,57 @@ async function searchProblems(query, page = 1) {
260
260
  const $ = cheerio.load(html);
261
261
  const problems = [];
262
262
  const rows = $("tbody tr");
263
- rows.each((_, row) => {
263
+ rows.each((index, row) => {
264
264
  const $row = $(row);
265
265
  const cells = $row.find("td");
266
266
  if (cells.length >= 2) {
267
- const problemIdText = $(cells[0]).text().trim();
268
- const problemId = parseInt(problemIdText, 10);
269
- const title = $(cells[1]).text().trim();
270
- if (!isNaN(problemId) && title) {
267
+ const firstCell = $(cells[0]);
268
+ const firstCellText = firstCell.text().trim();
269
+ const problemIdMatches = firstCellText.match(/\d{4,}/g);
270
+ let problemId;
271
+ if (problemIdMatches && problemIdMatches.length > 0) {
272
+ problemId = parseInt(problemIdMatches[0], 10);
273
+ } else {
274
+ const problemIdMatch = firstCellText.match(/\d+/);
275
+ if (problemIdMatch) {
276
+ problemId = parseInt(problemIdMatch[0], 10);
277
+ } else {
278
+ problemId = parseInt(firstCellText, 10);
279
+ }
280
+ }
281
+ if (isNaN(problemId) || problemId <= 0) {
282
+ return;
283
+ }
284
+ const titleCell = $(cells[1]);
285
+ const linkElement = titleCell.find("a").first();
286
+ let title = linkElement.length > 0 ? linkElement.text().trim() : "";
287
+ if (!title) {
288
+ const clonedCell = titleCell.clone();
289
+ clonedCell.find("span, div").remove();
290
+ clonedCell.find('[class*="css-"]').remove();
291
+ title = clonedCell.text().trim();
292
+ title = title.replace(
293
+ /\s+(STANDARD|CLASS|NORMAL|EASY|MEDIUM|HARD|EXPERT|MASTER|CLASSIC)\s*$/i,
294
+ ""
295
+ );
296
+ title = title.replace(/\s*\.css-[a-z0-9-]+\s*/g, "");
297
+ title = title.trim();
298
+ }
299
+ if (!title || title.length === 0) {
300
+ title = titleCell.text().trim();
301
+ title = title.replace(
302
+ /\s+(STANDARD|CLASS|NORMAL|EASY|MEDIUM|HARD|EXPERT|MASTER|CLASSIC)\s*$/i,
303
+ ""
304
+ );
305
+ title = title.trim();
306
+ }
307
+ if (!isNaN(problemId) && problemId > 0) {
308
+ if (!title || title.length === 0) {
309
+ title = `\uBB38\uC81C ${problemId}`;
310
+ }
271
311
  let level;
272
- const firstCell = $(cells[0]);
273
- const tierImg = firstCell.find("img[src*='tier_small']");
312
+ const firstCell2 = $(cells[0]);
313
+ const tierImg = firstCell2.find("img[src*='tier_small']");
274
314
  if (tierImg.length > 0) {
275
315
  const imgSrc = tierImg.attr("src");
276
316
  if (imgSrc) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  scrapeProblem
4
- } from "../chunk-AG6KWWHS.js";
4
+ } from "../chunk-4ISG24GW.js";
5
5
  import {
6
6
  getProblem
7
7
  } from "../chunk-A6STXEAE.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-ASMT3CRD.js";
5
5
  import {
6
6
  searchProblems
7
- } from "../chunk-AG6KWWHS.js";
7
+ } from "../chunk-4ISG24GW.js";
8
8
  import {
9
9
  getProblem
10
10
  } from "../chunk-A6STXEAE.js";
package/dist/index.js CHANGED
@@ -9422,25 +9422,21 @@ function generateHelpText(commands2) {
9422
9422
 
9423
9423
  \uBA85\uB839\uC5B4:
9424
9424
  ${commandList}
9425
- help \uC774 \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
9425
+ help \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
9426
9426
 
9427
- \uC635\uC158:
9428
- --language, -l \uC5B8\uC5B4 \uC120\uD0DD
9429
- \uC9C0\uC6D0 \uC5B8\uC5B4: ${getSupportedLanguagesString()}
9430
- - fetch: \uAE30\uBCF8\uAC12 python
9431
- - test: solution.* \uD30C\uC77C\uB85C \uC790\uB3D9 \uAC10\uC9C0 (\uC9C0\uC815 \uC2DC \uB36E\uC5B4\uC4F0\uAE30)
9427
+ \uC8FC\uC694 \uC635\uC158:
9428
+ --language, -l \uC5B8\uC5B4 \uC120\uD0DD (${getSupportedLanguagesString()})
9429
+ --watch, -w \uD14C\uC2A4\uD2B8 watch \uBAA8\uB4DC (test \uC804\uC6A9)
9430
+ --help, -h \uBA85\uB839\uC5B4\uBCC4 \uB3C4\uC6C0\uB9D0
9432
9431
 
9433
- --watch, -w \uD14C\uC2A4\uD2B8 watch \uBAA8\uB4DC (test \uBA85\uB839\uC5B4 \uC804\uC6A9)
9434
- - solution.*, input*.txt, output*.txt \uD30C\uC77C \uBCC0\uACBD \uAC10\uC9C0
9435
- - \uBCC0\uACBD \uC2DC \uC790\uB3D9\uC73C\uB85C \uD14C\uC2A4\uD2B8 \uC7AC\uC2E4\uD589
9432
+ \uBE60\uB978 \uC2DC\uC791:
9433
+ $ ps init # \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654
9434
+ $ ps fetch 1000 # \uBB38\uC81C \uAC00\uC838\uC624\uAE30
9435
+ $ ps test # \uD14C\uC2A4\uD2B8 \uC2E4\uD589
9436
+ $ ps submit # \uC81C\uCD9C
9436
9437
 
9437
- --help, -h \uBA85\uB839\uC5B4\uBCC4 \uB3C4\uC6C0\uB9D0 \uD45C\uC2DC
9438
-
9439
- \uC608\uC81C:
9440
- $ ps fetch 1000
9441
- $ ps test 1000 --watch
9442
- $ ps help
9443
- $ ps fetch --help
9438
+ \uC790\uC138\uD55C \uB3C4\uC6C0\uB9D0:
9439
+ $ ps <\uBA85\uB839\uC5B4> --help
9444
9440
  `;
9445
9441
  }
9446
9442
  var cli = meow(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhseung/ps-cli",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "백준(BOJ) 문제 해결을 위한 통합 CLI 도구",
5
5
  "type": "module",
6
6
  "bin": {