jun-claude-code 0.0.15 → 0.0.17
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 +10 -1
- package/dist/copy.js +27 -4
- package/dist/init-context.js +76 -5
- package/package.json +1 -1
- package/templates/global/CLAUDE.md +31 -182
- package/templates/global/agents/context-manager.md +9 -0
- package/templates/global/hooks/dangerous-command-blocker.sh +67 -0
- package/templates/global/hooks/skill-forced-subagent.sh +63 -0
- package/templates/global/hooks/skill-forced.sh +6 -36
- package/templates/global/hooks/workflow-enforced.sh +4 -41
- package/templates/global/settings.json +25 -0
- package/templates/global/skills/ContextHandoff/SKILL.md +54 -0
- package/templates/global/skills/PromptStructuring/SKILL.md +10 -58
- package/templates/global/skills/PromptStructuring/output-optimization.md +66 -0
- package/templates/global/skills/PromptStructuring/positive-phrasing.md +17 -194
- package/templates/global/skills/PromptStructuring/xml-tags.md +24 -317
package/README.md
CHANGED
|
@@ -165,7 +165,16 @@ jun-claude-code init-context
|
|
|
165
165
|
└── INDEX.md # 비즈니스 도메인 참조 목록
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
**필수 설정:**
|
|
169
|
+
|
|
170
|
+
1. **Repository Actions 권한 활성화**
|
|
171
|
+
- Repository → Settings → Actions → General
|
|
172
|
+
- **Workflow permissions** 섹션에서:
|
|
173
|
+
- "Read and write permissions" 선택
|
|
174
|
+
- ✅ "Allow GitHub Actions to create and approve pull requests" 체크
|
|
175
|
+
|
|
176
|
+
2. **CLAUDE_CODE_OAUTH_TOKEN 추가**
|
|
177
|
+
- Settings → Secrets and variables → Actions → New repository secret
|
|
169
178
|
|
|
170
179
|
## 프로젝트 구조
|
|
171
180
|
|
package/dist/copy.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.copyClaudeFiles = copyClaudeFiles;
|
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const readline = __importStar(require("readline"));
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
43
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
44
45
|
/**
|
|
45
46
|
* Prompt user for confirmation using readline
|
|
@@ -57,6 +58,13 @@ function askConfirmation(question) {
|
|
|
57
58
|
});
|
|
58
59
|
});
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Calculate SHA-256 hash of a file
|
|
63
|
+
*/
|
|
64
|
+
function getFileHash(filePath) {
|
|
65
|
+
const content = fs.readFileSync(filePath);
|
|
66
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
67
|
+
}
|
|
60
68
|
/**
|
|
61
69
|
* Get all files recursively from a directory
|
|
62
70
|
*/
|
|
@@ -221,10 +229,18 @@ async function copyClaudeFiles(options = {}) {
|
|
|
221
229
|
console.log(chalk_1.default.yellow('[DRY RUN] Files that would be copied:'));
|
|
222
230
|
console.log();
|
|
223
231
|
for (const file of files) {
|
|
232
|
+
const sourcePath = path.join(sourceDir, file);
|
|
224
233
|
const destPath = path.join(destDir, file);
|
|
225
234
|
const exists = fs.existsSync(destPath);
|
|
226
|
-
|
|
227
|
-
|
|
235
|
+
if (exists) {
|
|
236
|
+
const sourceHash = getFileHash(sourcePath);
|
|
237
|
+
const destHash = getFileHash(destPath);
|
|
238
|
+
const status = sourceHash === destHash ? chalk_1.default.gray('[unchanged]') : chalk_1.default.yellow('[overwrite]');
|
|
239
|
+
console.log(` ${status} ${file}`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
console.log(` ${chalk_1.default.green('[new]')} ${file}`);
|
|
243
|
+
}
|
|
228
244
|
}
|
|
229
245
|
// settings.json merge indicator
|
|
230
246
|
const sourceSettingsExists = fs.existsSync(path.join(sourceDir, 'settings.json'));
|
|
@@ -243,8 +259,15 @@ async function copyClaudeFiles(options = {}) {
|
|
|
243
259
|
const destPath = path.join(destDir, file);
|
|
244
260
|
const exists = fs.existsSync(destPath);
|
|
245
261
|
if (exists && !force) {
|
|
246
|
-
|
|
247
|
-
const
|
|
262
|
+
const sourceHash = getFileHash(sourcePath);
|
|
263
|
+
const destHash = getFileHash(destPath);
|
|
264
|
+
if (sourceHash === destHash) {
|
|
265
|
+
console.log(` ${chalk_1.default.gray('[unchanged]')} ${file}`);
|
|
266
|
+
skippedCount++;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
// Hash differs - ask for confirmation
|
|
270
|
+
const shouldOverwrite = await askConfirmation(chalk_1.default.yellow(`File changed: ${file}. Overwrite? (y/N): `));
|
|
248
271
|
if (!shouldOverwrite) {
|
|
249
272
|
console.log(chalk_1.default.gray(` Skipped: ${file}`));
|
|
250
273
|
skippedCount++;
|
package/dist/init-context.js
CHANGED
|
@@ -39,6 +39,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.initContext = initContext;
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
|
+
const readline = __importStar(require("readline"));
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
42
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
43
45
|
/**
|
|
44
46
|
* Get the templates/project directory path (from package installation)
|
|
@@ -46,6 +48,29 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
46
48
|
function getTemplatesDir() {
|
|
47
49
|
return path.resolve(__dirname, '..', 'templates', 'project');
|
|
48
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Prompt user for confirmation using readline
|
|
53
|
+
*/
|
|
54
|
+
function askConfirmation(question) {
|
|
55
|
+
const rl = readline.createInterface({
|
|
56
|
+
input: process.stdin,
|
|
57
|
+
output: process.stdout,
|
|
58
|
+
});
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
rl.question(question, (answer) => {
|
|
61
|
+
rl.close();
|
|
62
|
+
const normalized = answer.toLowerCase().trim();
|
|
63
|
+
resolve(normalized === 'y' || normalized === 'yes');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Calculate SHA-256 hash of a file
|
|
69
|
+
*/
|
|
70
|
+
function getFileHash(filePath) {
|
|
71
|
+
const content = fs.readFileSync(filePath);
|
|
72
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
73
|
+
}
|
|
49
74
|
/**
|
|
50
75
|
* Initialize context auto-generation with GitHub Actions
|
|
51
76
|
*/
|
|
@@ -57,7 +82,21 @@ async function initContext() {
|
|
|
57
82
|
const workflowDest = path.join(cwd, '.github', 'workflows', 'context-gen.yml');
|
|
58
83
|
fs.mkdirSync(path.dirname(workflowDest), { recursive: true });
|
|
59
84
|
if (fs.existsSync(workflowDest)) {
|
|
60
|
-
|
|
85
|
+
const sourceHash = getFileHash(templateSrc);
|
|
86
|
+
const destHash = getFileHash(workflowDest);
|
|
87
|
+
if (sourceHash === destHash) {
|
|
88
|
+
console.log(chalk_1.default.gray(' [unchanged] .github/workflows/context-gen.yml'));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const shouldOverwrite = await askConfirmation(chalk_1.default.yellow(' ⚠ .github/workflows/context-gen.yml has changes. Overwrite? (y/N): '));
|
|
92
|
+
if (shouldOverwrite) {
|
|
93
|
+
fs.copyFileSync(templateSrc, workflowDest);
|
|
94
|
+
console.log(chalk_1.default.green(' ✓ Replaced .github/workflows/context-gen.yml'));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.log(chalk_1.default.gray(' Skipped: .github/workflows/context-gen.yml'));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
61
100
|
}
|
|
62
101
|
else {
|
|
63
102
|
fs.copyFileSync(templateSrc, workflowDest);
|
|
@@ -68,7 +107,21 @@ async function initContext() {
|
|
|
68
107
|
const agentDest = path.join(cwd, '.claude', 'agents', 'context-generator.md');
|
|
69
108
|
fs.mkdirSync(path.dirname(agentDest), { recursive: true });
|
|
70
109
|
if (fs.existsSync(agentDest)) {
|
|
71
|
-
|
|
110
|
+
const sourceHash = getFileHash(agentSrc);
|
|
111
|
+
const destHash = getFileHash(agentDest);
|
|
112
|
+
if (sourceHash === destHash) {
|
|
113
|
+
console.log(chalk_1.default.gray(' [unchanged] .claude/agents/context-generator.md'));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const shouldOverwrite = await askConfirmation(chalk_1.default.yellow(' ⚠ .claude/agents/context-generator.md has changes. Overwrite? (y/N): '));
|
|
117
|
+
if (shouldOverwrite) {
|
|
118
|
+
fs.copyFileSync(agentSrc, agentDest);
|
|
119
|
+
console.log(chalk_1.default.green(' ✓ Replaced .claude/agents/context-generator.md'));
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.log(chalk_1.default.gray(' Skipped: .claude/agents/context-generator.md'));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
72
125
|
}
|
|
73
126
|
else {
|
|
74
127
|
fs.copyFileSync(agentSrc, agentDest);
|
|
@@ -79,7 +132,21 @@ async function initContext() {
|
|
|
79
132
|
const skillDest = path.join(cwd, '.claude', 'skills', 'ContextGeneration', 'SKILL.md');
|
|
80
133
|
fs.mkdirSync(path.dirname(skillDest), { recursive: true });
|
|
81
134
|
if (fs.existsSync(skillDest)) {
|
|
82
|
-
|
|
135
|
+
const sourceHash = getFileHash(skillSrc);
|
|
136
|
+
const destHash = getFileHash(skillDest);
|
|
137
|
+
if (sourceHash === destHash) {
|
|
138
|
+
console.log(chalk_1.default.gray(' [unchanged] .claude/skills/ContextGeneration/SKILL.md'));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const shouldOverwrite = await askConfirmation(chalk_1.default.yellow(' ⚠ .claude/skills/ContextGeneration/SKILL.md has changes. Overwrite? (y/N): '));
|
|
142
|
+
if (shouldOverwrite) {
|
|
143
|
+
fs.copyFileSync(skillSrc, skillDest);
|
|
144
|
+
console.log(chalk_1.default.green(' ✓ Replaced .claude/skills/ContextGeneration/SKILL.md'));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(chalk_1.default.gray(' Skipped: .claude/skills/ContextGeneration/SKILL.md'));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
83
150
|
}
|
|
84
151
|
else {
|
|
85
152
|
fs.copyFileSync(skillSrc, skillDest);
|
|
@@ -136,8 +203,12 @@ description: 비즈니스 도메인 참조 목록
|
|
|
136
203
|
// 6. 안내 메시지
|
|
137
204
|
console.log(chalk_1.default.bold('\n✅ Context auto-generation setup complete!\n'));
|
|
138
205
|
console.log(chalk_1.default.cyan('Next steps:'));
|
|
139
|
-
console.log(chalk_1.default.cyan(' 1.
|
|
206
|
+
console.log(chalk_1.default.cyan(' 1. Enable GitHub Actions permissions:'));
|
|
207
|
+
console.log(chalk_1.default.cyan(' → Repository > Settings > Actions > General'));
|
|
208
|
+
console.log(chalk_1.default.cyan(' → Workflow permissions: "Read and write permissions"'));
|
|
209
|
+
console.log(chalk_1.default.cyan(' → ✅ "Allow GitHub Actions to create and approve pull requests"'));
|
|
210
|
+
console.log(chalk_1.default.cyan(' 2. Add CLAUDE_CODE_OAUTH_TOKEN to your repository secrets'));
|
|
140
211
|
console.log(chalk_1.default.cyan(' → Settings > Secrets and variables > Actions > New repository secret'));
|
|
141
|
-
console.log(chalk_1.default.cyan('
|
|
212
|
+
console.log(chalk_1.default.cyan(' 3. Create a PR to trigger context auto-generation'));
|
|
142
213
|
console.log('');
|
|
143
214
|
}
|
package/package.json
CHANGED
|
@@ -1,177 +1,48 @@
|
|
|
1
1
|
# Claude Code 작업 가이드
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Main Agent의 Context Window는 제한적입니다.
|
|
8
|
-
**Subagent가 할 수 있는 작업은 Subagent에 위임하세요.**
|
|
9
|
-
|
|
10
|
-
### 필수 위임 작업 (Subagent 전담)
|
|
11
|
-
|
|
12
|
-
| 작업 | Agent | 이유 |
|
|
13
|
-
|------|-------|------|
|
|
14
|
-
| 코드베이스 탐색/검색 | `explore` | 파일 내용이 Main Context에 쌓이지 않음 |
|
|
15
|
-
| 여러 파일 읽기 | `explore`, `context-collector` | 탐색 결과만 요약해서 받음 |
|
|
16
|
-
| .claude/context/ 문서 수집 | `project-context-collector` | 프로젝트 배경 정보만 요약해서 받음 |
|
|
17
|
-
| 코드 패턴/구조 파악 | `context-collector` | 분석 결과만 받음 |
|
|
18
|
-
| 복잡한 계획 수립 | `task-planner` | 계획 결과만 받음 |
|
|
19
|
-
| 영향 분석 | `impact-analyzer` | 분석 결과만 받음 |
|
|
20
|
-
| 코드 리뷰 | `code-reviewer` | 리뷰 결과만 받음 |
|
|
21
|
-
| 테스트/빌드 검증 | `qa-tester` | 검증 결과만 받음 |
|
|
22
|
-
| 단순 수정 (lint/build 오류, 오타, 설정값) | `simple-code-writer` | Main Context 보존 |
|
|
23
|
-
| 여러 파일 코드 작성 | `code-writer` | 구현 결과만 받음 |
|
|
24
|
-
| Git 작업 | `git-manager` | 커밋/PR 결과만 받음 |
|
|
25
|
-
| Context 문서 정리 | `context-manager` | 파일 분리, 토큰 최적화 |
|
|
3
|
+
## Context 절약 원칙
|
|
4
|
+
|
|
5
|
+
Main Agent의 Context Window는 제한적입니다. Subagent가 할 수 있는 작업은 Subagent에 위임합니다.
|
|
26
6
|
|
|
27
7
|
<delegation_rules>
|
|
28
8
|
|
|
29
|
-
###
|
|
9
|
+
### 위임 규칙
|
|
30
10
|
|
|
31
11
|
| 작업 | 전담 Agent |
|
|
32
12
|
|------|-----------|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
| 복잡한
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
42
|
-
|
|
13
|
+
| 코드베이스 탐색/검색 | `explore` |
|
|
14
|
+
| 여러 파일 읽기 | `explore`, `context-collector` |
|
|
15
|
+
| .claude/context/ 문서 수집 | `project-context-collector` |
|
|
16
|
+
| 코드 패턴/구조 파악 | `context-collector` |
|
|
17
|
+
| 복잡한 계획 수립 | `task-planner` |
|
|
18
|
+
| 영향 분석 | `impact-analyzer` |
|
|
19
|
+
| 코드 리뷰 | `code-reviewer` |
|
|
20
|
+
| 테스트/빌드 검증 | `qa-tester` |
|
|
21
|
+
| 단순 수정 (lint, 오타, 설정값) | `simple-code-writer` (haiku) |
|
|
22
|
+
| 로직 작성, 기능 구현, 리팩토링 | `code-writer` (opus) |
|
|
23
|
+
| Git 작업 (commit, PR, branch) | `git-manager` |
|
|
24
|
+
| Context 문서 정리 | `context-manager` |
|
|
25
|
+
|
|
26
|
+
### Main Agent 전담
|
|
43
27
|
|
|
44
28
|
- 사용자와 대화/질문 응답
|
|
45
29
|
- Task 흐름 관리 (TaskCreate, TaskUpdate, TaskList)
|
|
46
30
|
- Subagent 호출 및 결과 전달
|
|
47
|
-
- 단순 명령 실행 (Bash) - **Git/코드수정은 Subagent 전담**
|
|
48
31
|
|
|
49
32
|
</delegation_rules>
|
|
50
33
|
|
|
51
|
-
### 코드 수정 위임 규칙
|
|
52
|
-
|
|
53
|
-
모든 코드 수정은 Subagent가 전담합니다.
|
|
54
|
-
|
|
55
|
-
| 수정 유형 | Agent | 모델 |
|
|
56
|
-
|----------|-------|------|
|
|
57
|
-
| lint/build 오류 수정, 오타, 설정값 변경 등 단순 수정 | `simple-code-writer` | haiku |
|
|
58
|
-
| 로직 작성, 기능 구현, 리팩토링 (파일 수 무관) | `code-writer` | opus |
|
|
59
|
-
|
|
60
|
-
### Git 작업은 Subagent 전담
|
|
61
|
-
|
|
62
|
-
**모든 Git 작업은 `git-manager` Agent에 위임하세요.**
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
Task(subagent_type="git-manager", prompt="현재 변경사항을 커밋해줘")
|
|
66
|
-
Task(subagent_type="git-manager", prompt="PR을 생성해줘")
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 왜 Subagent를 사용해야 하는가?
|
|
70
|
-
|
|
71
|
-
1. **Context 절약**: Subagent의 탐색/분석 결과는 요약되어 Main에 전달
|
|
72
|
-
2. **대화 지속성**: Main Context가 절약되어 더 긴 대화 가능
|
|
73
|
-
3. **전문성**: 각 Agent는 특정 작업에 최적화됨
|
|
74
|
-
4. **병렬 처리**: 여러 Agent를 동시에 실행 가능
|
|
75
|
-
|
|
76
|
-
### 코드 작성 위임 기준
|
|
77
|
-
|
|
78
|
-
| 상황 | 처리 |
|
|
79
|
-
|------|------|
|
|
80
|
-
| lint/build 오류, 오타, 설정값 등 단순 수정 | `simple-code-writer` Agent에 위임 |
|
|
81
|
-
| 로직 작성, 기능 구현, 리팩토링 | `code-writer` Agent에 위임 |
|
|
82
|
-
|
|
83
34
|
<workflow>
|
|
84
35
|
|
|
85
|
-
## 작업 워크플로우
|
|
86
|
-
|
|
87
|
-
모든 코드 작업은 아래 순서를 따릅니다:
|
|
88
|
-
|
|
89
|
-
<phase name="계획">
|
|
90
|
-
|
|
91
|
-
### Phase 1: 계획 (Planning)
|
|
92
|
-
|
|
93
|
-
```
|
|
94
|
-
1. Context 수집
|
|
95
|
-
- EnterPlanMode 진입
|
|
96
|
-
- 관련 Context 문서 확인 (.claude/context/)
|
|
97
|
-
- 필요한 Skill 활성화 (.claude/skills/)
|
|
98
|
-
- 기존 코드 탐색 (Explore Agent)
|
|
99
|
-
|
|
100
|
-
2. TaskList 생성
|
|
101
|
-
- 작업을 작은 단위로 분해
|
|
102
|
-
- 각 Task에 명확한 완료 조건 정의
|
|
103
|
-
- Task 간 의존성 설정
|
|
104
|
-
|
|
105
|
-
3. 코드 수정 계획 작성
|
|
106
|
-
- 수정할 파일 목록
|
|
107
|
-
- 각 파일의 변경 내용 요약
|
|
108
|
-
- 예상되는 영향 범위
|
|
109
|
-
|
|
110
|
-
4. 작성된 내용을 사용자에게 Confirm 받음 **필수**
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
</phase>
|
|
114
|
-
|
|
115
|
-
<phase name="검증">
|
|
116
|
-
|
|
117
|
-
### Phase 2: 검증 (Validation)
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
4. 사이드이펙트 검증
|
|
121
|
-
- 코드 Flow 분석: 변경이 다른 모듈에 미치는 영향
|
|
122
|
-
- UI/UX UserFlow 분석: 사용자 경험에 미치는 영향
|
|
123
|
-
- Breaking Change 여부 확인
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
</phase>
|
|
127
|
-
|
|
128
|
-
<phase name="구현">
|
|
129
|
-
|
|
130
|
-
### Phase 3: 구현 (Implementation)
|
|
131
|
-
|
|
132
|
-
```
|
|
133
|
-
5. 작은 단위로 코드 수정
|
|
134
|
-
- 독립적으로 빌드 가능한 단위로 작업
|
|
135
|
-
- 한 번에 하나의 기능/수정만 진행
|
|
136
|
-
- 빌드 가능 상태를 유지
|
|
137
|
-
|
|
138
|
-
6. 단위별 커밋
|
|
139
|
-
- 수정한 파일만 개별 지정하여 git add
|
|
140
|
-
- 명확한 커밋 메시지 작성
|
|
141
|
-
- 커밋 단위: 하나의 논리적 변경
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
</phase>
|
|
145
|
-
|
|
146
|
-
<phase name="리뷰">
|
|
147
|
-
|
|
148
|
-
### Phase 4: 리뷰 (Review)
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
7. Self Code Review
|
|
152
|
-
- 작성한 코드가 프로젝트 규칙을 준수하는지 확인
|
|
153
|
-
- lint 실행
|
|
154
|
-
|
|
155
|
-
8. Task 완료 검증
|
|
156
|
-
- 원래 요청사항이 모두 충족되었는지 확인
|
|
157
|
-
- 예상한 동작이 구현되었는지 확인
|
|
158
|
-
- 모든 엣지케이스가 처리되었는지 점검
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
</phase>
|
|
162
|
-
|
|
163
|
-
### 워크플로우 요약
|
|
36
|
+
## 작업 워크플로우
|
|
164
37
|
|
|
165
38
|
```
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
│ 7. Self Code Review → 8. Task 완료 검증 │
|
|
174
|
-
└─────────────────────────────────────────────────────────────┘
|
|
39
|
+
1. Context 수집 → 2. TaskList 생성 → 3. 수정 계획 (사용자 Confirm 필수)
|
|
40
|
+
↓
|
|
41
|
+
4. 사이드이펙트 검증 (Code Flow, UserFlow, Breaking Change)
|
|
42
|
+
↓
|
|
43
|
+
5. 코드 수정 (작은 단위) → 6. 단위별 커밋
|
|
44
|
+
↓
|
|
45
|
+
7. Self Code Review (lint) → 8. Task 완료 검증
|
|
175
46
|
```
|
|
176
47
|
|
|
177
48
|
</workflow>
|
|
@@ -180,33 +51,11 @@ Task(subagent_type="git-manager", prompt="PR을 생성해줘")
|
|
|
180
51
|
|
|
181
52
|
<reference>
|
|
182
53
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
### Skills (방법/절차) - "이렇게 해라"
|
|
188
|
-
|
|
189
|
-
| 작업 | 위치 |
|
|
190
|
-
|-----|------|
|
|
54
|
+
| 유형 | 위치 |
|
|
55
|
+
|------|------|
|
|
56
|
+
| 프로젝트 배경 정보 | `.claude/context/` |
|
|
191
57
|
| 공통 코딩 원칙 | `.claude/skills/Coding/SKILL.md` |
|
|
192
|
-
| Git
|
|
193
|
-
|
|
|
194
|
-
| PR 피드백 적용 | `.claude/skills/Git/pr-apply.md` |
|
|
58
|
+
| Git 규칙 | `.claude/skills/Git/SKILL.md` |
|
|
59
|
+
| 문서 작성 가이드 | `.claude/skills/Documentation/SKILL.md` |
|
|
195
60
|
|
|
196
61
|
</reference>
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## .claude 문서 작성 가이드
|
|
201
|
-
|
|
202
|
-
`.claude/skills/Documentation/SKILL.md` 참조
|
|
203
|
-
|
|
204
|
-
### 핵심 요약
|
|
205
|
-
|
|
206
|
-
| 항목 | 내용 |
|
|
207
|
-
|------|------|
|
|
208
|
-
| 디렉토리 | `context/` (사실), `skills/` (방법), `agents/` (역할) |
|
|
209
|
-
| 파일 길이 | ~500줄 권장, 1000줄 초과 시 분리 |
|
|
210
|
-
| 필수 작성 | YAML frontmatter (name, description, keywords) |
|
|
211
|
-
|
|
212
|
-
상세 내용은 **Documentation Skill**을 참조하세요.
|
|
@@ -121,6 +121,14 @@ estimated_tokens: ~200
|
|
|
121
121
|
- 다른 문서와 중복되는 내용
|
|
122
122
|
- 더 이상 사용하지 않는 패턴
|
|
123
123
|
|
|
124
|
+
**Hook/프롬프트 출력 최적화:** (Context 문서 외 추가 대상)
|
|
125
|
+
- Hook 스크립트의 cat/echo 출력물도 최적화 대상
|
|
126
|
+
- 중복 텍스트 제거 (CLAUDE.md와 Hook 간 중복)
|
|
127
|
+
- 테이블 축약 (불필요한 컬럼 제거)
|
|
128
|
+
- 설명문 → 키워드 변환
|
|
129
|
+
- 예시 코드 블록 최소화
|
|
130
|
+
- 참조: `~/.claude/skills/PromptStructuring/output-optimization.md`
|
|
131
|
+
|
|
124
132
|
</instructions>
|
|
125
133
|
|
|
126
134
|
---
|
|
@@ -132,6 +140,7 @@ estimated_tokens: ~200
|
|
|
132
140
|
- "이 문서 너무 긴데 분리해줘"
|
|
133
141
|
- "context 토큰 사용량 줄여줘"
|
|
134
142
|
- "중복된 내용 정리해줘"
|
|
143
|
+
- "Hook 출력을 최적화해줘"
|
|
135
144
|
```
|
|
136
145
|
|
|
137
146
|
---
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# .claude/hooks/dangerous-command-blocker.sh
|
|
4
|
+
# Dangerous Command Blocker - PreToolUse Hook
|
|
5
|
+
# Bash 도구 실행 전 위험한 명령어를 감지하여 차단합니다.
|
|
6
|
+
|
|
7
|
+
INPUT=$(cat)
|
|
8
|
+
|
|
9
|
+
# jq가 있으면 jq로, 없으면 grep/sed로 command 추출
|
|
10
|
+
if command -v jq &>/dev/null; then
|
|
11
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
|
|
12
|
+
else
|
|
13
|
+
# jq 없이 JSON에서 command 값 추출 (fallback)
|
|
14
|
+
COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\(.*\)"/\1/p' | head -1)
|
|
15
|
+
# 이스케이프된 따옴표 복원
|
|
16
|
+
COMMAND=$(echo "$COMMAND" | sed 's/\\"/"/g')
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# command가 비어있으면 허용
|
|
20
|
+
if [ -z "$COMMAND" ]; then
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# 차단 함수
|
|
25
|
+
block() {
|
|
26
|
+
echo "{\"decision\": \"block\", \"reason\": \"$1\"}"
|
|
27
|
+
exit 0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# 1. 위험한 rm 명령어 (루트/홈/현재 디렉토리 전체 삭제)
|
|
31
|
+
if echo "$COMMAND" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|(-[a-zA-Z]*f[a-zA-Z]*r))\s+/[[:space:]]*($|;|\||&)'; then
|
|
32
|
+
block "rm -rf / 는 시스템 전체를 삭제합니다. 이 명령어는 차단됩니다."
|
|
33
|
+
fi
|
|
34
|
+
if echo "$COMMAND" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|(-[a-zA-Z]*f[a-zA-Z]*r))\s+~/?\s*($|;|\||&)'; then
|
|
35
|
+
block "rm -rf ~ 는 홈 디렉토리 전체를 삭제합니다. 이 명령어는 차단됩니다."
|
|
36
|
+
fi
|
|
37
|
+
if echo "$COMMAND" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|(-[a-zA-Z]*f[a-zA-Z]*r))\s+\./?\s*($|;|\||&)'; then
|
|
38
|
+
block "rm -rf . 는 현재 디렉토리 전체를 삭제합니다. 이 명령어는 차단됩니다."
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# 2. sudo 명령어 (명시적 요청 없이 권한 상승)
|
|
42
|
+
if echo "$COMMAND" | grep -qE '(^|;|\||&&)\s*sudo\s'; then
|
|
43
|
+
block "sudo 명령어는 명시적 요청 없이 사용할 수 없습니다. 사용자에게 확인하세요."
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# 3. git push --force / -f (강제 푸시)
|
|
47
|
+
if echo "$COMMAND" | grep -qE 'git\s+push\s+.*(-f|--force)'; then
|
|
48
|
+
block "git push --force 는 원격 히스토리를 덮어씁니다. 이 명령어는 차단됩니다."
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# 4. git reset --hard (하드 리셋)
|
|
52
|
+
if echo "$COMMAND" | grep -qE 'git\s+reset\s+--hard'; then
|
|
53
|
+
block "git reset --hard 는 커밋되지 않은 변경사항을 모두 삭제합니다. 이 명령어는 차단됩니다."
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# 5. chmod 777 (과도한 권한)
|
|
57
|
+
if echo "$COMMAND" | grep -qE 'chmod\s+777'; then
|
|
58
|
+
block "chmod 777 은 과도한 권한을 부여합니다. 보안상 차단됩니다."
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# 6. 원격 스크립트 직접 실행 (curl/wget | sh/bash)
|
|
62
|
+
if echo "$COMMAND" | grep -qE '(curl|wget)\s+.*\|\s*(sh|bash)'; then
|
|
63
|
+
block "원격 스크립트를 직접 실행하는 것은 보안 위험이 있습니다. 이 명령어는 차단됩니다."
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# 모든 체크 통과 시 허용
|
|
67
|
+
exit 0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# .claude/hooks/skill-forced-subagent.sh
|
|
4
|
+
# Subagent용 Skill 평가 프로토콜 - SubagentStart hook
|
|
5
|
+
# Subagent가 작업 시작 전 관련 Skills를 평가하고 활성화하도록 유도
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
CLAUDE_DIR="$(dirname "$SCRIPT_DIR")"
|
|
9
|
+
GLOBAL_CLAUDE_DIR="$HOME/.claude"
|
|
10
|
+
PROJECT_CLAUDE_DIR="$(pwd)/.claude"
|
|
11
|
+
|
|
12
|
+
echo "✅ [Hook] Subagent Skill 평가 프로토콜 실행됨"
|
|
13
|
+
|
|
14
|
+
cat << 'EOF'
|
|
15
|
+
SKILL EVALUATION (Subagent)
|
|
16
|
+
|
|
17
|
+
<phase name="Skill 평가">
|
|
18
|
+
|
|
19
|
+
각 Skill을 YES/NO로 평가하고, YES인 Skill의 SKILL.md를 읽으세요.
|
|
20
|
+
|
|
21
|
+
### 사용 가능한 Skills (자동 탐색됨)
|
|
22
|
+
|
|
23
|
+
</phase>
|
|
24
|
+
EOF
|
|
25
|
+
|
|
26
|
+
# skills 폴더에서 SKILL.md 파일들의 frontmatter 자동 탐색
|
|
27
|
+
# 프로젝트 .claude/ 와 ~/.claude/ 양쪽에서 탐색 (프로젝트 우선, 중복 제거)
|
|
28
|
+
SEEN_SKILLS=""
|
|
29
|
+
for search_dir in "$PROJECT_CLAUDE_DIR" "$GLOBAL_CLAUDE_DIR"; do
|
|
30
|
+
if [ -d "$search_dir/skills" ]; then
|
|
31
|
+
for skill_dir in "$search_dir/skills"/*/; do
|
|
32
|
+
if [ -d "$skill_dir" ]; then
|
|
33
|
+
skill_name=$(basename "$skill_dir")
|
|
34
|
+
skill_file="$skill_dir/SKILL.md"
|
|
35
|
+
|
|
36
|
+
# 이미 탐색된 Skill은 건너뜀
|
|
37
|
+
case "$SEEN_SKILLS" in
|
|
38
|
+
*"|${skill_name}|"*) continue ;;
|
|
39
|
+
esac
|
|
40
|
+
SEEN_SKILLS="${SEEN_SKILLS}|${skill_name}|"
|
|
41
|
+
|
|
42
|
+
if [ -f "$skill_file" ]; then
|
|
43
|
+
# 출처 표시
|
|
44
|
+
if [ "$search_dir" = "$PROJECT_CLAUDE_DIR" ]; then
|
|
45
|
+
display_path=".claude/skills/$skill_name/SKILL.md"
|
|
46
|
+
else
|
|
47
|
+
display_path="~/.claude/skills/$skill_name/SKILL.md"
|
|
48
|
+
fi
|
|
49
|
+
echo "**[$skill_name]** \`$display_path\`"
|
|
50
|
+
echo '```yaml'
|
|
51
|
+
head -6 "$skill_file"
|
|
52
|
+
echo '```'
|
|
53
|
+
echo ""
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
done
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
cat << 'EOF'
|
|
61
|
+
|
|
62
|
+
관련 Skill 확인 후 작업을 시작하세요. Skill 규칙을 준수하세요.
|
|
63
|
+
EOF
|
|
@@ -48,27 +48,7 @@ Main Agent의 Context Window는 제한적입니다.
|
|
|
48
48
|
- Subagent 호출 및 결과 전달
|
|
49
49
|
- 단순 명령 실행 (Bash) - **Git/코드수정은 Subagent 전담**
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
**모든 Git 작업은 `git-manager` Agent에 위임하세요.**
|
|
54
|
-
|
|
55
|
-
\`\`\`
|
|
56
|
-
Task(subagent_type="git-manager", prompt="현재 변경사항을 커밋해줘")
|
|
57
|
-
Task(subagent_type="git-manager", prompt="PR을 생성해줘")
|
|
58
|
-
\`\`\`
|
|
59
|
-
|
|
60
|
-
| Git 작업 | 전담 여부 | 이유 |
|
|
61
|
-
|----------|----------|------|
|
|
62
|
-
| 단순 커밋 | **전담** | 커밋 규칙 자동 준수 |
|
|
63
|
-
| PR 생성 | **전담** | PR 템플릿 자동 적용 |
|
|
64
|
-
| 브랜치 관리 | **전담** | 안전 규칙 자동 적용 |
|
|
65
|
-
|
|
66
|
-
### 왜 Subagent를 사용해야 하는가?
|
|
67
|
-
|
|
68
|
-
1. **Context 절약**: Subagent의 탐색/분석 결과는 요약되어 Main에 전달
|
|
69
|
-
2. **대화 지속성**: Main Context가 절약되어 더 긴 대화 가능
|
|
70
|
-
3. **전문성**: 각 Agent는 특정 작업에 최적화됨
|
|
71
|
-
4. **병렬 처리**: 여러 Agent를 동시에 실행 가능
|
|
51
|
+
모든 Git 작업(커밋, PR, 브랜치)은 git-manager에 위임
|
|
72
52
|
|
|
73
53
|
</delegation_rules>
|
|
74
54
|
|
|
@@ -133,16 +113,10 @@ cat << 'EOF'
|
|
|
133
113
|
아래는 이 프로젝트의 배경 정보입니다. 작업 판단 시 참고하세요.
|
|
134
114
|
상세 분석이 필요하면 아래 Agent에 위임하세요.
|
|
135
115
|
|
|
136
|
-
| 필요한 정보 | Agent |
|
|
137
|
-
|
|
138
|
-
| 프로젝트 배경/도메인 지식 | project-context-collector |
|
|
139
|
-
| 소스 코드 패턴/구현 방식 | context-collector |
|
|
140
|
-
|
|
141
|
-
두 Agent를 순차적으로 사용하면 가장 포괄적인 Context를 수집할 수 있습니다:
|
|
142
|
-
\`\`\`
|
|
143
|
-
1. project-context-collector → 프로젝트 배경 수집
|
|
144
|
-
2. context-collector → 소스 코드 패턴 수집
|
|
145
|
-
\`\`\`
|
|
116
|
+
| 필요한 정보 | Agent |
|
|
117
|
+
|------------|-------|
|
|
118
|
+
| 프로젝트 배경/도메인 지식 | project-context-collector |
|
|
119
|
+
| 소스 코드 패턴/구현 방식 | context-collector |
|
|
146
120
|
|
|
147
121
|
EOF
|
|
148
122
|
|
|
@@ -263,11 +237,7 @@ Step 5 - 구현: 모든 관련 Skill 확인 및 Agent 호출 후에 구현을
|
|
|
263
237
|
|
|
264
238
|
---
|
|
265
239
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
- **탐색 작업은 Subagent 전담**: Main Context 절약
|
|
269
|
-
- **구현 후 검증 수행**: code-reviewer + qa-tester
|
|
270
|
-
- **단순 작업은 예외**: 설정 파일 수정, 오타 수정은 직접 처리 가능
|
|
240
|
+
탐색은 Subagent 전담, 구현 후 검증(code-reviewer + qa-tester), 단순 작업은 직접 처리 가능
|
|
271
241
|
|
|
272
242
|
지금 바로 모든 사용 가능한 Skill과 Agent를 평가하세요.
|
|
273
243
|
|