jun-claude-code 0.0.11 → 0.0.12
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 +104 -83
- package/dist/cli.js +18 -0
- package/dist/copy.js +92 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/init-context.d.ts +4 -0
- package/dist/init-context.js +121 -0
- package/dist/init-project.js +4 -4
- package/package.json +2 -2
- package/templates/global/agents/context-generator.md +66 -0
- package/{.claude → templates/global}/agents/context-manager.md +1 -1
- package/{.claude → templates/global}/agents/explore.md +1 -1
- package/{.claude → templates/global}/agents/simple-code-writer.md +1 -1
- package/{.claude → templates/global}/hooks/skill-forced.sh +2 -12
- package/templates/global/skills/ContextGeneration/SKILL.md +152 -0
- package/templates/project/workflows/context-gen.yml +52 -0
- /package/{.claude → templates/global}/CLAUDE.md +0 -0
- /package/{.claude → templates/global}/agents/architect.md +0 -0
- /package/{.claude → templates/global}/agents/code-reviewer.md +0 -0
- /package/{.claude → templates/global}/agents/code-writer.md +0 -0
- /package/{.claude → templates/global}/agents/context-collector.md +0 -0
- /package/{.claude → templates/global}/agents/designer.md +0 -0
- /package/{.claude → templates/global}/agents/director.md +0 -0
- /package/{.claude → templates/global}/agents/git-manager.md +0 -0
- /package/{.claude → templates/global}/agents/impact-analyzer.md +0 -0
- /package/{.claude → templates/global}/agents/qa-tester.md +0 -0
- /package/{.claude → templates/global}/agents/task-planner.md +0 -0
- /package/{.claude → templates/global}/hooks/workflow-enforced.sh +0 -0
- /package/{.claude → templates/global}/settings.json +0 -0
- /package/{.claude → templates/global}/skills/Backend/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/Coding/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/Director/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/Documentation/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/Git/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/Git/git.md +0 -0
- /package/{.claude → templates/global}/skills/Git/pr-apply.md +0 -0
- /package/{.claude → templates/global}/skills/Git/pr-review.md +0 -0
- /package/{.claude → templates/global}/skills/React/SKILL.md +0 -0
- /package/{.claude → templates/global}/skills/React/react-hook-form.md +0 -0
- /package/{.claude → templates/global}/skills/React/tailwind-styled.md +0 -0
- /package/{.claude → templates/global}/skills/React/tanstack-router.md +0 -0
- /package/{.claude → templates/project}/agents/project-task-manager.md +0 -0
- /package/{.claude → templates/project}/hooks/task-loader.sh +0 -0
- /package/{.claude → templates/project}/project.env.example +0 -0
package/README.md
CHANGED
|
@@ -1,140 +1,161 @@
|
|
|
1
1
|
# jun-claude-code
|
|
2
2
|
|
|
3
|
-
Claude Code 설정 템플릿 CLI
|
|
3
|
+
Claude Code 설정 템플릿 CLI. 미리 정의된 Agents, Skills, Hooks, Workflow를 프로젝트에 설치하여 Claude Code 환경을 빠르게 구축합니다.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# npx로 바로 실행
|
|
9
|
-
npx jun-claude-code
|
|
10
|
-
|
|
11
|
-
# 또는 전역 설치
|
|
12
|
-
npm install -g jun-claude-code
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## 사용법
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# 기본 실행 (기존 파일이 있으면 덮어쓰기 확인)
|
|
19
|
-
jun-claude-code
|
|
20
|
-
|
|
21
|
-
# 미리보기 (실제 복사 없이 복사될 파일 목록 확인)
|
|
22
|
-
jun-claude-code --dry-run
|
|
23
|
-
|
|
24
|
-
# 강제 덮어쓰기 (확인 없이 모든 파일 복사)
|
|
25
|
-
jun-claude-code --force
|
|
26
|
-
```
|
|
5
|
+
## 포함 내용
|
|
27
6
|
|
|
28
|
-
|
|
7
|
+
### Agents (`templates/global/agents/`)
|
|
29
8
|
|
|
30
|
-
|
|
9
|
+
작업별 전문 Subagent 15종. Main Agent의 Context Window를 절약하면서 각 작업을 위임합니다.
|
|
31
10
|
|
|
32
|
-
| Agent |
|
|
11
|
+
| Agent | 역할 |
|
|
33
12
|
|-------|------|
|
|
34
|
-
| `explore` |
|
|
13
|
+
| `explore` | 코드베이스 탐색 |
|
|
35
14
|
| `task-planner` | 작업 계획 수립 |
|
|
36
|
-
| `code-writer` | 코드 작성 |
|
|
15
|
+
| `code-writer` | 코드 작성 (Opus) |
|
|
16
|
+
| `simple-code-writer` | 단순 수정 (Haiku) |
|
|
37
17
|
| `code-reviewer` | 셀프 코드 리뷰 |
|
|
38
|
-
| `git-manager` | Git
|
|
18
|
+
| `git-manager` | Git 커밋/PR |
|
|
39
19
|
| `impact-analyzer` | 사이드이펙트 분석 |
|
|
40
20
|
| `qa-tester` | 테스트/빌드 검증 |
|
|
41
21
|
| `architect` | 아키텍처 설계 |
|
|
42
22
|
| `designer` | UI/UX 스타일링 |
|
|
23
|
+
| `director` | 작업 총괄 디렉터 |
|
|
43
24
|
| `context-collector` | Context 수집 |
|
|
44
25
|
| `context-manager` | Context 문서 관리 |
|
|
26
|
+
| `context-generator` | Context 자동 생성 |
|
|
27
|
+
| `project-task-manager` | GitHub Project 태스크 관리 |
|
|
45
28
|
|
|
46
|
-
### Skills (
|
|
29
|
+
### Skills (`templates/global/skills/`)
|
|
47
30
|
|
|
48
31
|
| Skill | 설명 |
|
|
49
32
|
|-------|------|
|
|
50
33
|
| `Coding` | 공통 코딩 원칙 (SRP, 응집도, 가독성) |
|
|
51
|
-
| `Git` | Git 커밋/PR
|
|
34
|
+
| `Git` | Git 커밋/PR 규칙, PR 리뷰, 피드백 적용 |
|
|
52
35
|
| `Backend` | 백엔드 개발 원칙 (레이어, TypeORM) |
|
|
36
|
+
| `React` | React 개발 (TanStack Router, React Hook Form, Tailwind) |
|
|
37
|
+
| `Documentation` | .claude 문서 작성 가이드 |
|
|
38
|
+
| `Director` | 디렉터 Agent 운영 스킬 |
|
|
39
|
+
| `ContextGeneration` | Context 자동 생성 스킬 |
|
|
53
40
|
|
|
54
|
-
### Hooks (
|
|
41
|
+
### Hooks (`templates/global/hooks/`)
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
| Hook | 설명 |
|
|
44
|
+
|------|------|
|
|
45
|
+
| `workflow-enforced.sh` | 워크플로우 순서 강제 프로토콜 |
|
|
46
|
+
| `skill-forced.sh` | Skill/Agent 평가 프로토콜 |
|
|
47
|
+
| `task-loader.sh` | GitHub Project 태스크 조회 |
|
|
58
48
|
|
|
59
|
-
|
|
49
|
+
### Workflow
|
|
60
50
|
|
|
61
|
-
|
|
51
|
+
Planning -> Validation -> Implementation -> Review 순서의 작업 워크플로우와 Context 절약 원칙(Subagent 위임 규칙)을 정의합니다.
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
## 설치
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# npx로 바로 실행
|
|
57
|
+
npx jun-claude-code
|
|
58
|
+
|
|
59
|
+
# 또는 전역 설치
|
|
60
|
+
npm install -g jun-claude-code
|
|
70
61
|
```
|
|
71
62
|
|
|
72
|
-
|
|
63
|
+
## 사용법
|
|
73
64
|
|
|
74
|
-
|
|
65
|
+
### 기본 명령어: 설정 복사
|
|
75
66
|
|
|
67
|
+
`templates/global` 설정 파일을 `~/.claude`로 복사합니다.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
jun-claude-code
|
|
76
71
|
```
|
|
77
|
-
your-project/
|
|
78
|
-
├── .claude/
|
|
79
|
-
│ ├── context/ # 프로젝트 아키텍처, 도메인 지식
|
|
80
|
-
│ └── skills/ # 프로젝트 전용 스킬
|
|
81
|
-
└── CLAUDE.md # 프로젝트 설명
|
|
82
|
-
```
|
|
83
72
|
|
|
84
|
-
|
|
73
|
+
| 옵션 | 설명 |
|
|
74
|
+
|------|------|
|
|
75
|
+
| `--dry-run`, `-d` | 실제 복사 없이 복사될 파일 목록만 확인 |
|
|
76
|
+
| `--force`, `-f` | 확인 없이 모든 파일 덮어쓰기 |
|
|
77
|
+
|
|
78
|
+
### `init-project`: GitHub Project 연동
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
프로젝트 디렉토리에서 GitHub Project 태스크 관리를 설정합니다.
|
|
87
81
|
|
|
88
82
|
```bash
|
|
89
|
-
# 프로젝트 루트에서 실행
|
|
90
83
|
jun-claude-code init-project
|
|
91
84
|
```
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
3. **Repository** (owner/repo 형식)
|
|
86
|
+
인터랙티브로 다음을 설정합니다:
|
|
87
|
+
- GitHub Owner (org 또는 user)
|
|
88
|
+
- Project Number
|
|
89
|
+
- Repository (owner/repo 형식)
|
|
98
90
|
|
|
99
|
-
설정
|
|
91
|
+
설정 후 생성되는 파일:
|
|
100
92
|
|
|
101
93
|
```
|
|
102
|
-
|
|
103
|
-
├── .
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
│
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
│ └── project-task-manager.md # 태스크 관리 Agent
|
|
94
|
+
.claude/
|
|
95
|
+
├── project.env # GitHub Project 환경변수
|
|
96
|
+
├── settings.json # StartSession hook 설정
|
|
97
|
+
├── hooks/
|
|
98
|
+
│ └── task-loader.sh # 태스크 조회 스크립트
|
|
99
|
+
└── agents/
|
|
100
|
+
└── project-task-manager.md # 태스크 관리 Agent
|
|
110
101
|
```
|
|
111
102
|
|
|
112
|
-
|
|
103
|
+
> `read:project` 스코프 필요: `gh auth refresh -s read:project,project`
|
|
104
|
+
|
|
105
|
+
### `init-context`: Context 자동 생성 설정
|
|
113
106
|
|
|
114
|
-
|
|
107
|
+
GitHub Actions를 통한 Context 문서 자동 생성을 설정합니다.
|
|
115
108
|
|
|
116
109
|
```bash
|
|
117
|
-
|
|
118
|
-
GITHUB_PROJECT_OWNER=your-org
|
|
119
|
-
GITHUB_PROJECT_NUMBER=1
|
|
120
|
-
GITHUB_PROJECT_REPO=your-org/your-repo
|
|
110
|
+
jun-claude-code init-context
|
|
121
111
|
```
|
|
122
112
|
|
|
123
|
-
|
|
113
|
+
설정 후 생성되는 파일:
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
```
|
|
116
|
+
.github/workflows/
|
|
117
|
+
└── context-gen.yml # Context 생성 GitHub Actions 워크플로우
|
|
118
|
+
|
|
119
|
+
.claude/context/
|
|
120
|
+
├── codebase/
|
|
121
|
+
│ └── INDEX.md # 코드베이스 모듈 참조 목록
|
|
122
|
+
└── business/
|
|
123
|
+
└── INDEX.md # 비즈니스 도메인 참조 목록
|
|
124
|
+
```
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
> `CLAUDE_CODE_OAUTH_TOKEN`를 GitHub repository secrets에 추가해야 합니다.
|
|
127
|
+
|
|
128
|
+
## 프로젝트 구조
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
templates/
|
|
132
|
+
├── global/ # ~/.claude/에 설치되는 전역 설정
|
|
133
|
+
│ ├── CLAUDE.md # 작업 가이드 (워크플로우, Context 절약 원칙)
|
|
134
|
+
│ ├── agents/ # Subagent 정의 (15종)
|
|
135
|
+
│ ├── skills/ # 스킬 가이드 (코딩, Git, BE, FE 등)
|
|
136
|
+
│ ├── hooks/ # 자동 실행 스크립트 (워크플로우 강제, 스킬 평가)
|
|
137
|
+
│ └── settings.json # Claude Code 전역 설정
|
|
138
|
+
└── project/ # 프로젝트 .claude/에 설치되는 프로젝트별 설정
|
|
139
|
+
├── agents/ # project-task-manager Agent
|
|
140
|
+
├── hooks/ # task-loader Hook
|
|
141
|
+
├── workflows/ # context-gen Workflow
|
|
142
|
+
└── project.env.example
|
|
129
143
|
```
|
|
130
144
|
|
|
131
|
-
##
|
|
145
|
+
## 커스터마이징
|
|
146
|
+
|
|
147
|
+
설치 후 `~/.claude/`에서 필요에 맞게 수정할 수 있습니다. 프로젝트별로는 프로젝트 루트에 `.claude/`를 만들어 설정을 추가합니다.
|
|
132
148
|
|
|
133
|
-
|
|
149
|
+
```
|
|
150
|
+
your-project/
|
|
151
|
+
├── .claude/
|
|
152
|
+
│ ├── context/ # 프로젝트 아키텍처, 도메인 지식
|
|
153
|
+
│ └── skills/ # 프로젝트 전용 스킬
|
|
154
|
+
└── CLAUDE.md # 프로젝트 설명
|
|
155
|
+
```
|
|
134
156
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
3. **Git 작업 위임**: 모든 Git 작업은 `git-manager` Agent 사용
|
|
157
|
+
- **context/**: 프로젝트의 사실/배경 정보 (아키텍처, 도메인 모델, API 스펙 등)
|
|
158
|
+
- **skills/**: 프로젝트 고유의 작업 절차 (배포 방법, 테스트 규칙 등)
|
|
138
159
|
|
|
139
160
|
## License
|
|
140
161
|
|
package/dist/cli.js
CHANGED
|
@@ -36,6 +36,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
const commander_1 = require("commander");
|
|
38
38
|
const copy_1 = require("./copy");
|
|
39
|
+
const init_context_1 = require("./init-context");
|
|
39
40
|
const program = new commander_1.Command();
|
|
40
41
|
program
|
|
41
42
|
.name('jun-claude-code')
|
|
@@ -78,4 +79,21 @@ program
|
|
|
78
79
|
process.exit(1);
|
|
79
80
|
}
|
|
80
81
|
});
|
|
82
|
+
program
|
|
83
|
+
.command('init-context')
|
|
84
|
+
.description('Setup context auto-generation with GitHub Actions')
|
|
85
|
+
.action(async () => {
|
|
86
|
+
try {
|
|
87
|
+
await (0, init_context_1.initContext)();
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error instanceof Error) {
|
|
91
|
+
console.error('Error:', error.message);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error('An unexpected error occurred');
|
|
95
|
+
}
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
81
99
|
program.parse();
|
package/dist/copy.js
CHANGED
|
@@ -93,12 +93,12 @@ function copyFile(src, dest) {
|
|
|
93
93
|
fs.copyFileSync(src, dest);
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
|
-
* Get the source
|
|
96
|
+
* Get the source templates/global directory path (from package installation)
|
|
97
97
|
*/
|
|
98
|
-
function
|
|
98
|
+
function getSourceGlobalDir() {
|
|
99
99
|
// When installed as npm package, __dirname is in dist/
|
|
100
|
-
//
|
|
101
|
-
return path.resolve(__dirname, '..', '
|
|
100
|
+
// templates/global folder is at package root
|
|
101
|
+
return path.resolve(__dirname, '..', 'templates', 'global');
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
104
|
* Get the destination .claude directory path (user's home)
|
|
@@ -110,26 +110,100 @@ function getDestClaudeDir() {
|
|
|
110
110
|
}
|
|
111
111
|
return path.join(homeDir, '.claude');
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Merge settings.json from source into destination.
|
|
115
|
+
* Hooks are merged per event key; duplicate hook entries (by deep equality) are skipped.
|
|
116
|
+
* Non-hook keys are shallow-merged (source wins for new keys, dest preserved for existing).
|
|
117
|
+
*/
|
|
118
|
+
function mergeSettingsJson(sourceDir, destDir) {
|
|
119
|
+
const sourcePath = path.join(sourceDir, 'settings.json');
|
|
120
|
+
const destPath = path.join(destDir, 'settings.json');
|
|
121
|
+
if (!fs.existsSync(sourcePath)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
let sourceSettings;
|
|
125
|
+
try {
|
|
126
|
+
sourceSettings = JSON.parse(fs.readFileSync(sourcePath, 'utf-8'));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
console.log(chalk_1.default.yellow(' Warning: Could not parse source settings.json, skipping merge.'));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let destSettings = {};
|
|
133
|
+
if (fs.existsSync(destPath)) {
|
|
134
|
+
try {
|
|
135
|
+
destSettings = JSON.parse(fs.readFileSync(destPath, 'utf-8'));
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
console.log(chalk_1.default.yellow(' Warning: Could not parse destination settings.json, creating fresh.'));
|
|
139
|
+
destSettings = {};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Merge top-level keys (source fills in missing keys, dest's existing keys preserved)
|
|
143
|
+
for (const key of Object.keys(sourceSettings)) {
|
|
144
|
+
if (key === 'hooks') {
|
|
145
|
+
continue; // hooks are merged separately below
|
|
146
|
+
}
|
|
147
|
+
if (!(key in destSettings)) {
|
|
148
|
+
destSettings[key] = sourceSettings[key];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Merge hooks
|
|
152
|
+
const sourceHooks = sourceSettings.hooks || {};
|
|
153
|
+
if (!destSettings.hooks) {
|
|
154
|
+
destSettings.hooks = {};
|
|
155
|
+
}
|
|
156
|
+
const destHooks = destSettings.hooks;
|
|
157
|
+
for (const event of Object.keys(sourceHooks)) {
|
|
158
|
+
const sourceEntries = sourceHooks[event] || [];
|
|
159
|
+
if (!destHooks[event]) {
|
|
160
|
+
destHooks[event] = [];
|
|
161
|
+
}
|
|
162
|
+
const destEntries = destHooks[event];
|
|
163
|
+
// Extract a command-based key from a hook entry for duplicate detection.
|
|
164
|
+
// Type 1: { type: "command", command: "..." } → returns "type:command"
|
|
165
|
+
// Type 2: { hooks: [{ type: "command", command: "..." }, ...] } → returns sorted "type:command" joined
|
|
166
|
+
const getHookKey = (entry) => {
|
|
167
|
+
if (entry.hooks && Array.isArray(entry.hooks)) {
|
|
168
|
+
return entry.hooks
|
|
169
|
+
.map((h) => `${h.type || ''}:${h.command || ''}`)
|
|
170
|
+
.sort()
|
|
171
|
+
.join('\n');
|
|
172
|
+
}
|
|
173
|
+
return `${entry.type || ''}:${entry.command || ''}`;
|
|
174
|
+
};
|
|
175
|
+
// Build a Set of command keys from existing entries for fast duplicate detection
|
|
176
|
+
const existingKeys = new Set(destEntries.map((entry) => getHookKey(entry)));
|
|
177
|
+
for (const entry of sourceEntries) {
|
|
178
|
+
const key = getHookKey(entry);
|
|
179
|
+
if (!existingKeys.has(key)) {
|
|
180
|
+
destEntries.push(entry);
|
|
181
|
+
existingKeys.add(key);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
ensureDir(destDir);
|
|
186
|
+
fs.writeFileSync(destPath, JSON.stringify(destSettings, null, 2) + '\n', 'utf-8');
|
|
187
|
+
console.log(` ${chalk_1.default.blue('[merged]')} settings.json`);
|
|
188
|
+
}
|
|
113
189
|
/**
|
|
114
190
|
* Copy .claude files to user's home directory
|
|
115
191
|
*/
|
|
116
192
|
async function copyClaudeFiles(options = {}) {
|
|
117
193
|
const { dryRun = false, force = false } = options;
|
|
118
|
-
const sourceDir =
|
|
194
|
+
const sourceDir = getSourceGlobalDir();
|
|
119
195
|
const destDir = getDestClaudeDir();
|
|
120
196
|
console.log(chalk_1.default.blue('Source:'), sourceDir);
|
|
121
197
|
console.log(chalk_1.default.blue('Destination:'), destDir);
|
|
122
198
|
console.log();
|
|
123
199
|
// Check if source exists
|
|
124
200
|
if (!fs.existsSync(sourceDir)) {
|
|
125
|
-
console.error(chalk_1.default.red('Error:'), 'Source
|
|
201
|
+
console.error(chalk_1.default.red('Error:'), 'Source templates/global directory not found');
|
|
126
202
|
process.exit(1);
|
|
127
203
|
}
|
|
128
|
-
// Files to exclude from global copy (
|
|
204
|
+
// Files to exclude from global copy (merge-handled separately)
|
|
129
205
|
const EXCLUDE_FROM_GLOBAL = [
|
|
130
|
-
'
|
|
131
|
-
'agents/project-task-manager.md',
|
|
132
|
-
'project.env.example',
|
|
206
|
+
'settings.json',
|
|
133
207
|
];
|
|
134
208
|
// Get all files to copy
|
|
135
209
|
const allFiles = getAllFiles(sourceDir);
|
|
@@ -137,7 +211,7 @@ async function copyClaudeFiles(options = {}) {
|
|
|
137
211
|
return !EXCLUDE_FROM_GLOBAL.includes(file);
|
|
138
212
|
});
|
|
139
213
|
if (files.length === 0) {
|
|
140
|
-
console.log(chalk_1.default.yellow('No files found in
|
|
214
|
+
console.log(chalk_1.default.yellow('No files found in templates/global directory'));
|
|
141
215
|
return;
|
|
142
216
|
}
|
|
143
217
|
console.log(chalk_1.default.cyan(`Found ${files.length} files to copy:`));
|
|
@@ -152,6 +226,11 @@ async function copyClaudeFiles(options = {}) {
|
|
|
152
226
|
const status = exists ? chalk_1.default.yellow('[overwrite]') : chalk_1.default.green('[new]');
|
|
153
227
|
console.log(` ${status} ${file}`);
|
|
154
228
|
}
|
|
229
|
+
// settings.json merge indicator
|
|
230
|
+
const sourceSettingsExists = fs.existsSync(path.join(sourceDir, 'settings.json'));
|
|
231
|
+
if (sourceSettingsExists) {
|
|
232
|
+
console.log(` ${chalk_1.default.blue('[merge]')} settings.json`);
|
|
233
|
+
}
|
|
155
234
|
console.log();
|
|
156
235
|
console.log(chalk_1.default.yellow('No files were copied (dry run mode)'));
|
|
157
236
|
return;
|
|
@@ -177,6 +256,8 @@ async function copyClaudeFiles(options = {}) {
|
|
|
177
256
|
console.log(` ${status} ${file}`);
|
|
178
257
|
copiedCount++;
|
|
179
258
|
}
|
|
259
|
+
// Merge settings.json (hooks are merged, not overwritten)
|
|
260
|
+
mergeSettingsJson(sourceDir, destDir);
|
|
180
261
|
console.log();
|
|
181
262
|
console.log(chalk_1.default.green(`Done! Copied ${copiedCount} files, skipped ${skippedCount} files.`));
|
|
182
263
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.initProject = exports.copyClaudeFiles = void 0;
|
|
3
|
+
exports.initContext = exports.initProject = exports.copyClaudeFiles = void 0;
|
|
4
4
|
var copy_1 = require("./copy");
|
|
5
5
|
Object.defineProperty(exports, "copyClaudeFiles", { enumerable: true, get: function () { return copy_1.copyClaudeFiles; } });
|
|
6
6
|
var init_project_1 = require("./init-project");
|
|
7
7
|
Object.defineProperty(exports, "initProject", { enumerable: true, get: function () { return init_project_1.initProject; } });
|
|
8
|
+
var init_context_1 = require("./init-context");
|
|
9
|
+
Object.defineProperty(exports, "initContext", { enumerable: true, get: function () { return init_context_1.initContext; } });
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.initContext = initContext;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
/**
|
|
44
|
+
* Get the templates/project directory path (from package installation)
|
|
45
|
+
*/
|
|
46
|
+
function getTemplatesDir() {
|
|
47
|
+
return path.resolve(__dirname, '..', 'templates', 'project');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Initialize context auto-generation with GitHub Actions
|
|
51
|
+
*/
|
|
52
|
+
async function initContext() {
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
console.log(chalk_1.default.bold('\n📄 Initializing Context Auto-Generation...\n'));
|
|
55
|
+
// 1. templates/project/workflows/context-gen.yml → .github/workflows/context-gen.yml 복사
|
|
56
|
+
const templateSrc = path.join(getTemplatesDir(), 'workflows', 'context-gen.yml');
|
|
57
|
+
const workflowDest = path.join(cwd, '.github', 'workflows', 'context-gen.yml');
|
|
58
|
+
fs.mkdirSync(path.dirname(workflowDest), { recursive: true });
|
|
59
|
+
if (fs.existsSync(workflowDest)) {
|
|
60
|
+
console.log(chalk_1.default.yellow(' ⚠ .github/workflows/context-gen.yml already exists, skipping'));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
fs.copyFileSync(templateSrc, workflowDest);
|
|
64
|
+
console.log(chalk_1.default.green(' ✓ Created .github/workflows/context-gen.yml'));
|
|
65
|
+
}
|
|
66
|
+
// 2. .claude/context/codebase/ 디렉토리 + stub INDEX.md
|
|
67
|
+
const codebaseDirPath = path.join(cwd, '.claude', 'context', 'codebase');
|
|
68
|
+
const codebaseIndex = path.join(codebaseDirPath, 'INDEX.md');
|
|
69
|
+
fs.mkdirSync(codebaseDirPath, { recursive: true });
|
|
70
|
+
if (fs.existsSync(codebaseIndex)) {
|
|
71
|
+
console.log(chalk_1.default.yellow(' ⚠ .claude/context/codebase/INDEX.md already exists, skipping'));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
fs.writeFileSync(codebaseIndex, `---
|
|
75
|
+
name: Codebase Index
|
|
76
|
+
description: 코드베이스 모듈 참조 목록
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
# Codebase Context Index
|
|
80
|
+
|
|
81
|
+
## 모듈 목록
|
|
82
|
+
|
|
83
|
+
| 모듈 | 설명 | 문서 |
|
|
84
|
+
|------|------|------|
|
|
85
|
+
`);
|
|
86
|
+
console.log(chalk_1.default.green(' ✓ Created .claude/context/codebase/INDEX.md'));
|
|
87
|
+
}
|
|
88
|
+
// 3. .claude/context/business/ 디렉토리 + stub INDEX.md
|
|
89
|
+
const businessDirPath = path.join(cwd, '.claude', 'context', 'business');
|
|
90
|
+
const businessIndex = path.join(businessDirPath, 'INDEX.md');
|
|
91
|
+
fs.mkdirSync(businessDirPath, { recursive: true });
|
|
92
|
+
if (fs.existsSync(businessIndex)) {
|
|
93
|
+
console.log(chalk_1.default.yellow(' ⚠ .claude/context/business/INDEX.md already exists, skipping'));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
fs.writeFileSync(businessIndex, `---
|
|
97
|
+
name: Business Index
|
|
98
|
+
description: 비즈니스 도메인 참조 목록
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# Business Context Index
|
|
102
|
+
|
|
103
|
+
## 프로젝트 개요
|
|
104
|
+
|
|
105
|
+
<!-- 프로젝트가 해결하는 문제와 대상 사용자를 작성하세요 -->
|
|
106
|
+
|
|
107
|
+
## 도메인 목록
|
|
108
|
+
|
|
109
|
+
| 도메인 | 설명 | 문서 |
|
|
110
|
+
|--------|------|------|
|
|
111
|
+
`);
|
|
112
|
+
console.log(chalk_1.default.green(' ✓ Created .claude/context/business/INDEX.md'));
|
|
113
|
+
}
|
|
114
|
+
// 4. 안내 메시지
|
|
115
|
+
console.log(chalk_1.default.bold('\n✅ Context auto-generation setup complete!\n'));
|
|
116
|
+
console.log(chalk_1.default.cyan('Next steps:'));
|
|
117
|
+
console.log(chalk_1.default.cyan(' 1. Add CLAUDE_CODE_OAUTH_TOKEN to your repository secrets'));
|
|
118
|
+
console.log(chalk_1.default.cyan(' → Settings > Secrets and variables > Actions > New repository secret'));
|
|
119
|
+
console.log(chalk_1.default.cyan(' 2. Create a PR to trigger context auto-generation'));
|
|
120
|
+
console.log('');
|
|
121
|
+
}
|
package/dist/init-project.js
CHANGED
|
@@ -57,10 +57,10 @@ function askQuestion(question) {
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* Get the source
|
|
60
|
+
* Get the source templates/project directory path (from package installation)
|
|
61
61
|
*/
|
|
62
|
-
function
|
|
63
|
-
return path.resolve(__dirname, '..', '
|
|
62
|
+
function getSourceProjectDir() {
|
|
63
|
+
return path.resolve(__dirname, '..', 'templates', 'project');
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Get the project .claude directory path (current working directory)
|
|
@@ -101,7 +101,7 @@ function createProjectEnv(destDir, config) {
|
|
|
101
101
|
* Copy a project-specific file from package source to project directory
|
|
102
102
|
*/
|
|
103
103
|
function copyProjectFile(srcRelative, destDir) {
|
|
104
|
-
const srcPath = path.join(
|
|
104
|
+
const srcPath = path.join(getSourceProjectDir(), srcRelative);
|
|
105
105
|
const destPath = path.join(destDir, srcRelative);
|
|
106
106
|
if (!fs.existsSync(srcPath)) {
|
|
107
107
|
console.log(chalk_1.default.yellow(` ⚠ 소스 파일 없음: ${srcRelative}`));
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jun-claude-code",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Claude Code configuration template - copy .claude settings to your project",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "dist/cli.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"
|
|
9
|
+
"templates"
|
|
10
10
|
],
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-generator
|
|
3
|
+
description: GitHub Action에서 PR diff 기반으로 .claude/context/ 문서를 자동 생성/업데이트 (CI 전용)
|
|
4
|
+
keywords: [context, PR, diff, codebase, business, 문서생성]
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: green
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Context Generator Agent
|
|
10
|
+
|
|
11
|
+
PR의 변경 내용을 분석하여 `.claude/context/` 하위에 codebase/business 문서를 자동 생성하고 업데이트합니다.
|
|
12
|
+
|
|
13
|
+
## 실행 조건
|
|
14
|
+
|
|
15
|
+
- GitHub Action에서 PR 이벤트로 트리거
|
|
16
|
+
- `anthropics/claude-code-action@v1`을 통해 실행
|
|
17
|
+
|
|
18
|
+
## 프로세스
|
|
19
|
+
|
|
20
|
+
### 1. Diff 수집
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git diff HEAD~1 --name-only
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
변경된 파일 목록을 수집합니다.
|
|
27
|
+
|
|
28
|
+
### 2. 모듈 매핑
|
|
29
|
+
|
|
30
|
+
변경된 파일을 모듈 단위로 그룹화합니다.
|
|
31
|
+
- `src/cli.ts` → `cli` 모듈
|
|
32
|
+
- `src/copy.ts` → `copy-logic` 모듈
|
|
33
|
+
- `.claude/agents/*.md` → `agents` 모듈
|
|
34
|
+
|
|
35
|
+
### 3. 기존 Context 확인
|
|
36
|
+
|
|
37
|
+
`.claude/context/codebase/`와 `.claude/context/business/`에서 기존 문서를 확인합니다.
|
|
38
|
+
- 기존 문서가 있으면 → 업데이트
|
|
39
|
+
- 기존 문서가 없으면 → 새로 생성
|
|
40
|
+
|
|
41
|
+
### 4. Codebase Context 생성
|
|
42
|
+
|
|
43
|
+
[ContextGeneration Skill](../../skills/ContextGeneration/SKILL.md)의 Codebase 규칙에 따라:
|
|
44
|
+
- 모듈별 `.md` 파일 생성/업데이트
|
|
45
|
+
- 파일 경로와 함수명만 참조 (원본 코드 포함 금지)
|
|
46
|
+
- `codebase/INDEX.md` 업데이트
|
|
47
|
+
|
|
48
|
+
### 5. Business Context 생성
|
|
49
|
+
|
|
50
|
+
[ContextGeneration Skill](../../skills/ContextGeneration/SKILL.md)의 Business 규칙에 따라:
|
|
51
|
+
- 기술 용어를 비즈니스 관점으로 변환
|
|
52
|
+
- 도메인별 `.md` 파일 생성/업데이트
|
|
53
|
+
- `business/INDEX.md` 업데이트
|
|
54
|
+
|
|
55
|
+
### 6. 커밋
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git add .claude/context/
|
|
59
|
+
git commit -m "docs: update context for PR changes"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 제약사항
|
|
63
|
+
|
|
64
|
+
- `.claude/context/**` 경로 변경은 무시 (무한루프 방지)
|
|
65
|
+
- 변경된 파일과 관련된 context만 업데이트 (전체 재생성 금지)
|
|
66
|
+
- 원본 소스 코드를 context 문서에 포함하지 않음
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-manager
|
|
3
|
-
description: .claude 문서의
|
|
3
|
+
description: 기존 .claude/context/ 문서의 구조 최적화 시 호출. 큰 파일을 INDEX.md + 상세파일로 분리, 중복 제거, 테이블 압축으로 토큰 절약 (수동 호출, 스펙 정합성 검증은 director 담당)
|
|
4
4
|
keywords: [Context관리, 문서정리, 파일분리, 토큰최적화, 구조개선, 문서품질]
|
|
5
5
|
model: sonnet
|
|
6
6
|
color: green
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: simple-code-writer
|
|
3
|
-
description:
|
|
3
|
+
description: lint/build 오류, 오타, 설정값 등 간단한 코드 수정 시 호출. 단순 수정, 설정 변경, 오타 수정 수행.
|
|
4
4
|
keywords: [간단수정, 단순수정, 설정변경, 오타수정, 1-2파일, 소규모수정]
|
|
5
5
|
model: haiku
|
|
6
6
|
color: cyan
|
|
@@ -25,18 +25,8 @@ Main Agent의 Context Window는 제한적입니다.
|
|
|
25
25
|
|
|
26
26
|
### 🚨 필수 위임 작업 (Main Agent 직접 수행 금지)
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
| 코드베이스 탐색/검색 | explore | 파일 내용이 Main Context에 쌓이지 않음 |
|
|
31
|
-
| 여러 파일 읽기 | explore / context-collector | 탐색 결과만 요약해서 받음 |
|
|
32
|
-
| 패턴/구조 파악 | context-collector | 분석 결과만 받음 |
|
|
33
|
-
| 복잡한 계획 수립 | task-planner | 계획 결과만 받음 |
|
|
34
|
-
| 영향 분석 | impact-analyzer | 분석 결과만 받음 |
|
|
35
|
-
| 코드 리뷰 | code-reviewer | 리뷰 결과만 받음 |
|
|
36
|
-
| 테스트/빌드 검증 | qa-tester | 검증 결과만 받음 |
|
|
37
|
-
| 단순 수정 (lint/build 오류, 오타, 설정값) | simple-code-writer | Main이 직접 수정하지 않음 |
|
|
38
|
-
| 여러 파일 코드 작성 | code-writer / designer | 구현 결과만 받음 |
|
|
39
|
-
| Git 작업 | git-manager | 커밋/PR 결과만 받음 |
|
|
28
|
+
아래 PART 2의 "사용 가능한 Agents" 목록에서 각 Agent의 description을 확인하고,
|
|
29
|
+
작업에 적합한 Agent에 위임하세요. 각 Agent의 description에 위임 이유가 포함되어 있습니다.
|
|
40
30
|
|
|
41
31
|
### ❌ 절대 금지 (Main Agent에서 직접 수행 금지)
|
|
42
32
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ContextGeneration
|
|
3
|
+
description: PR 변경 내용을 분석하여 .claude/context/ 문서를 자동 생성하는 규칙
|
|
4
|
+
keywords: [context, codebase, business, PR, 자동생성, 문서화]
|
|
5
|
+
estimated_tokens: ~800
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Context 자동 생성 규칙
|
|
9
|
+
|
|
10
|
+
PR 변경 내용을 분석하여 `.claude/context/` 하위에 codebase/business 문서를 자동 생성합니다.
|
|
11
|
+
|
|
12
|
+
## Context 디렉토리 구조
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
.claude/context/
|
|
16
|
+
├── codebase/
|
|
17
|
+
│ ├── INDEX.md # 모듈 목록 + 경로
|
|
18
|
+
│ └── <module-name>.md # 모듈별 구현 참조
|
|
19
|
+
└── business/
|
|
20
|
+
├── INDEX.md # 프로젝트 개요 + 도메인 목록
|
|
21
|
+
└── <domain-area>.md # 비즈니스 레벨 요약
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Codebase Context 규칙
|
|
25
|
+
|
|
26
|
+
### 파일명
|
|
27
|
+
- **kebab-case** 사용 (예: `cli.md`, `copy-logic.md`, `auth-middleware.md`)
|
|
28
|
+
- 모듈/기능 단위로 분리
|
|
29
|
+
|
|
30
|
+
### 필수 섹션
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
---
|
|
34
|
+
name: <모듈명>
|
|
35
|
+
description: <한 줄 설명>
|
|
36
|
+
keywords: [관련, 키워드]
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# <모듈명>
|
|
40
|
+
|
|
41
|
+
<2-3문장 개요>
|
|
42
|
+
|
|
43
|
+
## 파일 구조
|
|
44
|
+
|
|
45
|
+
| 파일 | 역할 | 핵심 함수/클래스 |
|
|
46
|
+
|------|------|-----------------|
|
|
47
|
+
| src/example.ts | 메인 로직 | mainFunction(), HelperClass |
|
|
48
|
+
|
|
49
|
+
## 핵심 흐름
|
|
50
|
+
|
|
51
|
+
1. <진입점> → <처리> → <결과>
|
|
52
|
+
2. ...
|
|
53
|
+
|
|
54
|
+
## 관련 Business Context
|
|
55
|
+
|
|
56
|
+
- [<도메인명>](../business/<domain>.md)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 금지사항
|
|
60
|
+
|
|
61
|
+
- **원본 코드 포함 절대 금지** (코드 블록으로 소스 코드를 복사하지 않음)
|
|
62
|
+
- 파일 경로와 함수/클래스명만 참조
|
|
63
|
+
- 파일 참조 형식: `| src/copy.ts | 파일 복사 메인 로직 | mergeSettingsJson() |`
|
|
64
|
+
|
|
65
|
+
## Business Context 규칙
|
|
66
|
+
|
|
67
|
+
### 파일명
|
|
68
|
+
- **비즈니스 도메인 기준** (예: `configuration-management.md`, `user-authentication.md`)
|
|
69
|
+
- 기술 용어 금지 (예: `settings-json-merge.md` ❌ → `configuration-management.md` ✅)
|
|
70
|
+
|
|
71
|
+
### 필수 섹션
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
---
|
|
75
|
+
name: <도메인명>
|
|
76
|
+
description: <비즈니스 관점 한 줄 설명>
|
|
77
|
+
keywords: [비즈니스, 키워드]
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
# <도메인명>
|
|
81
|
+
|
|
82
|
+
## 목적
|
|
83
|
+
|
|
84
|
+
<이 기능이 사용자에게 제공하는 가치>
|
|
85
|
+
|
|
86
|
+
## 핵심 기능
|
|
87
|
+
|
|
88
|
+
| 기능 | 설명 | 사용자 관점 |
|
|
89
|
+
|------|------|------------|
|
|
90
|
+
| 설정 복사 | 템플릿 설정을 사용자 환경에 적용 | 초기 설정 자동화 |
|
|
91
|
+
|
|
92
|
+
## 사용자 흐름
|
|
93
|
+
|
|
94
|
+
1. 사용자가 <동작> → <결과>
|
|
95
|
+
2. ...
|
|
96
|
+
|
|
97
|
+
## 관련 Codebase Context
|
|
98
|
+
|
|
99
|
+
- [<모듈명>](../codebase/<module>.md)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 변환 규칙
|
|
103
|
+
- Codebase의 기술 용어를 비즈니스 관점으로 변환
|
|
104
|
+
- `mergeSettingsJson()` → "기존 설정을 보존하면서 새 설정 적용"
|
|
105
|
+
- `copyClaudeFiles()` → "템플릿 설정을 사용자 환경에 배포"
|
|
106
|
+
|
|
107
|
+
## INDEX.md 작성 규칙
|
|
108
|
+
|
|
109
|
+
### codebase/INDEX.md
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
---
|
|
113
|
+
name: Codebase Index
|
|
114
|
+
description: 코드베이스 모듈 참조 목록
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
# Codebase Context Index
|
|
118
|
+
|
|
119
|
+
## 모듈 목록
|
|
120
|
+
|
|
121
|
+
| 모듈 | 설명 | 문서 |
|
|
122
|
+
|------|------|------|
|
|
123
|
+
| CLI | 커맨드라인 인터페이스 | [cli.md](./cli.md) |
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### business/INDEX.md
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
---
|
|
130
|
+
name: Business Index
|
|
131
|
+
description: 비즈니스 도메인 참조 목록
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
# Business Context Index
|
|
135
|
+
|
|
136
|
+
## 프로젝트 개요
|
|
137
|
+
|
|
138
|
+
<프로젝트가 해결하는 문제와 대상 사용자 1-2문장>
|
|
139
|
+
|
|
140
|
+
## 도메인 목록
|
|
141
|
+
|
|
142
|
+
| 도메인 | 설명 | 문서 |
|
|
143
|
+
|--------|------|------|
|
|
144
|
+
| 설정 관리 | 사용자 설정 배포 및 관리 | [configuration-management.md](./configuration-management.md) |
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 증분 업데이트 원칙
|
|
148
|
+
|
|
149
|
+
- PR에서 변경된 파일만 해당하는 context 문서를 업데이트
|
|
150
|
+
- 전체 재생성 금지 -- 기존 문서의 변경되지 않은 부분은 유지
|
|
151
|
+
- 새 모듈이 추가되면 INDEX.md에 행 추가
|
|
152
|
+
- 모듈이 삭제되면 INDEX.md에서 해당 행 제거 및 문서 파일 삭제
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Context Auto-Generation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize]
|
|
6
|
+
paths-ignore:
|
|
7
|
+
- '.claude/context/**'
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
generate-context:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout PR branch
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
ref: ${{ github.head_ref }}
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
|
|
24
|
+
- name: Generate context documents
|
|
25
|
+
uses: anthropics/claude-code-action@v1
|
|
26
|
+
with:
|
|
27
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
28
|
+
prompt: |
|
|
29
|
+
당신은 context-generator 에이전트입니다.
|
|
30
|
+
.claude/agents/context-generator.md의 에이전트 정의와
|
|
31
|
+
.claude/skills/ContextGeneration/SKILL.md의 스킬 가이드를 읽고 정확히 따르세요.
|
|
32
|
+
|
|
33
|
+
PR diff를 분석하고 .claude/context/ 아래에 컨텍스트 문서를 생성/업데이트하세요.
|
|
34
|
+
|
|
35
|
+
단계:
|
|
36
|
+
1. `git diff HEAD~1 --name-only`을 실행하여 변경된 파일 목록 가져오기
|
|
37
|
+
2. 변경된 각 모듈에 대해 .claude/context/codebase/<module>.md 생성 또는 업데이트
|
|
38
|
+
3. 영향을 받는 각 비즈니스 도메인에 대해 .claude/context/business/<domain>.md 생성 또는 업데이트
|
|
39
|
+
4. 두 디렉토리의 INDEX.md 파일 업데이트
|
|
40
|
+
5. "docs: update context for PR changes" 메시지로 변경사항 커밋
|
|
41
|
+
|
|
42
|
+
중요사항:
|
|
43
|
+
- 컨텍스트 문서에 소스 코드를 포함하지 말고, 파일 경로와 함수 이름만 포함하세요
|
|
44
|
+
- 실제로 변경된 파일에 대해서만 컨텍스트 업데이트
|
|
45
|
+
- ContextGeneration 스킬에 명시된 정확한 형식 따르기
|
|
46
|
+
|
|
47
|
+
- name: Commit and push context changes
|
|
48
|
+
run: |
|
|
49
|
+
git config user.name "github-actions[bot]"
|
|
50
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
51
|
+
git add .claude/context/
|
|
52
|
+
git diff --staged --quiet || (git commit -m "docs: context 문서 자동 업데이트" && git push)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|