@simplysm/sd-claude 13.0.84 → 13.0.86
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 +160 -30
- package/claude/rules/sd-claude-rules.md +14 -9
- package/claude/rules/sd-library-issue.md +12 -0
- package/claude/rules/sd-readme.md +5 -0
- package/claude/sd-statusline.py +5 -2
- package/claude/skills/sd-audit/SKILL.md +133 -0
- package/claude/skills/sd-check/SKILL.md +110 -44
- package/claude/skills/sd-commit/SKILL.md +121 -32
- package/claude/skills/sd-debug/SKILL.md +96 -82
- package/claude/skills/sd-document/SKILL.md +64 -58
- package/claude/skills/sd-document/_common.py +1 -6
- package/claude/skills/sd-document/extract_docx.py +0 -1
- package/claude/skills/sd-document/extract_pdf.py +17 -25
- package/claude/skills/sd-document/extract_pptx.py +0 -1
- package/claude/skills/sd-document/extract_xlsx.py +2 -4
- package/claude/skills/sd-email-analyze/SKILL.md +33 -23
- package/claude/skills/sd-init/SKILL.md +99 -80
- package/claude/skills/sd-plan/SKILL.md +94 -69
- package/claude/skills/sd-plan-dev/SKILL.md +122 -0
- package/claude/skills/sd-readme/SKILL.md +147 -100
- package/claude/skills/sd-spec/SKILL.md +140 -0
- package/claude/skills/sd-spec/sections/api.md +85 -0
- package/claude/skills/sd-spec/sections/architecture.md +104 -0
- package/claude/skills/sd-spec/sections/db.md +99 -0
- package/claude/skills/sd-spec/sections/process.md +98 -0
- package/claude/skills/sd-spec/sections/ui.md +146 -0
- package/claude/skills/sd-test/SKILL.md +116 -0
- package/claude/skills/sd-use/SKILL.md +149 -0
- package/package.json +4 -1
- package/scripts/cli.mjs +12 -0
- package/scripts/postinstall.mjs +20 -4
- package/claude/rules/sd-simplysm-usage.md +0 -7
- package/claude/skills/sd-api-review/SKILL.md +0 -89
- package/claude/skills/sd-review/SKILL.md +0 -65
- package/claude/skills/sd-simplify/SKILL.md +0 -59
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Extract text, tables, and images from PDF files page by page."""
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import struct
|
|
5
|
+
import logging
|
|
5
6
|
from _common import (
|
|
6
7
|
setup_encoding, make_output_paths, print_header, save_image,
|
|
7
8
|
print_image_summary, run_cli, normalize_cell,
|
|
@@ -40,35 +41,26 @@ def extract(file_path):
|
|
|
40
41
|
print("| " + " | ".join(cells) + " |")
|
|
41
42
|
print()
|
|
42
43
|
|
|
43
|
-
# Image extraction (pypdf)
|
|
44
|
+
# Image extraction (pypdf page.images API)
|
|
45
|
+
logging.getLogger("pypdf").setLevel(logging.ERROR)
|
|
44
46
|
reader = PdfReader(file_path)
|
|
45
47
|
for page_num, page in enumerate(reader.pages, 1):
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if "/DCTDecode" in filter_str:
|
|
59
|
-
ext = "jpg"
|
|
60
|
-
elif "/JPXDecode" in filter_str:
|
|
61
|
-
ext = "jp2"
|
|
62
|
-
try:
|
|
63
|
-
img_path = save_image(out_dir, img_idx, obj.get_data(), ext)
|
|
64
|
-
except Exception as exc:
|
|
65
|
-
print(f"Warning: failed to decode image {img_idx}: {exc}", file=sys.stderr)
|
|
66
|
-
img_path = save_image(out_dir, img_idx, obj._data if hasattr(obj, "_data") else b"", "bin")
|
|
67
|
-
print(f"[IMG] (page={page_num}) {img_path}")
|
|
48
|
+
for img in page.images:
|
|
49
|
+
data = img.data
|
|
50
|
+
# Filter small mask/decorative images by checking PNG IHDR dimensions
|
|
51
|
+
if data[:4] == b'\x89PNG' and len(data) >= 24:
|
|
52
|
+
w = struct.unpack('>I', data[16:20])[0]
|
|
53
|
+
h = struct.unpack('>I', data[20:24])[0]
|
|
54
|
+
if w <= 4 or h <= 4:
|
|
55
|
+
continue
|
|
56
|
+
ext = img.name.rsplit('.', 1)[-1] if '.' in img.name else "png"
|
|
57
|
+
img_idx += 1
|
|
58
|
+
img_path = save_image(out_dir, img_idx, data, ext)
|
|
59
|
+
print(f"[IMG] (page={page_num}) {img_path}")
|
|
68
60
|
|
|
69
61
|
print()
|
|
70
62
|
print_image_summary(img_idx, out_dir)
|
|
71
63
|
|
|
72
64
|
|
|
73
65
|
if __name__ == "__main__":
|
|
74
|
-
run_cli(extract, "extract_pdf.py", {"pdfplumber": "pdfplumber", "pypdf": "pypdf"})
|
|
66
|
+
run_cli(extract, "extract_pdf.py", {"pdfplumber": "pdfplumber", "pypdf": "pypdf", "Pillow": "PIL"})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Extract data and images from XLSX files with cell positions."""
|
|
3
3
|
|
|
4
|
-
import sys
|
|
5
4
|
from _common import (
|
|
6
5
|
setup_encoding, make_output_paths, print_header, save_image,
|
|
7
6
|
print_image_summary, run_cli,
|
|
@@ -24,12 +23,11 @@ def extract(file_path):
|
|
|
24
23
|
print(f"## Sheet: {sheet_name}\n")
|
|
25
24
|
|
|
26
25
|
# Data extraction
|
|
27
|
-
|
|
28
|
-
if not rows:
|
|
26
|
+
if ws.max_row is None or ws.max_row == 0:
|
|
29
27
|
print("(empty sheet)\n")
|
|
30
28
|
continue
|
|
31
29
|
|
|
32
|
-
for row in
|
|
30
|
+
for row in ws.iter_rows(values_only=False):
|
|
33
31
|
cells = []
|
|
34
32
|
for cell in row:
|
|
35
33
|
val = cell.value
|
|
@@ -1,44 +1,54 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-email-analyze
|
|
3
|
-
description:
|
|
3
|
+
description: 이메일 파일(.eml/.msg)을 분석하여 헤더, 본문, 인라인 이미지, 첨부파일을 추출. 사용자가 .eml/.msg 파일의 내용 확인이나 분석을 요청할 때 사용
|
|
4
|
+
argument-hint: "<이메일 파일 경로>"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
+
# sd-email-analyze: 이메일 파일 분석 및 내용 추출
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
`.eml` 및 `.msg`(Outlook) 이메일 파일을 파싱하여 메일 헤더, 본문, 인라인 이미지, 첨부파일을 추출하고 분석한다.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
## 1. 인자 파싱
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
`$ARGUMENTS`에서 이메일 파일 경로를 추출한다.
|
|
14
|
+
- `$ARGUMENTS`가 비어있으면 현재 대화 맥락에서 이메일 파일 경로를 파악한다. 대화 맥락도 없으면 AskUserQuestion으로 파일 경로를 요청한다
|
|
15
|
+
- 지원 형식: `.eml`, `.msg`
|
|
16
|
+
- 파일이 존재하지 않거나 지원하지 않는 확장자이면 AskUserQuestion으로 올바른 경로를 요청한다
|
|
13
17
|
|
|
14
|
-
##
|
|
18
|
+
## 2. 이메일 파일 파싱
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
다음 명령을 실행하여 이메일 파일을 파싱한다:
|
|
17
21
|
|
|
18
22
|
```bash
|
|
19
|
-
python
|
|
23
|
+
python ${CLAUDE_SKILL_DIR}/email-analyzer.py <이메일_파일_경로>
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
26
|
+
- 최초 실행 시 `extract-msg` 패키지가 자동 설치된다
|
|
27
|
+
- 출력은 마크다운 리포트(stdout)이며, 추출된 파일은 `<이메일_파일명>_files/` 디렉토리에 저장된다
|
|
28
|
+
|
|
29
|
+
### 출력 구조
|
|
30
|
+
|
|
31
|
+
| 섹션 | 내용 |
|
|
32
|
+
|------|------|
|
|
33
|
+
| Email Info | Subject, From, To, CC, Date, 첨부파일 수 |
|
|
34
|
+
| Body | 본문 텍스트 (plain text 우선, 없으면 HTML 스트립) |
|
|
35
|
+
| Inline Images | 저장된 인라인 이미지 파일 경로 테이블 |
|
|
36
|
+
| Attachments | 저장된 첨부파일 경로 테이블 |
|
|
24
37
|
|
|
25
|
-
|
|
38
|
+
## 3. 추출 파일 분석
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
2. **Body Text**: Plain text (if plain text is unavailable, HTML tags are stripped)
|
|
29
|
-
3. **Inline Images**: Table of saved file paths
|
|
30
|
-
4. **Attachments**: Table of saved file paths
|
|
40
|
+
2단계 출력의 파일 경로를 확인하고 다음을 수행한다. 인라인 이미지 확인과 첨부파일 분석은 독립적이므로 가능한 한 병렬로 수행한다.
|
|
31
41
|
|
|
32
|
-
|
|
42
|
+
### 인라인 이미지
|
|
33
43
|
|
|
34
|
-
|
|
44
|
+
Read 도구로 각 저장 경로의 이미지를 확인한다.
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
2. **Attachments**: Use the **Read** tool (for images) or the **sd-document** skill script (for DOCX, XLSX, PPTX, PDF)
|
|
46
|
+
### 첨부파일
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
- 이미지 파일: Read 도구로 확인
|
|
49
|
+
- 문서 파일(DOCX, XLSX, PPTX, PDF): `/sd-document` 스킬로 분석
|
|
40
50
|
|
|
41
|
-
|
|
51
|
+
## 4. 완료 안내
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
2
|
|
53
|
+
분석이 완료되면 다음을 출력한다:
|
|
54
|
+
- 3단계에서 수행한 파일별 분석 결과 요약 (2단계에서 이미 출력된 이메일 기본 정보는 반복하지 않는다)
|
|
@@ -1,133 +1,152 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-init
|
|
3
|
-
description:
|
|
3
|
+
description: 프로젝트 설정 파일을 분석하여 CLAUDE.md를 자동 생성. 사용자가 CLAUDE.md 생성이나 갱신을 요청할 때 사용
|
|
4
|
+
argument-hint: ""
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
+
# sd-init: CLAUDE.md 자동 생성
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
프로젝트를 분석하여 CLAUDE.md를 생성한다. 기존 파일이 있으면 비교하여 병합한다.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
1~3단계는 독립적이므로 병렬로 수행할 수 있다.
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## 1. 패키지 매니저 감지
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
프로젝트 루트의 lock 파일로 패키지 매니저를 판별한다:
|
|
15
16
|
|
|
16
17
|
1. `pnpm-lock.yaml` → pnpm
|
|
17
18
|
2. `yarn.lock` → yarn
|
|
18
|
-
3.
|
|
19
|
+
3. `bun.lock` 또는 `bun.lockb` → bun
|
|
20
|
+
4. 그 외 → npm
|
|
21
|
+
|
|
22
|
+
## 2. 스크립트 분석
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
`package.json`의 `scripts` 섹션을 Read하고, 각 스크립트가 실행하는 CLI 도구를 분석한다.
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
- 잘 알려진 도구(`tsc`, `vitest`, `eslint`, `prettier`, `playwright` 등)를 직접 실행하는 경우: 실행 내용을 그대로 기록
|
|
27
|
+
- 프로젝트 내부 CLI나 커스텀 스크립트(예: `tsx packages/.../cli.ts`)를 실행하는 경우: Bash로 `--help`를 붙여 실행(timeout 5초)하여 사용 가능한 서브커맨드와 주요 옵션을 파악. 실패하면 scripts 내용만 기록
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
이 단계에서는 정보 수집만 수행한다. 최종 포맷팅은 4단계에서 한다.
|
|
25
30
|
|
|
26
|
-
##
|
|
31
|
+
## 3. 코딩룰 분석
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
프로젝트 루트에서 다음 설정 파일을 찾아 존재하는 것만 Read한다:
|
|
29
34
|
|
|
30
|
-
- ESLint: `eslint.config.*`, `.eslintrc
|
|
35
|
+
- ESLint: 프로젝트 루트의 `eslint.config.*`, `.eslintrc.*`
|
|
31
36
|
- Prettier: `.prettierrc*`, `prettier.config.*`
|
|
32
37
|
- EditorConfig: `.editorconfig`
|
|
33
|
-
- TypeScript:
|
|
38
|
+
- TypeScript: 루트 `tsconfig.json`의 `compilerOptions`
|
|
34
39
|
- Stylelint: `.stylelintrc*`, `stylelint.config.*`
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
다음 기준으로 규칙을 선별하여 요약한다:
|
|
42
|
+
- 기본값과 다른 설정 (예: `verbatimModuleSyntax: true`)
|
|
43
|
+
- error 레벨의 비표준 규칙 (예: `no-console: error`)
|
|
44
|
+
- 특정 API 사용 금지/강제 규칙 (예: `Buffer` 금지 → `Uint8Array` 사용)
|
|
37
45
|
|
|
38
|
-
##
|
|
46
|
+
## 4. CLAUDE.md 생성
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
1~3단계에서 수집한 정보를 종합하여 CLAUDE.md 내용을 생성한다. 이미 읽은 파일은 다시 읽지 않는다.
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
- **PM**: Package manager detected in Step 1
|
|
44
|
-
- **Monorepo structure**: If a `workspaces` field or `pnpm-workspace.yaml` exists, briefly describe the workspace paths
|
|
45
|
-
- **Tech stack**: Identify key technologies (frameworks, bundlers, test tools, etc.) from `dependencies`/`devDependencies` and describe them very briefly
|
|
46
|
-
- **Commands**: Script usage organized in Step 2
|
|
47
|
-
- **Coding rules**: Rules from Step 3 that Claude should follow. Write as a `## Coding Rules` section
|
|
50
|
+
포함할 내용:
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
- **프로젝트 정보**: `package.json`의 `name`, `description`, 패키지 매니저
|
|
53
|
+
- **모노레포 구조**: `workspaces` 필드나 `pnpm-workspace.yaml`이 있으면 워크스페이스 경로를 간략히 기술
|
|
54
|
+
- **기술 스택**: `dependencies`/`devDependencies`에서 프레임워크, 번들러, 테스트 도구 등 주요 라이브러리를 나열 (최대 10개)
|
|
55
|
+
- **명령어**: 2단계에서 수집한 스크립트를 카테고리별로 bash 코드블록에 사용 예시로 포맷팅
|
|
56
|
+
- **코딩룰**: 3단계에서 선별한 규칙을 불릿 리스트로 작성
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
### 참고 예시
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
아래 예시의 **섹션 구성과 포맷팅 스타일**(bash 코드블록, 인라인 주석, 불릿 리스트)을 따르되, 내용은 대상 프로젝트에 맞게 작성한다. 예시에 없는 섹션을 추가하거나, 프로젝트에 해당하지 않는 섹션은 생략할 수 있다.
|
|
61
|
+
|
|
62
|
+
````markdown
|
|
54
63
|
# Simplysm
|
|
55
64
|
|
|
56
|
-
pnpm
|
|
65
|
+
pnpm 모노레포. 패키지 경로: `packages/*`, 테스트: `tests/*`
|
|
57
66
|
|
|
58
|
-
##
|
|
67
|
+
## 명령어
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
모든 명령어는 내부적으로 `pnpm sd-cli <command>`를 실행한다. `--debug` 플래그를 모든 명령어에 사용할 수 있다.
|
|
70
|
+
`[targets..]`를 지정하지 않으면 `sd.config.ts`에 정의된 모든 패키지가 대상이 된다.
|
|
71
|
+
대상은 패키지 경로로 지정한다 (예: `packages/core-common`, `tests/orm`).
|
|
63
72
|
|
|
64
|
-
###
|
|
73
|
+
### 개발
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
pnpm dev [targets..] #
|
|
68
|
-
pnpm dev packages/solid-demo #
|
|
69
|
-
pnpm dev -o key=value #
|
|
75
|
+
```bash
|
|
76
|
+
pnpm dev [targets..] # 클라이언트+서버 패키지를 개발 모드로 실행
|
|
77
|
+
pnpm dev packages/solid-demo # 특정 패키지만 개발 모드로 실행
|
|
78
|
+
pnpm dev -o key=value # sd.config.ts에 옵션 전달
|
|
70
79
|
|
|
71
|
-
pnpm watch [targets..] #
|
|
72
|
-
pnpm watch packages/core-common #
|
|
73
|
-
|
|
80
|
+
pnpm watch [targets..] # 라이브러리 패키지 빌드 watch 모드
|
|
81
|
+
pnpm watch packages/core-common # 특정 패키지만 watch
|
|
82
|
+
```
|
|
74
83
|
|
|
75
|
-
###
|
|
84
|
+
### 빌드 & 배포
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
pnpm build [targets..] #
|
|
79
|
-
pnpm build packages/solid #
|
|
86
|
+
```bash
|
|
87
|
+
pnpm build [targets..] # 프로덕션 빌드
|
|
88
|
+
pnpm build packages/solid # 특정 패키지만 빌드
|
|
80
89
|
|
|
81
|
-
pnpm pub [targets..] #
|
|
82
|
-
pnpm pub --no-build #
|
|
83
|
-
pnpm pub --dry-run #
|
|
84
|
-
|
|
90
|
+
pnpm pub [targets..] # 빌드 후 배포 (npm/sftp)
|
|
91
|
+
pnpm pub --no-build # 빌드 없이 배포만
|
|
92
|
+
pnpm pub --dry-run # 실제 배포 없이 시뮬레이션
|
|
93
|
+
```
|
|
85
94
|
|
|
86
|
-
###
|
|
95
|
+
### 코드 품질 검사
|
|
87
96
|
|
|
88
|
-
|
|
89
|
-
pnpm typecheck [targets..] # TypeScript
|
|
90
|
-
pnpm lint [targets..] #
|
|
91
|
-
pnpm lint:fix [targets..] #
|
|
92
|
-
pnpm check [targets..] #
|
|
93
|
-
pnpm vitest [targets..] # vitest watch
|
|
94
|
-
pnpm vitest run [targets..] #
|
|
95
|
-
|
|
97
|
+
```bash
|
|
98
|
+
pnpm typecheck [targets..] # TypeScript 타입 검사
|
|
99
|
+
pnpm lint [targets..] # ESLint + Stylelint 실행
|
|
100
|
+
pnpm lint:fix [targets..] # 린트 이슈 자동 수정 (--fix)
|
|
101
|
+
pnpm check [targets..] # 전체 검사 (타입 검사 + 린트 + 테스트 병렬 실행)
|
|
102
|
+
pnpm vitest [targets..] # vitest watch 모드
|
|
103
|
+
pnpm vitest run [targets..] # 테스트 1회 실행
|
|
104
|
+
```
|
|
96
105
|
|
|
97
|
-
##
|
|
106
|
+
## 아키텍처
|
|
98
107
|
|
|
99
|
-
|
|
108
|
+
의존 방향: 위 → 아래. `core-common`은 내부 의존성이 없는 리프 패키지이다.
|
|
100
109
|
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
```
|
|
111
|
+
앱: solid-demo (클라이언트) / solid-demo-server (서버)
|
|
103
112
|
UI: solid (SolidJS + Tailwind)
|
|
104
|
-
|
|
113
|
+
서비스: service-server (Fastify) / service-client / service-common
|
|
105
114
|
ORM: orm-node (MySQL/PostgreSQL/MSSQL) / orm-common
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
코어: core-common (중립) / core-browser / core-node
|
|
116
|
+
도구: sd-cli, lint, excel, storage, sd-claude, mcp-playwright
|
|
117
|
+
```
|
|
109
118
|
|
|
119
|
+
## 통합 테스트
|
|
110
120
|
|
|
111
|
-
|
|
121
|
+
`tests/` 폴더에 위치한다. `pnpm vitest run tests/orm` 등으로 실행한다.
|
|
112
122
|
|
|
113
|
-
|
|
123
|
+
- `tests/orm` — DB 연결, DbContext, escape 테스트 (MySQL, PostgreSQL, MSSQL). Docker 필요.
|
|
124
|
+
- `tests/service` — 서비스 클라이언트-서버 통신 테스트.
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
- `tests/service` — Service client-server communication tests.
|
|
126
|
+
## 코딩룰
|
|
117
127
|
|
|
118
|
-
|
|
128
|
+
- `import type` 필수 (`verbatimModuleSyntax`), `#private` 금지 → `private` 키워드 사용
|
|
129
|
+
- `console.*` 금지, `if (str)` 금지 → 명시적 비교 `str !== ""` 사용 (nullable boolean/object는 허용)
|
|
130
|
+
- `Buffer` 금지 → `Uint8Array`, `events` 금지 → `@simplysm/core-common`의 `EventEmitter` 사용
|
|
131
|
+
- SolidJS: props 구조분해 금지, `.map()` 대신 `<For>` 사용, `className` 대신 `class` 사용
|
|
132
|
+
- Prettier: 100자, 2칸 들여쓰기, 세미콜론, trailing comma, LF
|
|
133
|
+
````
|
|
119
134
|
|
|
120
|
-
|
|
121
|
-
- `console.*` forbidden, `if (str)` forbidden → use explicit comparison `str !== ""` (nullable boolean/object allowed)
|
|
122
|
-
- `Buffer` forbidden → `Uint8Array`, `events` forbidden → `EventEmitter` from `@simplysm/core-common`
|
|
123
|
-
- SolidJS: no props destructuring, use `<For>` instead of `.map()`, use `class` instead of `className`
|
|
124
|
-
- Prettier: 100 chars, 2-space indent, semicolons, trailing comma, LF
|
|
125
|
-
```
|
|
135
|
+
## 5. 기존 CLAUDE.md와 병합
|
|
126
136
|
|
|
127
|
-
|
|
137
|
+
- 기존 `CLAUDE.md`가 없으면 4단계의 결과를 그대로 저장한다
|
|
138
|
+
- 기존 `CLAUDE.md`가 있으면:
|
|
139
|
+
1. 기존 파일을 Read한다
|
|
140
|
+
2. 4단계에서 생성한 새 내용과 기존 내용을 섹션(`##` 헤딩) 단위로 비교한다
|
|
141
|
+
3. 병합 규칙:
|
|
142
|
+
- 4단계에서 생성한 섹션과 동일 주제의 기존 섹션이 있으면 → 새 내용으로 교체
|
|
143
|
+
- 기존에만 있고 4단계에서 생성하지 않은 섹션 → 그대로 보존
|
|
144
|
+
- 기존 섹션의 위치를 유지하되, 새로 추가된 섹션은 관련 섹션 근처에 배치
|
|
128
145
|
|
|
129
|
-
|
|
146
|
+
## 6. 완료 안내
|
|
130
147
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
148
|
+
저장이 완료되면 생성/업데이트된 파일 경로를 출력한다.
|
|
149
|
+
|
|
150
|
+
## 7. 커밋
|
|
151
|
+
|
|
152
|
+
수정된 파일이 있으면 `/sd-commit`을 실행하여 자동 커밋한다.
|
|
@@ -1,104 +1,129 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-plan
|
|
3
|
-
description:
|
|
3
|
+
description: 요구분석서 또는 점검 결과를 기반으로 TDD 방식의 구현계획서를 작성. 사용자가 구현계획/plan 작성을 요청할 때 사용
|
|
4
|
+
argument-hint: "<spec/audit 파일 경로 [R번호]> 또는 <간단한 요구사항>"
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
#
|
|
7
|
+
# sd-plan: 구현계획서 작성
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
요구분석서(spec) 또는 점검 결과(audit)를 기반으로 TDD 방식의 세부 구현 계획을 수립한다.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
## 1. 인자 파싱
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
`$ARGUMENTS`를 분석하여 호출 방식을 결정한다.
|
|
13
14
|
|
|
14
|
-
-
|
|
15
|
-
1. **Task request**: The task description provided by the user when invoking the skill
|
|
16
|
-
2. **Current conversation**: If no task request is provided, determine the task from the current conversation context
|
|
17
|
-
3. **AskUserQuestion**: If neither of the above is sufficient, ask "What task should I create a plan for? Please describe the task."
|
|
18
|
-
- Proceed to Step 2 after obtaining a sufficient task description.
|
|
15
|
+
### 1-1. spec/audit 파일 경로 (+ 선택적 R번호)
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
`$ARGUMENTS`에 `.md`로 끝나는 경로가 포함된 경우:
|
|
18
|
+
- 해당 파일을 Read한다
|
|
19
|
+
- 경로 뒤에 `R숫자` 또는 숫자만 있으면 해당 R항목만 대상으로 한다
|
|
20
|
+
- 예: `.tasks/260314143000_example/spec.md R2` → R2만 대상
|
|
21
|
+
- 예: `.tasks/260314143000_example/spec.md 3` → R3만 대상
|
|
22
|
+
- 경로만 있으면 전체 요구사항을 대상으로 한다
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
### 1-2. 인자 없음
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
`$ARGUMENTS`가 비어있으면:
|
|
27
|
+
- 현재 대화 맥락에서 spec/audit 내용을 파악한다
|
|
28
|
+
- 대화에도 spec/audit가 없으면 AskUserQuestion으로 spec 또는 review 파일 경로, 또는 요구사항을 요청한다
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
- For code tasks → Write test code first
|
|
28
|
-
- For non-code tasks → Define a self-verification checklist first
|
|
29
|
-
- For code tasks where the project has no test environment set up → Propose verification methods such as CLI or dry-run
|
|
30
|
+
### 1-3. 간단한 요구사항 텍스트
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
위 조건에 해당하지 않으면 (`.md` 경로가 아닌 일반 텍스트):
|
|
33
|
+
- spec/audit 없이 해당 텍스트를 요구사항으로 직접 사용한다
|
|
34
|
+
- 이 경우 spec/audit 참조 없이 바로 plan을 수립한다
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
## 2. 요구사항 분석 및 작업 계획
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- For each item, repeat "present one explanation -> AskUserQuestion"
|
|
39
|
-
4. **Apply**: Incorporate all answers to update the plan, then return to step 1.
|
|
38
|
+
요구사항을 독립적 기능 단위로 작업을 분리하고, 각 작업의 유형을 분류하여 테스트 전략을 결정한다.
|
|
39
|
+
- 각 작업은 하나의 독립적인 TDD 사이클로 처리할 수 있는 크기여야 한다
|
|
40
|
+
- 작업 간 의존성이 있으면 의존성을 명시한다
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
**작업 유형별 테스트 전략:**
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
| 작업 유형 | 테스트 전략 |
|
|
45
|
+
|----------|-----------|
|
|
46
|
+
| 코드 작업 (로직) | 프로젝트 테스트 환경(vitest) 확인 → 있으면 테스트 코드 작성 계획 |
|
|
47
|
+
| 코드 작업 (로직, 테스트 환경 없음) | subagent를 통한 직접 테스트 방안 계획 (sd-plan-dev에서 `_test.md` 작성) |
|
|
48
|
+
| 코드 작업 (비로직, 텍스트 변경 등) | 테스트 생략 가능 |
|
|
49
|
+
| 비코드 작업 (LLM용 문서) | subagent를 통한 테스트 방안 계획 (sd-plan-dev에서 `_test.md` 작성) |
|
|
50
|
+
| 비코드 작업 (일반 문서) | 테스트 생략 가능 |
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
**테스트 시나리오 작성 원칙:**
|
|
53
|
+
- 테스트는 **상태(정적)가 아닌 동작**을 검증한다
|
|
54
|
+
- 상태 (X): "파일에 특정 텍스트가 적혀있는지 확인" → 정적 검사에 불과
|
|
55
|
+
- 현상 (O): "실행했을 때 기대한 동작이 나타나는지 확인" → 실제 동작 검증
|
|
56
|
+
- 예: LLM용 문서 테스트 시 "SKILL.md에 '테스트 재실행' 문구가 있는지"가 아니라 "LLM이 SKILL.md를 따라 실행했을 때 실제로 테스트를 재실행하는지"를 검증한다
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
## 3. 구현계획서 초안 작성
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
3. **Ambiguous scope**: IN/OUT scope is not defined
|
|
52
|
-
4. **Unspecified behavior**: Errors, invalid inputs, default values, etc. are not specified
|
|
53
|
-
5. **Unknown constraints**: Performance, compatibility, or platform requirements are unclear
|
|
54
|
-
6. **Missing edge cases**: Boundary conditions, concurrency, empty states, etc.
|
|
55
|
-
7. **Vague file/function references**: "Modify related files" without specific paths
|
|
56
|
-
8. **Unclear ordering/dependencies**: Precedence between steps is not specified
|
|
57
|
-
9. **Speculative expressions**: "Probably", "might be", "TBD", "???", etc.
|
|
58
|
-
10. **Missing integration details**: API contracts, data formats, interfaces are undefined
|
|
59
|
-
11. **No failure/rollback strategy**: No response plan for failures
|
|
60
|
-
12. **Undefined verification methods**: No verification method corresponding to an implementation step
|
|
60
|
+
분석 결과를 바탕으로 아래 고정 구조의 구현계획서 초안을 작성한다.
|
|
61
|
+
불명확한 부분이 있더라도 최선의 판단으로 초안을 완성한다.
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
```markdown
|
|
64
|
+
# 구현계획서: {제목}
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
**참조 문서:** `{참조 문서 경로}` {R번호}
|
|
67
|
+
**대상:** `{대상 파일/패키지 경로}` {신규 작성/수정}
|
|
68
|
+
**작업 유형:** {유형} → {테스트 전략 요약}
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
## 작업 분석
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
2. Pay special attention to the following:
|
|
70
|
-
- Are there any parts that Claude decided on its own without user confirmation?
|
|
71
|
-
- Do all definitive statements (e.g., "will do X", "will handle as Y") have supporting evidence from user statements or the codebase?
|
|
72
|
-
- Are there any places missing specific file paths, function names, or data structures?
|
|
73
|
-
3. If **even one** unclear item is found during this verification, return to the question cycle in Step 2.
|
|
74
|
-
4. If truly none remain → Move to Step 3.
|
|
72
|
+
{요구사항을 기능 단위로 분리한 결과}
|
|
75
73
|
|
|
76
|
-
|
|
74
|
+
## TDD 계획
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
### RED Phase: {테스트 파일명} 작성 및 실패 확인
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
{테스트 시나리오 목록}
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
- Generate the timestamp first: `TS=$(date +%y%m%d%H%M%S)`
|
|
84
|
-
- Filename example: `260311143052_add-progress-component.md`
|
|
85
|
-
- `{topic}`: Short kebab-case based on the task content (e.g., add-progress-component)
|
|
80
|
+
### GREEN Phase: {구현 대상} 작성
|
|
86
81
|
|
|
87
|
-
|
|
82
|
+
{구현 계획 상세}
|
|
88
83
|
|
|
89
|
-
|
|
84
|
+
구현 후 테스트 재실행하여 통과 확인
|
|
90
85
|
|
|
91
|
-
|
|
86
|
+
### Refactor Phase
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
`/simplify` 하여 품질 개선 → 테스트 재실행하여 통과 확인
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**참조 문서 표기 규칙:**
|
|
92
|
+
- spec/audit 파일 경로로 호출된 경우: `**참조 문서:** {경로} {R번호}` 형식으로 상단에 명시
|
|
93
|
+
- 현재 대화의 spec/audit인 경우: `**참조 문서:** 현재 대화의 spec/audit` 으로 명시
|
|
94
|
+
- spec/audit 없이 호출된 경우: `**참조 문서:**` 줄 생략
|
|
95
|
+
|
|
96
|
+
**다중 작업인 경우:**
|
|
97
|
+
- 작업별로 `## 작업 1: {제목}`, `## 작업 2: {제목}` ... 으로 구분하고 각 작업 내에 작업 유형, TDD 계획 포함
|
|
98
|
+
- 작업 간 의존성이 있으면 `## 작업 의존성` 섹션에 명시
|
|
99
|
+
|
|
100
|
+
## 4. 초안 기반 검토 질문
|
|
101
|
+
|
|
102
|
+
초안은 사용자에게 출력하지 않는다 (최종본이 파일로 저장되므로 대화창 출력은 불필요).
|
|
103
|
+
불명확하거나 확인이 필요한 부분이 있으면 다음 프로세스를 반복한다:
|
|
104
|
+
|
|
105
|
+
1. 초안의 특정 부분을 인용하며 **자세한 설명을 텍스트로 먼저 출력**한다
|
|
106
|
+
- "초안에서 X를 Y로 계획했는데, Z 방식도 고려할 수 있습니다" 형식으로 구체적으로 질문한다
|
|
107
|
+
- 선택지 각각의 장단점, 트레이드오프를 설명한다
|
|
108
|
+
2. AskUserQuestion을 **1개만** 호출한다 (한번에 하나씩만 질문)
|
|
109
|
+
3. 답변을 반영하여 초안을 수정한다
|
|
110
|
+
4. 추가 확인이 필요하면 1번으로 돌아간다
|
|
111
|
+
|
|
112
|
+
불명확한 점이 없거나 충분히 확인되면 질문을 종료하고 파일 저장으로 넘어간다.
|
|
113
|
+
|
|
114
|
+
## 5. 파일 저장
|
|
115
|
+
|
|
116
|
+
- spec/audit 파일 기반 호출: 해당 문서와 동일 디렉토리에 저장. 전체면 `plan.md`, 특정 R항목이면 `{R번호}_plan.md` (예: `R2_plan.md`)
|
|
117
|
+
- 현재 대화의 spec/audit 기반이고 파일 경로가 있는 경우: 해당 문서와 동일 디렉토리에 저장. 파일명 규칙 동일
|
|
118
|
+
- spec/audit 없이 호출된 경우: 새 디렉토리 `.tasks/{yyMMddHHmmss}_{topic}/plan.md` 생성 (`yyMMddHHmmss`는 Bash `date +%y%m%d%H%M%S`, `{topic}`은 영문 kebab-case)
|
|
119
|
+
|
|
120
|
+
## 6. 완료 안내
|
|
100
121
|
|
|
101
|
-
|
|
122
|
+
문서 작성이 완료되면 다음을 출력한다:
|
|
123
|
+
- 완성된 문서의 파일 경로
|
|
124
|
+
- 사용자에게 직접 문서를 확인할 것을 권장
|
|
125
|
+
- 다음 단계 안내:
|
|
102
126
|
```
|
|
103
|
-
|
|
127
|
+
/sd-plan-dev
|
|
128
|
+
/sd-plan-dev --worktree # 별도 worktree에서 격리 실행
|
|
104
129
|
```
|