@simplysm/sd-claude 14.0.48 → 14.0.50

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,23 @@
1
+ #!/bin/bash
2
+ # 패키지 소스 파일을 하나의 텍스트 파일로 병합
3
+ # Usage: merge-source.sh <패키지경로> <출력파일경로>
4
+
5
+ pkg_path="$1"
6
+ output="$2"
7
+
8
+ if [ -z "$pkg_path" ] || [ -z "$output" ]; then
9
+ echo "Usage: $0 <package-path> <output-file>" >&2
10
+ exit 1
11
+ fi
12
+
13
+ mkdir -p "$(dirname "$output")"
14
+
15
+ files=$(find "$pkg_path/src" -name "*.ts" 2>/dev/null | sort)
16
+ [ -d "$pkg_path/scss" ] && files+=$'\n'$(find "$pkg_path/scss" -name "*.scss" 2>/dev/null | sort)
17
+
18
+ echo "$files" | while IFS= read -r f; do
19
+ [ -z "$f" ] && continue
20
+ echo "=== $f ==="
21
+ cat "$f"
22
+ echo
23
+ done > "$output"
@@ -0,0 +1,594 @@
1
+ # package-docs: 단일 패키지 문서 생성 지침
2
+
3
+ subagent가 한 패키지 경로를 받아 해당 패키지의 **CLAUDE.md**와 (private 패키지가 아니면) **README.md + docs/**를 생성·갱신한다. subagent는 이 한 파일만 읽으면 두 산출물을 모두 생성할 수 있다.
4
+
5
+ ## LLM 매뉴얼 원칙
6
+
7
+ 이 문서들은 **백과사전(wiki/API reference)이 아니라, 이 패키지를 소비하는 LLM(Claude Code)이 올바른 코드를 한 번에 쓰게 돕는 운영 매뉴얼**이다. 타겟 독자는 `Read` 툴로 md 파일을 로드해 소비자 코드를 작성하는 LLM 에이전트이며, 사람 개발자는 2차 독자다.
8
+
9
+ **우선순위**:
10
+
11
+ 1. **언제 쓰고 언제 쓰지 말아야 하는가** (When to use / When NOT to use)
12
+ 2. **전형적 호출 형태** (복붙 가능한 최소 예제 + 실전 예제)
13
+ 3. **자주 틀리는 지점** (🚫 anti-pattern + 근거)
14
+ 4. **정확한 시그니처** (호출에 필요한 수준까지)
15
+
16
+ 타입 사전처럼 "모든 필드를 다 채우는 것"이 목표가 아니다. 시그니처는 LLM이 소스에서도 읽을 수 있으므로, 문서는 **소스에 없는 정보**(의도·선택 기준·함정)에 집중한다.
17
+
18
+ ## 공통 규칙
19
+
20
+ ### 작성 원칙
21
+
22
+ - **대화언어 + 3인칭 서술**. "You can use…", "I can help…" 금지 → "Processes X", "Returns Y" 형태. "적절히", "필요에 따라" 같은 모호한 표현 금지.
23
+ - **소스에서 읽은 내용만** 문서화한다. 시그니처는 직접 복사하고, 존재하지 않는 파라미터·반환 타입·동작을 만들어내지 않는다 (hallucination 금지).
24
+ - **기존 문서의 시그니처를 신뢰하지 않는다**. 기존 README.md/docs/**/*.md의 코드블록을 그대로 재사용하지 않는다. 반드시 소스를 Read하여 확인한 내용만 작성한다.
25
+ - **일관된 용어**. 한 Entry 내에서 "Provider / Service / Module", "field / property / member" 같은 유사 용어를 혼용하지 않는다. LLM은 용어 동일성을 구조 신호로 사용한다.
26
+ - **상수에 근거**. 예제의 매직 넘버(`timeout: 30000`, `retries: 3` 등)에는 왜 그 값인지 1줄 주석을 단다. 근거 없는 상수는 LLM이 임의 값으로 변조한다.
27
+ - **엣지케이스까지**. 예제는 "happy path"만 보이고 에러·누락·기본값을 얼버무리지 않는다. 파일이 없을 때·네트워크 실패 시 처리까지 포함한다.
28
+
29
+ ### 병합 규칙
30
+
31
+ 기존 문서가 있으면 섹션(`##` 제목) 단위로 비교한다.
32
+
33
+ 1. 동일 주제의 기존 섹션 → 새 콘텐츠로 **대체**
34
+ 2. 대응 섹션이 없는 기존 섹션 → 그대로 **보존**
35
+ 3. 기존 섹션 위치를 유지하고, 새 섹션은 마지막 기존 섹션 **뒤에** 추가
36
+
37
+ ### 소스 분석 공유
38
+
39
+ CLAUDE.md의 "Key Patterns"와 README/docs의 Entry 문서는 동일한 소스 코드 분석에서 파생된다. 전달받은 **소스 병합 파일**을 Read하여 전체 소스를 한번에 파악하고, 두 산출물에 모두 활용한다. 추가 정보가 필요한 경우(다른 패키지의 타입 정의 등)에만 개별 Read를 수행한다.
40
+
41
+ ## CLAUDE.md 생성
42
+
43
+ 출력 경로: `{패키지 경로}/CLAUDE.md`
44
+
45
+ ### 최상단 안내 문구
46
+
47
+ `private: true`가 아닌 패키지인 경우, 제목(`# CLAUDE.md`) 바로 아래에 아래 인용 블록을 삽입한다. 이미 존재하면 갱신하지 않고 그대로 둔다.
48
+
49
+ ```markdown
50
+ > 이 패키지의 사용법 및 지침은 [README.md](./README.md) 및 [docs/](./docs/)를 참조한다.
51
+ ```
52
+
53
+ `private: true` 패키지는 이 문구를 삽입하지 않는다 (README.md/docs/가 생성되지 않으므로).
54
+
55
+ ### 분석 대상
56
+
57
+ 1. `package.json` — 이름, 설명, dependencies (Read)
58
+ 2. `tsconfig.json` — 패키지 고유 컴파일러 옵션 (Read)
59
+ 3. **소스 병합 파일** — 전달받은 경로를 Read하여 전체 소스를 한번에 분석. `=== 파일경로 ===` 구분자로 파일 경계를 식별하며, 디렉토리 구조·반복 패턴·export 체인·API 정보를 모두 이 파일에서 파악한다
60
+ 4. 테스트 디렉토리 (존재 시) — Glob으로 구조 확인 후 대표 파일 1~2개만 Read
61
+ 5. 추가 정보 필요 시 (다른 패키지의 타입 정의 등) — 개별 Read
62
+
63
+ ### 포함할 섹션
64
+
65
+ - **Package Overview**: 패키지명, 한 줄 설명, 소스 파일 수
66
+ - **Architecture**: `src/` 하위 디렉토리 트리, 각 디렉토리의 역할 설명
67
+ - **Key Patterns**: 소스 코드에서 반복되는 패턴을 코드 예시와 함께 기술. 패턴이 여러 개면 하위 섹션(`###`)으로 분리
68
+ - **Testing**: 테스트 디렉토리가 있으면 테스트 구조·패턴·규칙 기술. 없으면 섹션 생략
69
+ - 그 외 패키지 고유 정보 (예: 스타일링, 컴파일러 설정)
70
+
71
+ ### 제외할 내용
72
+
73
+ 아래는 루트 CLAUDE.md에만 포함한다. 패키지 CLAUDE.md에 반복하지 않는다:
74
+
75
+ - 명령어 (pnpm scripts)
76
+ - 프로젝트 전체 코딩 규칙 (lint, prettier 등)
77
+ - 패키지 매니저 정보
78
+ - 프로젝트 전체 기술 스택
79
+ - 루트와 동일한 컴파일러/빌드 설정 — 패키지에만 **고유한** 설정만 기술한다
80
+
81
+ subagent 프롬프트에서 전달받은 "루트 수준 설정" 목록과 중복되는 내용은 반복하지 않는다.
82
+
83
+ ## README.md + docs/ 생성
84
+
85
+ **`private: true` 패키지는 이 섹션 전체를 건너뛴다.**
86
+
87
+ 출력 경로: `{패키지 경로}/README.md` (분할 구조면 `{패키지 경로}/docs/{category}/{entry}.md` 트리 추가).
88
+
89
+ **구조 원칙**: 각 export된 class/component/함수(Entry)는 자체 md 파일로 분리한다. README.md는 **llms.txt 스타일 인덱스**(소비자가 어느 Entry를 열지 결정하는 길잡이) 역할에 집중하고, 상세는 각 Entry 파일에 둔다. Entry는 **self-contained**하게 작성한다 — 소비자가 필요한 Entry 파일 하나만 조회해도 올바른 코드를 작성할 수 있어야 한다.
90
+
91
+ **링크 규칙 (1-level deep)**: README → Entry까지만 링크한다. Entry 파일 본문에서 다른 Entry를 참조할 때는 "간단한 차이점 언급 + 링크"만 두고, 정의·세부 사용법을 그 링크에 떠넘기지 않는다. LLM이 부분 읽기(`offset/limit`)로 잘라 읽을 때 체인이 끊기면 정보가 유실된다.
92
+
93
+ ### 엔트리포인트 찾기
94
+
95
+ `package.json`의 `main` 또는 `exports` 필드에서 엔트리포인트 경로를 읽는다.
96
+ `dist/` 경로이면 `src/`로 변환하고 확장자를 소스 확장자(`.ts`, `.tsx`)로 변환한다.
97
+
98
+ ```
99
+ main: "./dist/index.js" → src/index.ts (또는 src/index.tsx)
100
+ ```
101
+
102
+ 엔트리포인트 파일이 존재하지 않으면 사용자에게 알리고 README.md/docs/ 생성을 건너뛴다.
103
+
104
+ ### Export 체인 재귀 추적
105
+
106
+ 소스 병합 파일 내에서 엔트리포인트 파일(`=== {경로} ===` 구분자로 식별)을 찾고, 아래 패턴을 추적한다:
107
+
108
+ | 패턴 | 처리 |
109
+ |------|------|
110
+ | `export * from "./path"` | 병합 파일 내 해당 파일 섹션에서 모든 export 수집 |
111
+ | `export * as name from "./path"` | namespace export로 기록하고, 해당 파일의 export 수집 |
112
+ | `export { A, B } from "./path"` | 명시된 항목만 수집 |
113
+ | `export class/function/type/interface/const/enum` | 직접 export로 기록 |
114
+ | `import "./path"` (side-effect import) | 부수효과 모듈로 기록 (prototype extension 등) |
115
+
116
+ 상대 경로를 병합 파일 내 파일 경로와 매칭한다. 확장자 생략 시 `.ts`, `.tsx`, `/index.ts`, `/index.tsx` 순서로 탐색한다.
117
+
118
+ ### 카테고리 수집
119
+
120
+ 엔트리포인트 파일의 `//#region {name}` ~ `//#endregion` 주석을 파싱하여 카테고리를 수집한다. region 주석이 없으면 re-export되는 파일의 디렉토리 구조를 카테고리로 사용한다.
121
+
122
+ ### API 정보 수집
123
+
124
+ 소스 병합 파일에서 추적된 각 파일의 export 항목 정보를 수집한다:
125
+
126
+ - **이름**: export 식별자
127
+ - **종류**: class, function, type, interface, const, enum
128
+ - **시그니처**: 타입 파라미터, 매개변수, 반환 타입
129
+ - **JSDoc**: `/** ... */` 주석이 있으면 설명으로 활용
130
+ - **카테고리**: 위에서 수집한 region 또는 디렉토리 기반
131
+
132
+ ### Entry 그룹핑 (매뉴얼 페이지 단위)
133
+
134
+ 수집된 export를 **Entry**(= 분할 시 1개 md 파일이 되는 단위)로 그룹핑한다. Entry는 LLM이 매뉴얼 한 페이지로 로드하는 응집 단위다.
135
+
136
+ **그룹핑 규칙 (위에서부터 순차 적용):**
137
+
138
+ 1. **Anchor 선정**: export된 class/component/directive/대표 함수를 anchor로 삼는다. Anchor 하나당 Entry 1개.
139
+ 2. **Prefix 매칭으로 흡수**: anchor 이름(또는 `I`·`T` 접두사를 제거한 식별자)으로 **시작하는 이름**을 가진 interface/type/enum/const는 해당 anchor Entry에 흡수된다.
140
+ - 예: anchor `FtpStorage` → `FtpStorageConfig`, `FtpStorageOption`, `TFtpStorageMode`, `IFtpStorageEntry`, `FTP_STORAGE_*` 상수 모두 같은 Entry
141
+ 3. **Anchor 시그니처 참조 타입 흡수**: anchor의 public 멤버(파라미터/반환 타입/프로퍼티 타입)에서 참조되며 **다른 anchor에서는 참조되지 않는** 타입은 해당 anchor Entry에 흡수된다.
142
+ 4. **Standalone Entry**: 어느 anchor에도 흡수되지 않은 export(독립 함수, 공용 interface, 독립 상수 등)는 각자 1개의 Entry가 된다.
143
+ 5. **유틸 클러스터**: 상호 참조가 강한 유틸 타입 쌍(예: `DateTime`·`DateOnly`·`Time`처럼 3개 이하가 서로를 타입 매개변수로 사용하는 경우)은 알파벳순 첫 항목을 anchor로 삼아 하나의 Entry로 묶는다.
144
+
145
+ **Entry 정보:**
146
+
147
+ - `name`: anchor 식별자 (예: `DbContext`, `FtpStorage`)
148
+ - `kebabName`: 파일명용 kebab-case (예: `db-context`, `ftp-storage`). standalone Entry는 해당 export 이름을 kebab-case로 변환
149
+ - `category`: 위에서 수집한 카테고리
150
+ - `kind`: anchor의 종류 (class/component/directive/function/interface/type/const/enum)
151
+ - `members`: 이 Entry에 포함된 모든 export 목록
152
+
153
+ ### 스타일 에셋 분석
154
+
155
+ `package.json`에 `style` 필드가 있거나 `files` 배열에 `"scss"`가 포함된 경우에만 수행한다. 둘 다 아니면 건너뛴다.
156
+
157
+ 소스 병합 파일에 `scss/**/*.scss` 파일이 포함되어 있으므로, 병합 파일 내에서 분석한다.
158
+
159
+ **SCSS 파일 탐색**: 병합 파일 내 `scss/` 경로의 엔트리포인트(`scss/styles.scss` 등)부터 `@use`/`@forward` 체인을 따라 모든 SCSS 파일을 수집한다.
160
+
161
+ **스타일 API 수집** (병합 파일 내 SCSS 파일에서):
162
+
163
+ | 항목 | 추출 대상 | 예시 |
164
+ |------|-----------|------|
165
+ | CSS 클래스 | 최상위 선택자로 정의된 클래스 (컴포넌트 내부 중첩 제외) | `.flex-row`, `.flex-fill` |
166
+ | CSS 커스텀 프로퍼티 | `:root` 또는 테마 클래스에서 선언된 `--*` 변수 | `--color-primary`, `--font-size` |
167
+ | 테마 | 테마 전환 클래스(프로젝트 네이밍 관례에 따름)와 해당 클래스가 오버라이드하는 변수 목록 | `.theme-dark`, `.sd-theme-*` 등 |
168
+ | 공개 mixin/function | `@mixin`, `@function` 중 `_`로 시작하지 않는 것 | `@mixin flex-direction($dir)` |
169
+
170
+ 카테고리 "Styling"으로 분류하고 하위 분류(Classes, CSS Custom Properties, Themes, Mixins)로 나눈다.
171
+
172
+ ### 분량 판단 & 문서 구조 결정
173
+
174
+ 수집된 Entry 수와 카테고리 수로 구조를 결정한다. 스타일 항목은 카테고리 `styling` 하나로 계산한다.
175
+
176
+ | 조건 | 구조 |
177
+ |------|------|
178
+ | 카테고리 1개 **그리고** Entry 10개 이하 | README.md 단독 |
179
+ | 그 외 | README.md (개요+카테고리 인덱스) + `docs/{category}/{entry}.md` (entry별 1 파일) |
180
+
181
+ **분할 구조 원칙**: 각 Entry는 해당 anchor 1개에만 집중한 md 파일이 되며, 카테고리는 **서브디렉토리**로만 표현된다 (카테고리 파일 `docs/{category}.md`을 만들지 않는다).
182
+
183
+ ### 문서 작성 원칙
184
+
185
+ - **기존 문서가 없으면** 분석 결과로 신규 작성. **있으면** `docs/` 하위 모든 파일(서브디렉토리 포함)을 읽어 분석 결과 기준으로 정합성을 맞춘다.
186
+ - **소스와 무관한 내용(사용 가이드, 주의사항, 규칙 등)은 보존**이 원칙이되, 현재 소스 및 산출물과 상충하면(없어진 API 언급, 옛 동작 기준 설명, 더 이상 유효하지 않은 규칙, 산출물 문서 링크 등) 소스 및 산출물 기준으로 수정한다.
187
+ - **소비자 관점 완전성**: 공개 entrypoint에서 export되어 **소비자 코드에 등장할 수 있는** 심볼은 문서화한다. 내부 재노출 유틸·타입 별칭은 주 Entry에 흡수하거나, "사용 빈도가 낮고 직접 쓰지 말아야 하는 경우" 생략할 수 있다 (생략 시 사유를 실행 로그에 남긴다). "모든 export를 기계적으로 나열"이 목표가 아니다.
188
+ - **interface/type 필드 테이블**은 **소비자가 채워야 하는 필드**에 한정한다. 반환값으로만 소비되는 타입은 시그니처만 유지하고 필드 테이블을 생략할 수 있다. 단, 소스에 필드가 있는 interface를 빈 `{}`로 축약 표시하는 것은 금지한다.
189
+ - **union type은 discriminant와 각 variant를 설명**한다. discriminated union인 경우 어떤 필드로 분기되는지와 각 variant를 나열한다.
190
+ - **Negative constraints 우선**. "이렇게 해라"만 나열하지 않는다. 소스 JSDoc·테스트·기존 `_common-rules.md` 류 문서에서 확인되는 **하지 말아야 할 사용법**을 Anti-patterns로 명시한다. "하지 마라"가 LLM 실수 방지에 더 효과적이다.
191
+
192
+ ### 반-기법 (피해야 할 작성 패턴)
193
+
194
+ 아래 패턴은 명시적으로 금지한다. 생성된 문서에서 발견되면 교정한다.
195
+
196
+ 1. **Members/Parameters/Returns만 채운 API reference** — 시그니처는 LLM이 소스에서 읽을 수 있다. "언제 쓰는가 / 흔한 실수" 없는 타입 덤프는 토큰 낭비.
197
+ 2. **백과사전식 긴 산문** — "이 기능은 ~를 위해 설계되었으며 역사적으로…" 같은 배경 서술. 별도 설명(Explanation) 문서가 필요하면 파일을 분리하되, Entry 본문에 섞지 않는다.
198
+ 3. **Deeply nested 링크 체인** — Entry → 다른 Entry → 또 다른 Entry. 1-level deep 원칙 위반.
199
+ 4. **"자세한 건 상위/다른 페이지 참조"** — Entry가 self-contained하지 않으면 부분 로드 시 깨진다.
200
+ 5. **1인칭·2인칭 서술** ("I can help…", "You should…") — 3인칭으로 통일.
201
+ 6. **시간 민감 정보 인라인** ("2025년 8월 이전엔…") — 금방 거짓이 된다. "Deprecated" 또는 "Legacy" 별도 섹션으로 격리한다.
202
+ 7. **동급 대안 나열** ("A, B, C 중 하나 고르세요") — LLM이 무작위 선택. **기본 1개 추천 + 예외 상황에만 대안**.
203
+ 8. **ALL CAPS / "ALWAYS"·"NEVER" 남발** — 진짜 중요한 곳에서만 써야 신호가 산다. 근거 1줄이 더 효과적이다.
204
+ 9. **Voodoo constants** — 근거 없는 매직 넘버.
205
+ 10. **일관되지 않은 용어** — 같은 개념을 여러 용어로 지칭하면 LLM이 별개 개념으로 오인.
206
+ 11. **Positive-only 지침** — 금지사항 없이 권장사항만 있으면 LLM이 훈련 데이터 디폴트 패턴으로 회귀한다.
207
+ 12. **Tutorial과 Reference 혼재** — "설치 후 첫 걸음…" 학습 서술을 API reference에 섞지 않는다.
208
+
209
+ ### README.md 형식 (llms.txt 스타일 인덱스 + Task 라우팅)
210
+
211
+ README.md는 **인덱스 + 작업→Entry 라우팅**에 집중한다. 분할 구조에서는 Entry 상세를 복사하지 않고 링크만 제공한다.
212
+
213
+ ```markdown
214
+ # {package-name}
215
+
216
+ > {2~3줄 요약. 런타임·타겟·핵심 의존성 전제. 이 패키지를 왜 쓰는지 한 문장.}
217
+
218
+ ## Installation
219
+
220
+ \`\`\`bash
221
+ npm install {package-name}
222
+ \`\`\`
223
+
224
+ ## 하려는 작업 → 먼저 읽을 파일
225
+
226
+ {Task 라우팅 테이블 — LLM이 사용자 의도를 파일로 직역하도록}
227
+
228
+ | 작업 | 먼저 읽을 파일 |
229
+ |------|----------------|
230
+ | 목록 화면 만들기 | [crud-list.md](./docs/recipes/crud-list.md) |
231
+ | 모달 열기 | [sd-modal-provider.md](./docs/providers/sd-modal-provider.md) |
232
+ | ... | ... |
233
+
234
+ ## 먼저 읽기 (횡단 전제)
235
+
236
+ {있는 경우에만 이 섹션을 생성}
237
+
238
+ - [공통 규칙](./docs/recipes/_common-rules.md) — 여러 Entry에 걸친 금지·컨벤션
239
+ - [Bootstrap](./docs/providers/...) — 반드시 등록해야 하는 provider / 초기화
240
+
241
+ ## API Overview
242
+
243
+ {README 단독인 경우: 카테고리별로 모든 Entry를 인라인 포함}
244
+ {분할 구조인 경우: 카테고리별 Entry 인덱스 테이블}
245
+
246
+ ### {Category Name}
247
+
248
+ | Entry | Kind | 언제 쓰나 |
249
+ |-------|------|-----------|
250
+ | [`DbContext`](./docs/{category}/db-context.md) | class | {1줄 — "어떤 작업을 할 때 이걸 쓰나"} |
251
+ | [`FtpStorage`](./docs/{category}/ftp-storage.md) | class | {1줄} |
252
+
253
+ {"Description" 대신 "언제 쓰나" 컬럼을 사용한다. 타입 요약보다 선택 기준이 LLM에게 유효하다.}
254
+
255
+ {스타일 항목이 수집된 경우:}
256
+ ### Styling
257
+
258
+ | Entry | 언제 쓰나 |
259
+ |-------|-----------|
260
+ | [CSS Classes](./docs/styling/classes.md) | 레이아웃·유틸리티 클래스가 필요할 때 |
261
+ | [CSS Custom Properties](./docs/styling/variables.md) | 디자인 토큰을 오버라이드할 때 |
262
+ | [Themes](./docs/styling/themes.md) | 테마 전환이 필요할 때 |
263
+ | [Mixins / Functions](./docs/styling/mixins.md) | SCSS에서 직접 mixin 쓸 때 |
264
+
265
+ {README 단독인 경우: 위 테이블 대신 스타일 전체 목록을 인라인으로 포함}
266
+
267
+ ## 이 패키지를 쓰지 말아야 할 때
268
+
269
+ {있는 경우에만. 예: "서버 사이드 로직 → @simplysm/service-server"}
270
+ ```
271
+
272
+ ### docs/{category}/{entry}.md 형식 (분할 대상만)
273
+
274
+ 각 Entry마다 `{패키지 경로}/docs/{category-kebab}/{entry.kebabName}.md`를 1개 생성한다. 카테고리는 서브디렉토리로 매핑한다.
275
+
276
+ Entry는 **anchor의 종류에 따라 아래 세 템플릿 중 하나**를 선택한다:
277
+
278
+ - **T1 (Recipe)**: `docs/recipes/` 하위 — 특정 화면·흐름을 만드는 방법 ("이 상황에서 어떻게 하지?")
279
+ - **T2 (API Reference)**: class / provider / 단독 함수 / util 등 API 사용법 조회
280
+ - **T3 (Rule / Decision)**: 여러 Entry에 걸친 횡단 규칙·금지 (예: `_common-rules.md`)
281
+
282
+ **공통 조건**:
283
+
284
+ - 파일이 100줄 초과 예상이면 상단에 `## Contents` TOC를 둔다.
285
+ - 어느 anchor Entry든 **anchor가 class/provider/주요 함수**이면 "When to use" 섹션을 **반드시** 작성한다. 소스에서 용도가 확인되지 않으면 "소스에서 확인되지 않음"으로 명시.
286
+ - **anchor가 class/provider/주요 함수**이고 Usage 예제가 필요한 경우, **최소 예제 + 전형 예제 2개 이상**을 포함한다. 단순 util/상수는 1개로 충분하며, 의미 있는 예제를 만들 수 없으면 Usage 섹션 자체를 생략한다 (형식적 예제 금지).
287
+
288
+ #### T1: How-to / Recipe Entry 템플릿
289
+
290
+ ```markdown
291
+ # {레시피 이름}
292
+
293
+ {1~2문장: 이 레시피가 해결하는 문제 / 산출하는 화면}
294
+
295
+ ## When to use / When NOT to use
296
+
297
+ - ✅ 이런 상황: ...
298
+ - ❌ 이런 상황엔 대신 [`OtherRecipe`](../recipes/other.md) — 이유: ...
299
+
300
+ ## 전제조건
301
+
302
+ - 필수 Provider: `provideSdAngular` 등
303
+ - peer dependency: ...
304
+ - 환경: ...
305
+
306
+ ## 기본 레시피
307
+
308
+ \`\`\`typescript
309
+ {복붙 가능한 최소 완성 코드. 엣지케이스 처리 포함.}
310
+ \`\`\`
311
+
312
+ ## 변형 (Variation)
313
+
314
+ ### {조건 A}
315
+ {코드블록}
316
+
317
+ ### {조건 B}
318
+ {코드블록}
319
+
320
+ ## 🚫 흔한 실수 (Anti-patterns)
321
+
322
+ ### {실수 이름}
323
+
324
+ \`\`\`typescript
325
+ // ❌ 잘못된 예
326
+ {코드}
327
+
328
+ // ✅ 올바른 예
329
+ {코드}
330
+ \`\`\`
331
+
332
+ **근거**: {1줄 — 왜 ❌가 문제인지}
333
+
334
+ ## 관련 Entry
335
+
336
+ - [`OtherEntry`](../other-category/other.md) — 차이: {한 줄}
337
+ ```
338
+
339
+ #### T2: API Reference Entry 템플릿
340
+
341
+ ```markdown
342
+ # `{EntryName}`
343
+
344
+ {1문장: 무엇인지 + "언제 쓰나" 축약}
345
+
346
+ ## When to use
347
+
348
+ - ✅ 이런 상황에 사용: ...
349
+ - ❌ 이런 상황엔 대신 [`OtherEntry`](../{category}/other.md) — 이유: ...
350
+
351
+ ## Signature
352
+
353
+ \`\`\`typescript
354
+ {호출 가능 수준 시그니처 — 제네릭·public 멤버 시그니처까지. private·internal 제외.}
355
+ \`\`\`
356
+
357
+ ## Members (class/component/provider인 경우)
358
+
359
+ | Member | Kind | Type | Description |
360
+ |--------|------|------|-------------|
361
+ | `host` | property | `string` | ... |
362
+ | `connect` | method | `(opt: Option) => Promise<void>` | ... |
363
+
364
+ {Kind 열은 패키지에 맞는 용어 — class는 `property`/`getter`/`method`/`static`, Angular 컴포넌트는 `input`/`input (required)`/`output`/`model`/`signal`/`computed` 등}
365
+
366
+ ## Parameters (function인 경우)
367
+
368
+ | Param | Type | Description |
369
+ |-------|------|-------------|
370
+ | `input` | `...` | ... |
371
+
372
+ ## Returns
373
+
374
+ `ReturnType` — ...
375
+
376
+ ## Usage
377
+
378
+ ### 최소 예제
379
+
380
+ \`\`\`typescript
381
+ {복붙용 가장 단순한 호출. 상수에는 근거 주석.}
382
+ \`\`\`
383
+
384
+ ### 전형 예제
385
+
386
+ \`\`\`typescript
387
+ {실전 컨텍스트 — 의존성 주입, 에러 처리, 엣지케이스 포함.}
388
+ \`\`\`
389
+
390
+ ## 🚫 Anti-patterns
391
+
392
+ ### {실수 이름}
393
+
394
+ \`\`\`typescript
395
+ // ❌
396
+ {코드}
397
+
398
+ // ✅
399
+ {코드}
400
+ \`\`\`
401
+
402
+ **근거**: {1줄}
403
+
404
+ ## Related Types
405
+
406
+ {Entry에 흡수된 interface/type/enum/const를 각각 섹션으로 나열. 소비자가 채우는 필드만 테이블화.}
407
+
408
+ ### `FtpStorageConfig`
409
+
410
+ \`\`\`typescript
411
+ {시그니처}
412
+ \`\`\`
413
+
414
+ | Field | Type | Description |
415
+ |-------|------|-------------|
416
+ | `host` | `string` | ... |
417
+
418
+ ## 관련
419
+
420
+ - [`OtherEntry`](../{category}/other.md) — 차이: {한 줄}
421
+ ```
422
+
423
+ #### T3: Rule / Decision Entry 템플릿
424
+
425
+ ```markdown
426
+ # {규칙 모음 이름}
427
+
428
+ {1~2문장: 이 규칙이 적용되는 범위와 목적}
429
+
430
+ ## 적용 범위
431
+
432
+ {어떤 Entry / 카테고리 / 상황에 적용되는가 — 구체적으로}
433
+
434
+ ## ✅ Always (반드시)
435
+
436
+ ### {규칙 이름}
437
+
438
+ \`\`\`typescript
439
+ // ❌
440
+ {코드}
441
+
442
+ // ✅
443
+ {코드}
444
+ \`\`\`
445
+
446
+ **근거**: {1줄}
447
+
448
+ ## ⚠️ Ask first (조건부)
449
+
450
+ ### {규칙 이름}
451
+
452
+ {조건 + 판단 근거}
453
+
454
+ ## 🚫 Never (금지)
455
+
456
+ ### {규칙 이름}
457
+
458
+ \`\`\`typescript
459
+ // ❌ 금지
460
+ {코드}
461
+ \`\`\`
462
+
463
+ **근거**: {왜 금지인지}
464
+ **대안**: {올바른 방법 또는 링크}
465
+
466
+ ## 예외 케이스
467
+
468
+ {규칙이 깨지는 상황과 허용 조건}
469
+ ```
470
+
471
+ ### 표시 규칙
472
+
473
+ - anchor와 흡수된 타입 모두 `##` 또는 `###` 섹션으로 반드시 노출한다. interface 필드가 많다고 `{}`로 축약하지 않는다.
474
+ - 비어 있는 섹션(예: 멤버 없음, 흔한 실수가 소스에서 확인되지 않음)은 생략한다.
475
+ - anchor가 class/provider/주요 함수면 "When to use" 섹션은 **생략 불가**.
476
+
477
+ ### Styling 분할 구조 (`docs/styling/*.md`)
478
+
479
+ 스타일 항목이 수집된 경우, 아래 4개 파일로 분할하여 생성한다. 모두 `docs/styling/` 서브디렉토리에 둔다.
480
+
481
+ - `docs/styling/classes.md` — 전역 CSS 클래스 목록
482
+ - `docs/styling/variables.md` — CSS 커스텀 프로퍼티
483
+ - `docs/styling/themes.md` — 테마 클래스와 각 테마가 오버라이드하는 변수
484
+ - `docs/styling/mixins.md` — 공개 SCSS mixin / function
485
+
486
+ 각 파일 형식:
487
+
488
+ ```markdown
489
+ <!-- classes.md -->
490
+ # CSS Classes
491
+
492
+ | Class | 언제 쓰나 |
493
+ |-------|-----------|
494
+ | `.flex-row` | {설명} |
495
+
496
+ <!-- variables.md -->
497
+ # CSS Custom Properties
498
+
499
+ | Property | Default | Description |
500
+ |----------|---------|-------------|
501
+ | `--color-primary` | `#...` | {설명} |
502
+
503
+ <!-- themes.md -->
504
+ # Themes
505
+
506
+ ## `.theme-dark` (또는 프로젝트 네이밍 관례의 테마 클래스)
507
+
508
+ {설명 + 오버라이드 변수 목록 테이블}
509
+
510
+ <!-- mixins.md -->
511
+ # Mixins / Functions
512
+
513
+ | Name | Signature | 언제 쓰나 |
514
+ |------|-----------|-----------|
515
+ | `flex-direction` | `@mixin flex-direction($dir)` | {설명} |
516
+ ```
517
+
518
+ README 단독 구조이면 위 4개 섹션을 README의 `## Styling` 하위에 인라인으로 포함하고, `docs/styling/` 서브디렉토리는 만들지 않는다.
519
+
520
+ ### 이전 구조 잔여 파일 정리
521
+
522
+ 분할 구조 전환으로 더 이상 유효하지 않은 **레이아웃 파일만** 정리한다. 이 단계는 파일 레이아웃(구조)만 다루며, 내용의 정합성은 다음 "완전성 및 정확성 검증" 단계에서 처리한다.
523
+
524
+ 1. 이전 구조(`docs/{category}.md` 단일 파일)에서 분할 구조(`docs/{category}/{entry}.md` 트리)로 전환되면서 더 이상 쓰이지 않는 **카테고리 단위 단일 파일**(예: `docs/utils.md`, `docs/pipes.md`, `docs/drivers.md` 등 카테고리가 디렉토리가 아닌 단일 md로 남은 경우)이 있으면 삭제한다.
525
+ 2. 이전에 styling이 단일 파일(`docs/styling.md`)이었고 이번 실행에서 분할 구조(`docs/styling/*.md`)로 전환되면 이전 `docs/styling.md`를 삭제한다. 반대로 README 단독 구조로 전환되어 `docs/styling/` 서브디렉토리가 불필요해지면 해당 서브디렉토리를 삭제한다.
526
+ 3. `docs/` 하위의 그 외 파일(현재 Entry 파일, recipe, 가이드 등)은 이 단계에서 삭제하지 않는다. 이들의 존속 여부는 다음 검증 단계 결과에 따라 결정된다.
527
+
528
+ ### 완전성 및 정확성 검증
529
+
530
+ 문서 작업 후, 수집한 export 목록과 `docs/` 하위 **모든 파일**(자동 생성 Entry 파일·styling 파일·recipe·가이드 등 수동 작성물 전부 포함) 및 README.md를 대조한다. 자동 생성물과 수동 작성물에 **동일한 정합성 규칙**을 적용한다.
531
+
532
+ #### 완전성
533
+
534
+ 1. export 목록의 각 항목이 README.md 또는 `docs/` 하위 어느 파일(서브디렉토리 포함)에 존재하는지 확인
535
+ 2. 누락된 항목이 있으면 해당 API를 문서에 추가 (단, "소비자 관점 완전성" 원칙에 따라 내부 유틸·재노출 타입은 흡수·생략 가능)
536
+ 3. 문서에 있는 심볼 참조 중 **현재 export에 없는 것**(제거·이름 변경된 API)은 소스 기준으로 수정하거나 제거
537
+ 4. **주제 자체가 소멸한 문서는 파일 통째로 삭제**: recipe·가이드·사용 예시처럼 특정 API 중심으로 작성된 파일의 경우, 해당 문서가 다루는 핵심 주제(제목·첫 문단·코드 예제에서 중심이 되는 anchor 심볼)가 현재 export에서 **전부 사라졌다면** 파일 내 심볼 참조를 하나씩 고치는 대신 **파일 자체를 삭제**한다. 주제가 일부만 바뀐 경우(일부 API만 사라짐)에는 내용을 수정하고 파일은 유지한다.
538
+ 5. **README의 인덱스 링크 무결성**: 모든 `[...](./docs/...)` 링크의 대상 파일이 실제로 존재하는지 확인. 깨진 링크는 수정하거나 제거 (4번에서 파일이 삭제된 경우 해당 링크도 제거)
539
+
540
+ #### 정확성
541
+
542
+ 문서의 각 API 항목에 대해, 소스 병합 파일 내 해당 소스를 다시 확인하여 아래 항목을 대조한다:
543
+
544
+ | 검증 항목 | 확인 내용 |
545
+ |-----------|-----------|
546
+ | 클래스/함수명 | 제네릭 파라미터 포함 일치 여부 |
547
+ | 멤버 이름 | property/getter/setter/method 및 프레임워크 특수 멤버(Angular `input`/`output`/`model`/`signal`/`computed` 등) 이름 일치 여부 |
548
+ | 멤버 종류 | 멤버가 어떤 종류인지 구분 정확성 (패키지에 해당하는 용어로) |
549
+ | 타입 | 파라미터 타입, 반환 타입 일치 여부 |
550
+ | required/optional | 필수/선택 구분 정확성 (Angular `input()` vs `input.required()`, interface의 `?` 유무 등) |
551
+ | 기본값 | 기본값이 있는 경우 정확한 값 |
552
+
553
+ 불일치가 발견되면 **소스 코드를 기준으로** 문서를 수정한다.
554
+
555
+ #### 매뉴얼 품질 검증
556
+
557
+ 시그니처 정합성 외에, LLM 매뉴얼로서의 품질을 아래 축으로 검증한다:
558
+
559
+ | 검증 항목 | 확인 내용 |
560
+ |-----------|-----------|
561
+ | When to use 명시 | anchor가 class/provider/주요 함수인 Entry에 "언제 쓰나"가 1문장 이상 있는가 |
562
+ | 계열 간 선택 기준 | 유사 역할 Entry가 ≥2개인 카테고리에 "무엇을 언제 고르는지" 한 줄 이상이 있는가 (README 테이블 또는 각 Entry 상호 링크) |
563
+ | Anti-pattern 수집 | 소스 JSDoc·테스트·기존 recipe·`_common-rules.md` 류 문서에서 확인된 anti-pattern이 Entry에 반영되었는가 |
564
+ | 예제 품질 | 예제에 매직 넘버가 있으면 근거 주석이 있는가. happy path만 보여주지 않는가 |
565
+ | 3인칭 서술 | "I can…", "You should…" 류 1·2인칭 서술이 없는가 |
566
+ | 용어 일관성 | 한 Entry 내에서 동일 개념에 대해 여러 용어가 혼용되지 않는가 |
567
+
568
+ #### 검증 결과 표시
569
+
570
+ ```
571
+ 완전성 검증: 52/52 API 문서화됨
572
+ 정확성 검증: 52/52 API 시그니처 일치
573
+ 매뉴얼 품질: 48/52 Entry에 When to use 명시, 12개 카테고리 중 10개에 선택 기준 있음
574
+ ```
575
+
576
+ 불일치가 있는 경우:
577
+
578
+ ```
579
+ 완전성 검증: 52/52 API 문서화됨
580
+ 정확성 검증: 50/52 API 시그니처 일치
581
+ 불일치: DbContext (tables→repositories 필드명 변경), FtpStorage (port: required→optional)
582
+ 매뉴얼 품질: 누락 - FtpStorage에 When to use 없음, SdToast/SdAlert 선택 기준 없음
583
+ → 소스 기준으로 문서를 수정하고 매뉴얼 품질 누락 항목을 보완합니다.
584
+ ```
585
+
586
+ ### package.json `files` 배열 동기화
587
+
588
+ 생성된 `docs/`가 npm publish에 포함되도록 `{패키지 경로}/package.json`의 `files` 배열을 점검한다.
589
+
590
+ 1. `package.json`에 `files` 필드가 없으면 이 단계를 건너뛴다 (npm이 기본으로 전체 파일 포함).
591
+ 2. `files` 필드가 있으면:
592
+ - 실행 후 `{패키지 경로}/docs/`가 존재하면, `files` 배열에 `"docs"`가 **없을 때 추가**한다.
593
+ - 실행 후 `{패키지 경로}/docs/`가 존재하지 않으면(분량 축소로 단독 구조로 전환되었거나 Step 3 판단으로 `docs/`를 생성하지 않은 경우), `files` 배열에 `"docs"`가 **있을 때 제거**한다.
594
+ 3. `README.md`는 npm이 `files` 선언과 무관하게 항상 포함하므로 `files`에 추가할 필요가 없다.
@@ -39,6 +39,8 @@ sd-wbs → sd-plan → sd-tdd → sd-check → sd-review를 순차 진행하는
39
39
 
40
40
  ## Step 5: sd-check
41
41
 
42
+ 수정된 소스코드(`src/`, `tests/`)가 하나도 없으면(예: 문서만 수정) 이 단계를 스킵한다.
43
+
42
44
  변경 패키지에 대한 `/sd-check` 스킬을 즉시 수행한다.
43
45
 
44
46
  ## Step 6: sd-review
@@ -79,6 +81,7 @@ sd-wbs → sd-plan → sd-tdd → sd-check → sd-review를 순차 진행하는
79
81
  `/sd-review {wbs디렉토리경로}/*.md 가 잘 구현되었는지, 문제는 없는지 최종 심층 리뷰`
80
82
  ```
81
83
 
82
- **MUST:** 완료 보고 출력 직전에 **반드시(MUST) wbs.md의 현재 상태를 다시 읽어** Feature 체크박스(`[x]`/`[ ]`)를 확인한 뒤, 위 두 섹션 중 조건에 맞는 정확히 하나만 출력한다.
84
+ 완료 보고 출력 직전에 **반드시(MUST) wbs.md의 현재 상태를 다시 읽어** Feature 체크박스(`[x]`/`[ ]`)를 확인한 뒤, 위 두 섹션 중 조건에 맞는 정확히 하나만 출력한다.
85
+ - 다시 읽지 않으면 병렬 로 수행한 모든것이 적용되지 않은 상태로 표기되기 때문에 중복 수행 문제가 발생할 수 있다.
83
86
 
84
87
  **NEVER:** 미완료(`[ ]`) Feature가 1개라도 남아 있으면 `/sd-review`를 어떤 형태로도(조건부·제안·예시 포함) 언급하지 않는다. "모든 Feature가 끝난 뒤 /sd-review를 권장" 같은 조건부 안내도 금지한다.
@@ -12,10 +12,27 @@ description: (내부 전용) 코드 리뷰 분석 로직. sd-review, sd-dev 등
12
12
  - `/sd-inner-review src/services` → `src/services` 하위만
13
13
  - `/sd-inner-review` → 프로젝트 루트 전체
14
14
 
15
+ **CRITICAL: git 명령 사용 금지.** `git diff`, `git status`, `git log`, `git show` 등 git 명령으로 대상 파일을 결정하지 않는다. 리뷰 대상은 오직 인자로 지정된 경로 또는 대화 맥락에서 사용자가 지정한 범위이다. "최근 변경 파일", "커밋된 파일" 등의 개념으로 대상을 좁히지 않는다.
16
+
15
17
  ## Step 2: 컨텍스트 수집
16
18
 
17
19
  프로젝트의 기술 스택, 컨벤션등의 규칙을 파악한다.
18
20
 
21
+ ### 소스 수집
22
+
23
+ 대상 경로 유형에 따라 소스를 수집한다.
24
+
25
+ - **패키지 디렉토리** (경로 내 `src/` 존재): `merge-source.sh`로 병합하여 단일 파일로 읽는다.
26
+ ```bash
27
+ bash .claude/skills/sd-inner-review/merge-source.sh ./tmp/review-source.txt --dir <패키지경로>
28
+ ```
29
+ - **개별 파일 목록**:
30
+ - **5개 미만**: 각 파일을 개별 Read로 읽는다.
31
+ - **5개 이상**: `merge-source.sh`로 병합하여 단일 파일로 읽는다.
32
+ ```bash
33
+ bash .claude/skills/sd-inner-review/merge-source.sh ./tmp/review-source.txt --files <파일1> <파일2> ...
34
+ ```
35
+
19
36
  ## Step 3: 분석
20
37
 
21
38
  대상 파일을 읽고, 4가지 관점으로 이슈를 탐지한다.