@simplysm/sd-claude 13.0.77 → 13.0.80
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/claude/rules/sd-claude-rules.md +4 -63
- package/claude/rules/sd-simplysm-usage.md +7 -0
- package/claude/sd-session-start.sh +10 -0
- package/claude/skills/sd-api-review/SKILL.md +89 -0
- package/claude/skills/sd-check/SKILL.md +55 -57
- package/claude/skills/sd-commit/SKILL.md +37 -42
- package/claude/skills/sd-debug/SKILL.md +75 -265
- package/claude/skills/sd-document/SKILL.md +63 -53
- package/claude/skills/sd-document/_common.py +94 -0
- package/claude/skills/sd-document/extract_docx.py +19 -48
- package/claude/skills/sd-document/extract_pdf.py +22 -50
- package/claude/skills/sd-document/extract_pptx.py +17 -40
- package/claude/skills/sd-document/extract_xlsx.py +19 -40
- package/claude/skills/sd-email-analyze/SKILL.md +23 -31
- package/claude/skills/sd-email-analyze/email-analyzer.py +79 -65
- package/claude/skills/sd-init/SKILL.md +133 -0
- package/claude/skills/sd-plan/SKILL.md +69 -120
- package/claude/skills/sd-readme/SKILL.md +106 -131
- package/claude/skills/sd-review/SKILL.md +38 -155
- package/claude/skills/sd-simplify/SKILL.md +59 -0
- package/package.json +3 -2
- package/README.md +0 -297
- package/claude/refs/sd-angular.md +0 -127
- package/claude/refs/sd-code-conventions.md +0 -155
- package/claude/refs/sd-directories.md +0 -7
- package/claude/refs/sd-library-issue.md +0 -7
- package/claude/refs/sd-migration.md +0 -7
- package/claude/refs/sd-orm-v12.md +0 -81
- package/claude/refs/sd-orm.md +0 -23
- package/claude/refs/sd-service.md +0 -5
- package/claude/refs/sd-simplysm-docs.md +0 -52
- package/claude/refs/sd-solid.md +0 -68
- package/claude/refs/sd-workflow.md +0 -25
- package/claude/rules/sd-refs-linker.md +0 -52
- package/claude/sd-statusline.js +0 -296
- package/claude/skills/sd-api-name-review/SKILL.md +0 -154
- package/claude/skills/sd-brainstorm/SKILL.md +0 -215
- package/claude/skills/sd-debug/condition-based-waiting-example.ts +0 -158
- package/claude/skills/sd-debug/condition-based-waiting.md +0 -114
- package/claude/skills/sd-debug/defense-in-depth.md +0 -128
- package/claude/skills/sd-debug/find-polluter.sh +0 -64
- package/claude/skills/sd-debug/root-cause-tracing.md +0 -168
- package/claude/skills/sd-discuss/SKILL.md +0 -91
- package/claude/skills/sd-explore/SKILL.md +0 -118
- package/claude/skills/sd-plan-dev/SKILL.md +0 -294
- package/claude/skills/sd-plan-dev/code-quality-reviewer-prompt.md +0 -49
- package/claude/skills/sd-plan-dev/final-review-prompt.md +0 -50
- package/claude/skills/sd-plan-dev/implementer-prompt.md +0 -60
- package/claude/skills/sd-plan-dev/spec-reviewer-prompt.md +0 -45
- package/claude/skills/sd-review/api-reviewer-prompt.md +0 -75
- package/claude/skills/sd-review/code-reviewer-prompt.md +0 -82
- package/claude/skills/sd-review/convention-checker-prompt.md +0 -61
- package/claude/skills/sd-review/refactoring-analyzer-prompt.md +0 -92
- package/claude/skills/sd-skill/SKILL.md +0 -417
- package/claude/skills/sd-skill/anthropic-best-practices.md +0 -156
- package/claude/skills/sd-skill/cso-guide.md +0 -161
- package/claude/skills/sd-skill/examples/CLAUDE_MD_TESTING.md +0 -200
- package/claude/skills/sd-skill/persuasion-principles.md +0 -220
- package/claude/skills/sd-skill/testing-skills-with-subagents.md +0 -408
- package/claude/skills/sd-skill/writing-guide.md +0 -159
- package/claude/skills/sd-tdd/SKILL.md +0 -385
- package/claude/skills/sd-tdd/testing-anti-patterns.md +0 -317
- package/claude/skills/sd-use/SKILL.md +0 -67
- package/claude/skills/sd-worktree/SKILL.md +0 -78
|
@@ -1,303 +1,113 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-debug
|
|
3
|
-
description: "
|
|
3
|
+
description: "디버그", "debug", "sd-debug", "오류 분석", "에러 원인", "버그 찾기" 등을 요청할 때 사용.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# SD Debug — 오류 원인 분석 및 해결 계획 수립
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
에러 메시지, 스택 트레이스, 또는 문제 상황 설명을 받아 코드베이스를 심층 분석한 뒤 근본 원인을 진단하고, `/sd-plan` 프로세스로 해결 계획을 수립한다.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
ARGUMENTS: 에러 메시지, 스택 트레이스, 또는 문제 상황 설명 (선택). 미지정 시 대화 컨텍스트에서 파악하거나 사용자에게 질문한다.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
**Violating the letter of this process is violating the spirit of debugging.**
|
|
15
|
-
|
|
16
|
-
## The Iron Law
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
If you haven't completed Phase 1, you cannot propose fixes.
|
|
23
|
-
|
|
24
|
-
## When to Use
|
|
25
|
-
|
|
26
|
-
Use for ANY technical issue:
|
|
27
|
-
|
|
28
|
-
- Test failures
|
|
29
|
-
- Bugs in production
|
|
30
|
-
- Unexpected behavior
|
|
31
|
-
- Performance problems
|
|
32
|
-
- Build failures
|
|
33
|
-
- Integration issues
|
|
34
|
-
|
|
35
|
-
**Use this ESPECIALLY when:**
|
|
36
|
-
|
|
37
|
-
- Under time pressure (emergencies make guessing tempting)
|
|
38
|
-
- "Just one quick fix" seems obvious
|
|
39
|
-
- You've already tried multiple fixes
|
|
40
|
-
- Previous fix didn't work
|
|
41
|
-
- You don't fully understand the issue
|
|
42
|
-
|
|
43
|
-
**Don't skip when:**
|
|
44
|
-
|
|
45
|
-
- Issue seems simple (simple bugs have root causes too)
|
|
46
|
-
- You're in a hurry (rushing guarantees rework)
|
|
47
|
-
- Manager wants it fixed NOW (systematic is faster than thrashing)
|
|
48
|
-
|
|
49
|
-
## The Four Phases
|
|
50
|
-
|
|
51
|
-
You MUST complete each phase before proceeding to the next.
|
|
52
|
-
|
|
53
|
-
### Phase 1: Root Cause Investigation
|
|
54
|
-
|
|
55
|
-
**BEFORE attempting ANY fix:**
|
|
56
|
-
|
|
57
|
-
1. **Read Error Messages Carefully**
|
|
58
|
-
- Don't skip past errors or warnings
|
|
59
|
-
- They often contain the exact solution
|
|
60
|
-
- Read stack traces completely
|
|
61
|
-
- Note line numbers, file paths, error codes
|
|
62
|
-
|
|
63
|
-
2. **Reproduce Consistently**
|
|
64
|
-
- Can you trigger it reliably?
|
|
65
|
-
- What are the exact steps?
|
|
66
|
-
- Does it happen every time?
|
|
67
|
-
- If not reproducible → gather more data, don't guess
|
|
68
|
-
|
|
69
|
-
3. **Read the Source Code Directly**
|
|
70
|
-
- Read the actual code where the bug manifests
|
|
71
|
-
- Understand what the code does line by line
|
|
72
|
-
- Walk through the logic with the failing input mentally
|
|
73
|
-
- Do NOT run `git diff` or `git log` — diffs show WHAT changed, not WHY it's broken
|
|
74
|
-
- The bug is in the code as it exists NOW; analyze the code as-is
|
|
75
|
-
|
|
76
|
-
4. **Gather Evidence in Multi-Component Systems**
|
|
77
|
-
|
|
78
|
-
**WHEN system has multiple components (CI → build → signing, API → service → database):**
|
|
79
|
-
|
|
80
|
-
**BEFORE proposing fixes, add diagnostic instrumentation:**
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
For EACH component boundary:
|
|
84
|
-
- Log what data enters component
|
|
85
|
-
- Log what data exits component
|
|
86
|
-
- Verify environment/config propagation
|
|
87
|
-
- Check state at each layer
|
|
88
|
-
|
|
89
|
-
Run once to gather evidence showing WHERE it breaks
|
|
90
|
-
THEN analyze evidence to identify failing component
|
|
91
|
-
THEN investigate that specific component
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Example (multi-layer system):**
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
# Layer 1: Workflow
|
|
98
|
-
echo "=== Secrets available in workflow: ==="
|
|
99
|
-
echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"
|
|
100
|
-
|
|
101
|
-
# Layer 2: Build script
|
|
102
|
-
echo "=== Env vars in build script: ==="
|
|
103
|
-
env | grep IDENTITY || echo "IDENTITY not in environment"
|
|
104
|
-
|
|
105
|
-
# Layer 3: Signing script
|
|
106
|
-
echo "=== Keychain state: ==="
|
|
107
|
-
security list-keychains
|
|
108
|
-
security find-identity -v
|
|
109
|
-
|
|
110
|
-
# Layer 4: Actual signing
|
|
111
|
-
codesign --sign "$IDENTITY" --verbose=4 "$APP"
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗)
|
|
115
|
-
|
|
116
|
-
5. **Trace Data Flow**
|
|
117
|
-
|
|
118
|
-
**WHEN error is deep in call stack:**
|
|
119
|
-
|
|
120
|
-
See `root-cause-tracing.md` in this directory for the complete backward tracing technique.
|
|
121
|
-
|
|
122
|
-
**Quick version:**
|
|
123
|
-
- Where does bad value originate?
|
|
124
|
-
- What called this with bad value?
|
|
125
|
-
- Keep tracing up until you find the source
|
|
126
|
-
- Fix at source, not at symptom
|
|
127
|
-
|
|
128
|
-
### Phase 2: Pattern Analysis
|
|
129
|
-
|
|
130
|
-
**Find the pattern before fixing:**
|
|
131
|
-
|
|
132
|
-
1. **Find Working Examples**
|
|
133
|
-
- Locate similar working code in same codebase
|
|
134
|
-
- What works that's similar to what's broken?
|
|
135
|
-
|
|
136
|
-
2. **Compare Against References**
|
|
137
|
-
- If implementing pattern, read reference implementation COMPLETELY
|
|
138
|
-
- Don't skim - read every line
|
|
139
|
-
- Understand the pattern fully before applying
|
|
140
|
-
|
|
141
|
-
3. **Identify Differences**
|
|
142
|
-
- What's different between working and broken?
|
|
143
|
-
- List every difference, however small
|
|
144
|
-
- Don't assume "that can't matter"
|
|
145
|
-
|
|
146
|
-
4. **Understand Dependencies**
|
|
147
|
-
- What other components does this need?
|
|
148
|
-
- What settings, config, environment?
|
|
149
|
-
- What assumptions does it make?
|
|
150
|
-
|
|
151
|
-
### Phase 3: Hypothesis and Testing
|
|
152
|
-
|
|
153
|
-
**Scientific method:**
|
|
154
|
-
|
|
155
|
-
1. **Form Single Hypothesis**
|
|
156
|
-
- State clearly: "I think X is the root cause because Y"
|
|
157
|
-
- Write it down
|
|
158
|
-
- Be specific, not vague
|
|
159
|
-
|
|
160
|
-
2. **Test Minimally**
|
|
161
|
-
- Make the SMALLEST possible change to test hypothesis
|
|
162
|
-
- One variable at a time
|
|
163
|
-
- Don't fix multiple things at once
|
|
164
|
-
|
|
165
|
-
3. **Verify Before Continuing**
|
|
166
|
-
- Did it work? Yes → Phase 4
|
|
167
|
-
- Didn't work? Form NEW hypothesis
|
|
168
|
-
- DON'T add more fixes on top
|
|
169
|
-
|
|
170
|
-
4. **When You Don't Know**
|
|
171
|
-
- Say "I don't understand X"
|
|
172
|
-
- Don't pretend to know
|
|
173
|
-
- Ask for help
|
|
174
|
-
- Research more
|
|
175
|
-
|
|
176
|
-
### Phase 4: Implementation
|
|
177
|
-
|
|
178
|
-
**Fix the root cause, not the symptom:**
|
|
179
|
-
|
|
180
|
-
1. **Create Failing Test Case**
|
|
181
|
-
- Simplest possible reproduction
|
|
182
|
-
- Automated test if possible
|
|
183
|
-
- One-off test script if no framework
|
|
184
|
-
- MUST have before fixing
|
|
185
|
-
- Use the `sd-tdd` skill for writing proper failing tests
|
|
186
|
-
|
|
187
|
-
2. **Implement Single Fix**
|
|
188
|
-
- Address the root cause identified
|
|
189
|
-
- ONE change at a time
|
|
190
|
-
- No "while I'm here" improvements
|
|
191
|
-
- No bundled refactoring
|
|
12
|
+
---
|
|
192
13
|
|
|
193
|
-
|
|
194
|
-
- Test passes now?
|
|
195
|
-
- No other tests broken?
|
|
196
|
-
- Issue actually resolved?
|
|
14
|
+
## Step 1: 문제 정보 확보
|
|
197
15
|
|
|
198
|
-
|
|
16
|
+
- 문제 정보를 아래 우선순위로 확보하라:
|
|
17
|
+
1. **ARGUMENTS**: 스킬 호출 시 함께 전달된 에러 메시지, 스택 트레이스, 또는 문제 설명
|
|
18
|
+
2. **현재 대화**: ARGUMENTS가 없으면 현재 대화 컨텍스트에서 에러 메시지, 로그, 문제 상황을 파악
|
|
19
|
+
3. **AskUserQuestion**: 위 둘로도 파악이 안 되면 "어떤 문제를 디버깅할까요? 에러 메시지, 스택 트레이스, 또는 문제 상황을 설명해 주세요."라고 질문
|
|
20
|
+
- 확보한 문제 정보에서 아래를 추출하라:
|
|
21
|
+
- **에러 유형**: 컴파일 에러 / 런타임 에러 / 타입 에러 / 논리 오류 / 빌드 에러 / 동작 이상 등
|
|
22
|
+
- **관련 단서**: 파일 경로, 함수명, 라인 번호, 패키지명, 에러 코드 등 코드베이스 탐색에 활용할 키워드
|
|
199
23
|
|
|
200
|
-
|
|
201
|
-
flowchart TD
|
|
202
|
-
A{"Fix failed?"} --> B{"Attempts < 3?"}
|
|
203
|
-
B -->|yes| C["Phase 1: Re-analyze<br>with new information"]
|
|
204
|
-
B -->|"no (≥3)"| D["STOP: Question Architecture<br>→ Discuss with user first"]
|
|
205
|
-
```
|
|
24
|
+
## Step 2: 코드베이스 심층 분석
|
|
206
25
|
|
|
207
|
-
|
|
208
|
-
- Each fix reveals new shared state/coupling/problem in different place
|
|
209
|
-
- Fixes require "massive refactoring" to implement
|
|
210
|
-
- Each fix creates new symptoms elsewhere
|
|
26
|
+
Step 1에서 확보한 문제 정보와 단서를 바탕으로, 해당 문제의 근본 원인을 파악하기 위해 필요한 조사를 스스로 판단하여 수행하라. Agent 도구(subagent_type: Explore)를 활용하여 코드베이스를 탐색하되, 조사 범위와 방법은 문제의 성격에 따라 자유롭게 결정하라.
|
|
211
27
|
|
|
212
|
-
|
|
28
|
+
### 분석 원칙
|
|
213
29
|
|
|
214
|
-
|
|
30
|
+
> **핵심**: 근본 원인을 완전히 이해하기 전까지 해결 방안을 제시하지 마라. "분석 → 이해 → 해결책" 순서를 반드시 지켜라.
|
|
215
31
|
|
|
216
|
-
|
|
32
|
+
1. **추측 수정 금지**: 코드를 수정해보고 결과를 확인하는 시행착오 방식으로 원인을 찾지 마라. 코드를 읽고 로직을 추적하여 원인을 파악하라.
|
|
33
|
+
2. **우회 금지**: `as` 타입 단언, `any`, `// @ts-ignore`, 하드코딩, 예외 삼킴(`catch` 후 무시) 등으로 증상을 숨기는 방안을 해결책으로 제시하지 마라.
|
|
34
|
+
3. **의도 파악 우선**: 테스트 실패 시, 테스트가 검증하는 의도된 동작과 현재 코드의 실제 동작을 먼저 비교하라. 기능 변경이 의도적이면 테스트를 갱신하고, 의도치 않은 변경이면 코드를 수정하라. 의도를 판단할 수 없으면 사용자에게 질문하라.
|
|
35
|
+
4. **증상과 원인 구분**: 에러 메시지가 나타나는 지점이 원인이 아닐 수 있다. 에러 지점에서 역추적하여 실제 원인을 찾아라.
|
|
217
36
|
|
|
218
|
-
|
|
37
|
+
### 분석 결과 정리
|
|
219
38
|
|
|
220
|
-
|
|
221
|
-
-
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
- "I don't fully understand but this might work"
|
|
226
|
-
- "Pattern says X but I'll adapt it differently"
|
|
227
|
-
- "Here are the main problems: [lists fixes without investigation]"
|
|
228
|
-
- Proposing solutions before tracing data flow
|
|
229
|
-
- "Let me check git diff/log to see what changed"
|
|
230
|
-
- **"One more fix attempt" (when already tried 2+)**
|
|
231
|
-
- **Each fix reveals new problem in different place**
|
|
39
|
+
분석이 끝나면 아래 항목들을 정리하라:
|
|
40
|
+
- **에러 발생 지점**: 문제가 발생하는 구체적 코드 위치 (파일경로:라인)
|
|
41
|
+
- **근본 원인**: 왜 이 문제가 발생하는지에 대한 분석
|
|
42
|
+
- **영향 범위**: 이 문제가 영향을 미치는 파일/함수 목록
|
|
43
|
+
- **해결 방안**: 가능한 해결 방법들 (각각 수정 대상 파일 포함)
|
|
232
44
|
|
|
233
|
-
|
|
45
|
+
## Step 3: 진단 결과 종합 및 사용자 확인
|
|
234
46
|
|
|
235
|
-
|
|
47
|
+
Step 2의 분석 결과를 종합하여 아래 형식으로 진단 보고서를 작성하고 사용자에게 제시하라:
|
|
236
48
|
|
|
237
|
-
|
|
49
|
+
```
|
|
50
|
+
## 진단 결과
|
|
238
51
|
|
|
239
|
-
|
|
52
|
+
### 문제 요약
|
|
53
|
+
<에러/문제를 한 문장으로 요약>
|
|
240
54
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
- "Stop guessing" - You're proposing fixes without understanding
|
|
244
|
-
- "Ultrathink this" - Question fundamentals, not just symptoms
|
|
245
|
-
- "We're stuck?" (frustrated) - Your approach isn't working
|
|
55
|
+
### 근본 원인
|
|
56
|
+
<근본 원인을 명확하고 구체적으로 설명. 파일 경로와 라인 번호 포함.>
|
|
246
57
|
|
|
247
|
-
|
|
58
|
+
### 영향 범위
|
|
59
|
+
- <영향받는 파일/함수 1>
|
|
60
|
+
- <영향받는 파일/함수 2>
|
|
248
61
|
|
|
249
|
-
|
|
62
|
+
### 해결 방안
|
|
250
63
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
|
|
256
|
-
| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. |
|
|
257
|
-
| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
|
|
258
|
-
| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. |
|
|
259
|
-
| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
|
|
260
|
-
| "Let me check git diff to see what changed" | Diff shows WHAT changed, not WHY it's broken. Read the code as-is. |
|
|
261
|
-
| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. |
|
|
64
|
+
1. **<방안 1 제목>**: <설명>
|
|
65
|
+
- 수정 대상: <파일 경로 목록>
|
|
66
|
+
- 장점: ...
|
|
67
|
+
- 단점: ...
|
|
262
68
|
|
|
263
|
-
|
|
69
|
+
2. **<방안 2 제목>**: <설명> (해당 시)
|
|
70
|
+
- 수정 대상: <파일 경로 목록>
|
|
71
|
+
- 장점: ...
|
|
72
|
+
- 단점: ...
|
|
264
73
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
| **2. Pattern** | Find working examples, compare | Identify differences |
|
|
269
|
-
| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
|
|
270
|
-
| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |
|
|
74
|
+
### 권장 방안
|
|
75
|
+
<가장 적절한 방안과 그 이유>
|
|
76
|
+
```
|
|
271
77
|
|
|
272
|
-
|
|
78
|
+
진단 보고서를 출력한 뒤, AskUserQuestion으로 다음을 질문하라:
|
|
273
79
|
|
|
274
|
-
|
|
80
|
+
```
|
|
81
|
+
진단 결과를 확인해 주세요.
|
|
82
|
+
1. 진단이 정확하므로 권장 방안으로 계획을 수립한다
|
|
83
|
+
2. 진단이 정확하지만 다른 방안(번호)으로 계획을 수립한다
|
|
84
|
+
3. 진단이 부정확하다 — 추가 정보를 제공하겠다
|
|
85
|
+
```
|
|
275
86
|
|
|
276
|
-
1
|
|
277
|
-
2
|
|
278
|
-
3
|
|
279
|
-
4. Add monitoring/logging for future investigation
|
|
87
|
+
- **1번 선택**: 권장 방안을 기반으로 Step 4로 진행하라.
|
|
88
|
+
- **2번 선택**: 사용자가 지정한 방안을 기반으로 Step 4로 진행하라.
|
|
89
|
+
- **3번 선택**: 사용자가 제공한 추가 정보를 반영하여 Step 2로 돌아가라.
|
|
280
90
|
|
|
281
|
-
|
|
91
|
+
## Step 4: sd-plan으로 해결 계획 수립
|
|
282
92
|
|
|
283
|
-
|
|
93
|
+
사용자가 확인한 진단 결과와 선택된 해결 방안을 작업 설명으로 하여, Skill 도구로 `sd-plan`을 호출하라. args에 아래를 전달하라:
|
|
284
94
|
|
|
285
|
-
|
|
95
|
+
```
|
|
96
|
+
아래 디버깅 진단 결과에 따른 해결 방안을 구현하기 위한 계획을 수립하라:
|
|
286
97
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling
|
|
98
|
+
## 문제
|
|
99
|
+
<Step 3의 문제 요약>
|
|
290
100
|
|
|
291
|
-
|
|
101
|
+
## 근본 원인
|
|
102
|
+
<Step 3의 근본 원인>
|
|
292
103
|
|
|
293
|
-
|
|
294
|
-
|
|
104
|
+
## 해결 방안
|
|
105
|
+
<사용자가 선택한 해결 방안의 상세 내용>
|
|
295
106
|
|
|
296
|
-
##
|
|
107
|
+
## 수정 대상 파일
|
|
108
|
+
<해결 방안의 수정 대상 파일 경로 목록>
|
|
109
|
+
```
|
|
297
110
|
|
|
298
|
-
|
|
111
|
+
## Step 5: 계획 실행
|
|
299
112
|
|
|
300
|
-
-
|
|
301
|
-
- Random fixes approach: 2-3 hours of thrashing
|
|
302
|
-
- First-time fix rate: 95% vs 40%
|
|
303
|
-
- New bugs introduced: Near zero vs common
|
|
113
|
+
sd-plan이 완료되어 확정된 계획서가 나오면, 그 계획서에 따라 코드를 수정하라.
|
|
@@ -1,99 +1,109 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-document
|
|
3
|
-
description:
|
|
3
|
+
description: .docx, .xlsx, .pptx, .pdf 파일과 관련하여 "문서 읽기/분석", "파일 내용 추출", "DOCX/XLSX 생성", "고객 문서 검토", "데이터 내보내기"를 요청할때 사용.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Document
|
|
6
|
+
# SD Document — 문서 파일 읽기/쓰기
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
문서 파일(.docx/.xlsx/.pptx/.pdf)을 Python 스크립트로 읽거나 쓴다. 읽기 시 텍스트와 이미지를 위치 정보와 함께 추출하고, 이미지를 파일로 저장한 뒤 Claude Read로 분석한다.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
Python scripts extract text and images with location information by format, save images to files, and analyze them with Claude Read.
|
|
10
|
+
ARGUMENTS: 문서 파일 경로 (필수). `.docx`, `.xlsx`, `.pptx`, `.pdf` 파일 경로를 지정한다.
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Step 1: 작업 방향 결정
|
|
15
|
+
|
|
16
|
+
ARGUMENTS에서 파일 경로를 추출하고, 사용자의 요청이 **읽기**(분석/추출)인지 **쓰기**(생성/편집)인지 판단하라.
|
|
17
|
+
|
|
18
|
+
- **읽기** → Step 2로 이동
|
|
19
|
+
- **쓰기** → Step 4로 이동
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|--------|------|-------|---------|
|
|
17
|
-
| DOCX | Yes | Yes | `python-docx` |
|
|
18
|
-
| XLSX | Yes | Yes | `openpyxl`, `pandas` |
|
|
19
|
-
| PPTX | Yes | No | `python-pptx` |
|
|
20
|
-
| PDF | Yes | No | `pdfplumber`, `pypdf` |
|
|
21
|
+
### 형식별 지원 현황
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
| 형식 | 읽기 | 쓰기 | 라이브러리 |
|
|
24
|
+
|------|------|------|-----------|
|
|
25
|
+
| DOCX | 가능 | 가능 | `python-docx` |
|
|
26
|
+
| XLSX | 가능 | 가능 | `openpyxl`, `pandas` |
|
|
27
|
+
| PPTX | 가능 | 불가 | `python-pptx` |
|
|
28
|
+
| PDF | 가능 | 불가 | `pdfplumber`, `pypdf` |
|
|
23
29
|
|
|
24
|
-
|
|
30
|
+
누락된 패키지는 첫 스크립트 실행 시 자동 설치된다.
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
## Step 2: 문서 읽기 (추출 스크립트 실행)
|
|
33
|
+
|
|
34
|
+
파일 확장자에 맞는 추출 스크립트를 실행하라:
|
|
27
35
|
|
|
28
36
|
```bash
|
|
29
|
-
python .claude/skills/sd-document/extract_docx.py
|
|
30
|
-
python .claude/skills/sd-document/extract_xlsx.py
|
|
31
|
-
python .claude/skills/sd-document/extract_pptx.py
|
|
32
|
-
python .claude/skills/sd-document/extract_pdf.py
|
|
37
|
+
python .claude/skills/sd-document/extract_docx.py <파일경로>
|
|
38
|
+
python .claude/skills/sd-document/extract_xlsx.py <파일경로>
|
|
39
|
+
python .claude/skills/sd-document/extract_pptx.py <파일경로>
|
|
40
|
+
python .claude/skills/sd-document/extract_pdf.py <파일경로>
|
|
33
41
|
```
|
|
34
42
|
|
|
35
|
-
###
|
|
36
|
-
- **stdout**:
|
|
37
|
-
-
|
|
43
|
+
### 출력
|
|
44
|
+
- **stdout**: 텍스트 및 위치 정보 (Markdown 형식)
|
|
45
|
+
- **이미지 파일**: `<파일명>_files/` 디렉토리에 저장
|
|
46
|
+
|
|
47
|
+
### 위치 정보
|
|
48
|
+
|
|
49
|
+
| 형식 | 위치 표현 방식 |
|
|
50
|
+
|------|--------------|
|
|
51
|
+
| DOCX | 문단 흐름 순서 (텍스트-이미지 인라인) |
|
|
52
|
+
| XLSX | 셀 위치 (A1, B2 등) |
|
|
53
|
+
| PPTX | 도형 left/top 좌표 (인치) + 슬라이드 번호 |
|
|
54
|
+
| PDF | 페이지 번호 |
|
|
38
55
|
|
|
39
|
-
|
|
56
|
+
## Step 3: 추출 결과 분석
|
|
40
57
|
|
|
41
|
-
|
|
42
|
-
|--------|-------------------------|
|
|
43
|
-
| DOCX | Paragraph flow order (text-image inline) |
|
|
44
|
-
| XLSX | Cell position (A1, B2, etc.) |
|
|
45
|
-
| PPTX | Shape left/top coordinates (inches) + slide number |
|
|
46
|
-
| PDF | Page number |
|
|
58
|
+
Step 2의 출력에서 추출된 파일 경로를 확인하고 아래를 수행하라:
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
1. **이미지**: `_files/` 디렉토리에 저장된 각 이미지를 **Read** 도구로 열어 시각적 분석을 수행
|
|
61
|
+
2. **텍스트**: stdout으로 출력된 텍스트를 사용자의 요청에 맞게 분석/요약
|
|
50
62
|
|
|
51
|
-
|
|
52
|
-
If text extraction is empty, the script outputs OCR instructions.
|
|
53
|
-
Tesseract OCR requires OS-level installation (not auto-installable via pip).
|
|
63
|
+
## Step 4: 문서 쓰기
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
사용자의 요청에 따라 Python 스크립트를 작성하여 문서를 생성하거나 편집하라.
|
|
56
66
|
|
|
57
67
|
### DOCX (`python-docx`)
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
메일 템플릿 및 간단한 보고서용.
|
|
60
70
|
|
|
61
71
|
```python
|
|
62
72
|
from docx import Document
|
|
63
73
|
|
|
64
|
-
doc = Document() #
|
|
65
|
-
# doc = Document("existing.docx") #
|
|
66
|
-
doc.add_heading("
|
|
67
|
-
doc.add_paragraph("
|
|
74
|
+
doc = Document() # 새 문서
|
|
75
|
+
# doc = Document("existing.docx") # 기존 문서 편집
|
|
76
|
+
doc.add_heading("제목", level=1)
|
|
77
|
+
doc.add_paragraph("본문 내용")
|
|
68
78
|
table = doc.add_table(rows=2, cols=3)
|
|
69
|
-
table.cell(0, 0).text = "
|
|
79
|
+
table.cell(0, 0).text = "항목"
|
|
70
80
|
doc.save("output.docx")
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
기존 문서 편집: `Document("existing.docx")`로 열어 `paragraph.text` 교체, `table.cell().text` 수정.
|
|
74
84
|
|
|
75
85
|
### XLSX (`openpyxl`)
|
|
76
86
|
|
|
77
|
-
|
|
87
|
+
데이터와 수식 중심. 서식(색상, 테두리)은 필수가 아님.
|
|
78
88
|
|
|
79
89
|
```python
|
|
80
90
|
from openpyxl import Workbook
|
|
81
91
|
|
|
82
92
|
wb = Workbook()
|
|
83
93
|
ws = wb.active
|
|
84
|
-
ws["A1"] = "
|
|
85
|
-
ws["B1"] = "
|
|
86
|
-
ws.append(["
|
|
87
|
-
ws.append(["
|
|
94
|
+
ws["A1"] = "항목"
|
|
95
|
+
ws["B1"] = "수량"
|
|
96
|
+
ws.append(["사과", 10])
|
|
97
|
+
ws.append(["배", 20])
|
|
88
98
|
ws["B4"] = "=SUM(B2:B3)"
|
|
89
99
|
wb.save("output.xlsx")
|
|
90
100
|
```
|
|
91
101
|
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
기존 파일 편집: `load_workbook("existing.xlsx")`로 열어 수정.
|
|
103
|
+
pandas DataFrame 내보내기: `df.to_excel("output.xlsx", index=False)`
|
|
94
104
|
|
|
95
|
-
##
|
|
105
|
+
## 흔한 실수
|
|
96
106
|
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
- **XLSX data_only**: `load_workbook(data_only=True)
|
|
107
|
+
- **문자 인코딩**: 스크립트에 UTF-8 처리가 내장되어 있으므로 항상 스크립트를 통해 추출할 것
|
|
108
|
+
- **이미지 누락**: 추출 후 `_files/` 디렉토리의 이미지를 반드시 읽을 것
|
|
109
|
+
- **XLSX data_only**: `load_workbook(data_only=True)`는 수식을 제거함 — 수식을 유지하려면 `data_only=False` 사용
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Shared utilities for document extraction scripts."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import io
|
|
5
|
+
import re
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def setup_encoding():
|
|
11
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
|
12
|
+
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ensure_packages(packages: dict[str, str]):
|
|
16
|
+
for pip_name, import_name in packages.items():
|
|
17
|
+
try:
|
|
18
|
+
__import__(import_name)
|
|
19
|
+
except ImportError:
|
|
20
|
+
print(f"Installing package: {pip_name}...", file=sys.stderr)
|
|
21
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name],
|
|
22
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def make_output_paths(file_path: str) -> tuple[Path, Path]:
|
|
26
|
+
p = Path(file_path)
|
|
27
|
+
out_dir = p.parent / f"{p.stem}_files"
|
|
28
|
+
return p, out_dir
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def print_header(file_path: Path):
|
|
32
|
+
print(f"# {file_path.name}\n")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_created_dirs: set[Path] = set()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def save_image(out_dir: Path, img_idx: int, blob: bytes, ext: str) -> Path:
|
|
39
|
+
if out_dir not in _created_dirs:
|
|
40
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
_created_dirs.add(out_dir)
|
|
42
|
+
img_path = out_dir / f"img_{img_idx:03d}.{ext}"
|
|
43
|
+
img_path.write_bytes(blob)
|
|
44
|
+
return img_path
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
_CONTENT_TYPE_MAP = {
|
|
48
|
+
"image/jpeg": "jpg",
|
|
49
|
+
"image/png": "png",
|
|
50
|
+
"image/gif": "gif",
|
|
51
|
+
"image/bmp": "bmp",
|
|
52
|
+
"image/tiff": "tiff",
|
|
53
|
+
"image/svg+xml": "svg",
|
|
54
|
+
"image/webp": "webp",
|
|
55
|
+
"image/x-emf": "emf",
|
|
56
|
+
"image/x-wmf": "wmf",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def ext_from_content_type(content_type: str) -> str:
|
|
61
|
+
if content_type in _CONTENT_TYPE_MAP:
|
|
62
|
+
return _CONTENT_TYPE_MAP[content_type]
|
|
63
|
+
ext = content_type.split("/")[-1]
|
|
64
|
+
if "+" in ext:
|
|
65
|
+
ext = ext.split("+")[0]
|
|
66
|
+
return ext
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def print_image_summary(img_idx: int, out_dir: Path):
|
|
70
|
+
if img_idx > 0:
|
|
71
|
+
print(f"---\n{img_idx} image(s) saved: {out_dir}")
|
|
72
|
+
else:
|
|
73
|
+
print("---\nNo images")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def run_cli(extract_fn, usage_name: str, packages: dict[str, str]):
|
|
77
|
+
if len(sys.argv) < 2:
|
|
78
|
+
print(f"Usage: python {usage_name} <file>", file=sys.stderr)
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
ensure_packages(packages)
|
|
81
|
+
extract_fn(sys.argv[1])
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def normalize_cell(text) -> str:
|
|
85
|
+
if text is None:
|
|
86
|
+
return ""
|
|
87
|
+
return str(text).strip().replace("\n", " ")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def parse_heading_level(style_name: str) -> int | None:
|
|
91
|
+
m = re.match(r"Heading\s*(\d+)", style_name)
|
|
92
|
+
if m:
|
|
93
|
+
return int(m.group(1))
|
|
94
|
+
return None
|