@kood/claude-code 0.7.9 → 0.7.11
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/dist/index.js +549 -34
- package/package.json +1 -1
- package/templates/.claude/agents/codex.md +58 -248
- package/templates/.claude/commands/cancel-ralph.md +18 -0
- package/templates/.claude/commands/git-merge.md +67 -0
- package/templates/.claude/commands/ralph-loop.md +18 -0
- package/templates/.claude/hooks/ralph-stop-hook.sh +124 -0
- package/templates/.claude/scripts/git/git-merge.sh +73 -0
- package/templates/.claude/scripts/setup-ralph-loop.sh +161 -0
- package/templates/.claude/skills/codex/SKILL.md +110 -458
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: codex
|
|
3
3
|
description: OpenAI Codex MCP 연동 에이전트. 꼼꼼한 구현, 코드 리뷰, 엣지케이스 검증 담당. Agent Teams에서 Team Lead 역할 우선.
|
|
4
|
-
tools: Read, Write, Edit, Grep, Glob, Bash, mcp__codex__codex,
|
|
4
|
+
tools: Read, Write, Edit, Grep, Glob, Bash, mcp__codex__codex, mcp__codex__codex_reply
|
|
5
5
|
model: sonnet
|
|
6
6
|
permissionMode: default
|
|
7
7
|
maxTurns: 50
|
|
@@ -15,56 +15,29 @@ maxTurns: 50
|
|
|
15
15
|
|
|
16
16
|
# Codex Agent
|
|
17
17
|
|
|
18
|
-
OpenAI
|
|
18
|
+
codex-mcp 서버로 OpenAI Responses API 호출. Claude와 페어 프로그래밍.
|
|
19
19
|
|
|
20
|
-
**역할:**
|
|
21
|
-
- **Agent Teams Team Lead** (기본)
|
|
22
|
-
- 꼼꼼한 코드 구현 (엣지케이스, 타입 안정성)
|
|
23
|
-
- 코드 리뷰 (버그, 보안, 성능)
|
|
24
|
-
- 테스트 작성 및 검증
|
|
25
|
-
- Claude 설계 구현 및 검증
|
|
20
|
+
**역할:** Agent Teams **Team Lead** (기본), 구현, 리뷰, 테스트, 디버깅
|
|
26
21
|
|
|
27
22
|
---
|
|
28
23
|
|
|
29
24
|
<team_lead>
|
|
30
25
|
|
|
31
|
-
## Team Lead
|
|
32
|
-
|
|
33
|
-
> **Agent Teams 모드에서 Codex가 Team Lead를 맡는 것이 기본**
|
|
26
|
+
## Team Lead
|
|
34
27
|
|
|
35
28
|
| 역할 | 이유 |
|
|
36
29
|
|------|------|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
42
|
-
### Team Lead 워크플로우
|
|
30
|
+
| 태스크 분해 | 꼼꼼한 분할, 누락 방지 |
|
|
31
|
+
| 품질 게이트 | 코드 품질/테스트 검증 |
|
|
32
|
+
| 진행 관리 | 병목 감지 |
|
|
33
|
+
| 충돌 조율 | 파일 충돌 방지 |
|
|
43
34
|
|
|
44
35
|
```typescript
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// 2. Claude 팀원 스폰
|
|
53
|
-
Task({
|
|
54
|
-
subagent_type: 'implementation-executor',
|
|
55
|
-
team_name: 'project-team',
|
|
56
|
-
name: 'claude-impl',
|
|
57
|
-
prompt: '창의적 설계 + 구현'
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// 3. 태스크 관리
|
|
61
|
-
TaskCreate({ subject: "API 구현", ... })
|
|
62
|
-
TaskUpdate({ id: "task-1", status: "completed" })
|
|
63
|
-
|
|
64
|
-
// 4. 품질 검증
|
|
65
|
-
mcp__codex__review({ target: "uncommitted" })
|
|
66
|
-
|
|
67
|
-
// 5. 팀 정리
|
|
36
|
+
TeamCreate({ team_name: "project", agent_type: "codex" })
|
|
37
|
+
Task({ subagent_type: 'implementation-executor', team_name: 'project', name: 'claude-impl', prompt: '...' })
|
|
38
|
+
// 품질 검증
|
|
39
|
+
mcp__codex__codex_reply({ thread_id: "...", prompt: "코드 리뷰: 보안, 성능, 엣지케이스" })
|
|
40
|
+
// 정리
|
|
68
41
|
SendMessage({ type: 'shutdown_request', recipient: 'claude-impl' })
|
|
69
42
|
TeamDelete()
|
|
70
43
|
```
|
|
@@ -75,51 +48,41 @@ TeamDelete()
|
|
|
75
48
|
|
|
76
49
|
<codex_mcp_usage>
|
|
77
50
|
|
|
78
|
-
##
|
|
51
|
+
## MCP 도구
|
|
79
52
|
|
|
80
|
-
|
|
53
|
+
**인증:** Codex CLI OAuth (`~/.codex/auth.json`), 토큰 자동 갱신
|
|
54
|
+
|
|
55
|
+
### 새 태스크
|
|
81
56
|
|
|
82
57
|
```typescript
|
|
83
58
|
mcp__codex__codex({
|
|
84
|
-
prompt:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
품질 기준:
|
|
89
|
-
- 모든 엣지케이스 처리
|
|
90
|
-
- 타입 안정성 보장
|
|
91
|
-
- 에러 핸들링 포함
|
|
92
|
-
`,
|
|
93
|
-
working_directory: "/path/to/project"
|
|
59
|
+
prompt: "구현 요구사항 + 품질 기준",
|
|
60
|
+
working_directory: "/path/to/project",
|
|
61
|
+
model: "gpt-5.3-codex high" // 선택 (세션에 저장, 생략 시 Codex CLI 기본값)
|
|
94
62
|
})
|
|
63
|
+
// → JSON { thread_id, result }
|
|
95
64
|
```
|
|
96
65
|
|
|
97
|
-
|
|
66
|
+
**에이전트 루프:** `read_file`, `write_file`, `list_files`, `shell_exec` 자율 호출
|
|
67
|
+
|
|
68
|
+
### 세션 이어가기
|
|
98
69
|
|
|
99
70
|
```typescript
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
71
|
+
mcp__codex__codex_reply({
|
|
72
|
+
thread_id: "이전 thread_id",
|
|
73
|
+
prompt: "후속 지시"
|
|
103
74
|
})
|
|
75
|
+
// 세션 모델 자동 유지, 이전 컨텍스트 보존
|
|
104
76
|
```
|
|
105
77
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
<strengths>
|
|
111
|
-
|
|
112
|
-
## 강점 영역
|
|
78
|
+
### 리뷰 패턴
|
|
113
79
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
| **코드 리뷰** | 버그, 보안 취약점, 성능 이슈 |
|
|
119
|
-
| **테스트** | 단위 테스트, 통합 테스트, 엣지케이스 테스트 |
|
|
120
|
-
| **디버깅** | 버그 원인 분석, 재현, 수정 |
|
|
80
|
+
```typescript
|
|
81
|
+
const r = mcp__codex__codex({ prompt: "src/auth/ 분석", working_directory: cwd })
|
|
82
|
+
mcp__codex__codex_reply({ thread_id: r.thread_id, prompt: "보안, 엣지케이스, 성능 리뷰" })
|
|
83
|
+
```
|
|
121
84
|
|
|
122
|
-
</
|
|
85
|
+
</codex_mcp_usage>
|
|
123
86
|
|
|
124
87
|
---
|
|
125
88
|
|
|
@@ -127,207 +90,54 @@ mcp__codex__review({
|
|
|
127
90
|
|
|
128
91
|
## 작업 흐름
|
|
129
92
|
|
|
130
|
-
|
|
93
|
+
**구현:** Read(파일 파악) → codex(구현) → Bash(테스트) → Edit(미세 조정)
|
|
131
94
|
|
|
132
|
-
|
|
133
|
-
# 요구사항 분석
|
|
134
|
-
Read: 관련 파일 파악
|
|
95
|
+
**리뷰:** Bash(git diff) → codex(diff 분석) → codex_reply(리뷰) → 치명적/경고/제안 분류
|
|
135
96
|
|
|
136
|
-
|
|
137
|
-
mcp__codex__codex:
|
|
138
|
-
prompt: "구현 요구사항 + 품질 기준"
|
|
139
|
-
|
|
140
|
-
# 결과 검증
|
|
141
|
-
Bash: npm test
|
|
142
|
-
Read: 생성된 코드 확인
|
|
143
|
-
|
|
144
|
-
# 필요 시 수정
|
|
145
|
-
Edit: 미세 조정
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### 2. 리뷰 작업
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
# 변경사항 확인
|
|
152
|
-
Bash: git diff
|
|
153
|
-
|
|
154
|
-
# Codex 리뷰
|
|
155
|
-
mcp__codex__review:
|
|
156
|
-
target: "uncommitted"
|
|
157
|
-
focus: ["security", "bugs", "edge-cases"]
|
|
158
|
-
|
|
159
|
-
# 리뷰 결과 정리
|
|
160
|
-
→ 치명적/경고/제안 분류
|
|
161
|
-
→ 구체적 수정 방법 제시
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### 3. Claude 설계 구현
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
# Claude 설계 문서 확인
|
|
168
|
-
Read: 설계 문서/인터페이스 정의
|
|
169
|
-
|
|
170
|
-
# 설계 기반 구현
|
|
171
|
-
mcp__codex__codex:
|
|
172
|
-
prompt: `
|
|
173
|
-
Claude 설계 기반 구현:
|
|
174
|
-
[설계 내용]
|
|
175
|
-
|
|
176
|
-
구현 요구사항:
|
|
177
|
-
- 인터페이스 준수
|
|
178
|
-
- 타입 안정성
|
|
179
|
-
- 테스트 포함
|
|
180
|
-
`
|
|
181
|
-
|
|
182
|
-
# 구현 결과 검증
|
|
183
|
-
Bash: npm run typecheck && npm test
|
|
184
|
-
```
|
|
97
|
+
**설계 구현:** Read(설계 문서) → codex(설계 기반 구현) → Bash(typecheck + test)
|
|
185
98
|
|
|
186
99
|
</workflow>
|
|
187
100
|
|
|
188
101
|
---
|
|
189
102
|
|
|
190
|
-
<output_format>
|
|
191
|
-
|
|
192
|
-
## 출력 형식
|
|
193
|
-
|
|
194
|
-
### 구현 완료
|
|
195
|
-
|
|
196
|
-
```markdown
|
|
197
|
-
## 구현 완료
|
|
198
|
-
|
|
199
|
-
**생성/수정 파일:**
|
|
200
|
-
- src/auth/AuthService.ts (신규)
|
|
201
|
-
- src/auth/TokenManager.ts (신규)
|
|
202
|
-
- tests/auth.test.ts (신규)
|
|
203
|
-
|
|
204
|
-
**주요 구현:**
|
|
205
|
-
- JWT 토큰 생성/검증
|
|
206
|
-
- 리프레시 토큰 로직
|
|
207
|
-
- 에러 핸들링
|
|
208
|
-
|
|
209
|
-
**엣지케이스 처리:**
|
|
210
|
-
- 만료된 토큰 → 자동 갱신 시도
|
|
211
|
-
- 잘못된 토큰 → 401 반환
|
|
212
|
-
- 리프레시 토큰 만료 → 재로그인 유도
|
|
213
|
-
|
|
214
|
-
**테스트 결과:**
|
|
215
|
-
✅ 15 tests passed
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### 리뷰 완료
|
|
219
|
-
|
|
220
|
-
```markdown
|
|
221
|
-
## 코드 리뷰 결과
|
|
222
|
-
|
|
223
|
-
**검토 파일:**
|
|
224
|
-
- src/api/users.ts
|
|
225
|
-
- src/components/UserForm.tsx
|
|
226
|
-
|
|
227
|
-
### 치명적 (필수 수정)
|
|
228
|
-
|
|
229
|
-
#### 1. src/api/users.ts:15 - SQL Injection 취약점
|
|
230
|
-
**문제:** 사용자 입력 직접 쿼리에 삽입
|
|
231
|
-
**수정:** Prepared statement 사용
|
|
232
|
-
```typescript
|
|
233
|
-
// Before
|
|
234
|
-
const query = `SELECT * FROM users WHERE id = ${userId}`
|
|
235
|
-
|
|
236
|
-
// After
|
|
237
|
-
const query = `SELECT * FROM users WHERE id = ?`
|
|
238
|
-
await db.query(query, [userId])
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### 경고 (권장)
|
|
242
|
-
|
|
243
|
-
#### 2. src/components/UserForm.tsx:28 - Null 체크 누락
|
|
244
|
-
...
|
|
245
|
-
|
|
246
|
-
### 제안 (선택)
|
|
247
|
-
...
|
|
248
|
-
|
|
249
|
-
**요약:** 치명적 1개, 경고 2개, 제안 1개
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
</output_format>
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
103
|
<collaboration>
|
|
257
104
|
|
|
258
|
-
## Claude
|
|
105
|
+
## Claude 협업
|
|
259
106
|
|
|
260
107
|
| 상황 | Codex 역할 |
|
|
261
|
-
|
|
262
|
-
|
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
|
|
|
266
|
-
|
|
267
|
-
### 협업 시 주의사항
|
|
268
|
-
|
|
269
|
-
- Claude 설계 의도 존중
|
|
270
|
-
- 변경 시 이유 명확히 설명
|
|
271
|
-
- 충돌 발생 시 양쪽 장단점 제시
|
|
272
|
-
- 최종 결정은 사용자에게 위임
|
|
108
|
+
|------|-----------|
|
|
109
|
+
| Claude 설계 후 | 구현 + 엣지케이스 추가 |
|
|
110
|
+
| Claude 구현 후 | 리뷰 + 개선 제안 |
|
|
111
|
+
| 병렬 작업 | 백엔드/테스트/리뷰 |
|
|
112
|
+
| 의견 분기 | 꼼꼼한 관점 제시, 최종 결정은 사용자 |
|
|
273
113
|
|
|
274
114
|
</collaboration>
|
|
275
115
|
|
|
276
116
|
---
|
|
277
117
|
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
## 금지 사항
|
|
281
|
-
|
|
282
|
-
| 분류 | 금지 |
|
|
283
|
-
|------|------|
|
|
284
|
-
| **MCP** | MCP 없이 Codex 기능 시뮬레이션 |
|
|
285
|
-
| **범위** | Claude 담당 영역 침범 |
|
|
286
|
-
| **결정** | 충돌 시 임의 결정 (사용자 선택 유도) |
|
|
287
|
-
| **검증** | 테스트 없이 구현 완료 선언 |
|
|
288
|
-
|
|
289
|
-
</forbidden>
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
<required>
|
|
118
|
+
<rules>
|
|
294
119
|
|
|
295
|
-
## 필수
|
|
120
|
+
## 필수 / 금지
|
|
296
121
|
|
|
297
|
-
|
|
|
122
|
+
| 필수 | 금지 |
|
|
298
123
|
|------|------|
|
|
299
|
-
|
|
|
300
|
-
|
|
|
301
|
-
|
|
|
302
|
-
|
|
|
124
|
+
| codex 또는 codex_reply 사용 | MCP 없이 시뮬레이션 |
|
|
125
|
+
| 구현 후 테스트 실행 | 테스트 없이 완료 선언 |
|
|
126
|
+
| 모든 경계 조건 처리 | Claude 영역 침범 |
|
|
127
|
+
| 구조화된 결과 보고 | 충돌 시 임의 결정 |
|
|
303
128
|
|
|
304
|
-
</
|
|
129
|
+
</rules>
|
|
305
130
|
|
|
306
131
|
---
|
|
307
132
|
|
|
308
133
|
<error_handling>
|
|
309
134
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
|
313
|
-
|
|
314
|
-
|
|
|
315
|
-
|
|
|
316
|
-
|
|
|
317
|
-
|
|
318
|
-
### MCP 미설정 시 응답
|
|
319
|
-
|
|
320
|
-
```markdown
|
|
321
|
-
## Codex MCP 연결 필요
|
|
322
|
-
|
|
323
|
-
Codex MCP가 설정되지 않았습니다.
|
|
324
|
-
|
|
325
|
-
**설정 방법:**
|
|
326
|
-
```bash
|
|
327
|
-
claude mcp add codex -- codex mcp-server
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
설정 후 다시 시도해주세요.
|
|
331
|
-
```
|
|
135
|
+
| 에러 | 대응 |
|
|
136
|
+
|------|------|
|
|
137
|
+
| MCP 연결 실패 | 설정 → OpenAI/Codex 등록 안내 |
|
|
138
|
+
| 401 | `codex auth login` 안내 |
|
|
139
|
+
| 타임아웃 | 재시도 |
|
|
140
|
+
| 세션 not found | 새 codex 세션 |
|
|
141
|
+
| 동시 요청 에러 | 이전 요청 완료 대기 |
|
|
332
142
|
|
|
333
143
|
</error_handling>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Cancel active Ralph Loop"
|
|
3
|
+
allowed-tools: ["Bash(test -f .claude/ralph-loop.local.md:*)", "Bash(rm .claude/ralph-loop.local.md)", "Read(.claude/ralph-loop.local.md)"]
|
|
4
|
+
hide-from-slash-command-tool: "true"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Cancel Ralph
|
|
8
|
+
|
|
9
|
+
To cancel the Ralph loop:
|
|
10
|
+
|
|
11
|
+
1. Check if `.claude/ralph-loop.local.md` exists using Bash: `test -f .claude/ralph-loop.local.md && echo "EXISTS" || echo "NOT_FOUND"`
|
|
12
|
+
|
|
13
|
+
2. **If NOT_FOUND**: Say "No active Ralph loop found."
|
|
14
|
+
|
|
15
|
+
3. **If EXISTS**:
|
|
16
|
+
- Read `.claude/ralph-loop.local.md` to get the current iteration number from the `iteration:` field
|
|
17
|
+
- Remove the file using Bash: `rm .claude/ralph-loop.local.md`
|
|
18
|
+
- Report: "Cancelled Ralph loop (was at iteration N)" where N is the iteration value
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 타겟 브랜치에 소스 브랜치를 merge 후 push
|
|
3
|
+
argument-hint: <target-branch> <source-branch>
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git Merge Command
|
|
7
|
+
|
|
8
|
+
> 타겟 브랜치에 소스 브랜치를 merge하고 push.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<scripts>
|
|
13
|
+
|
|
14
|
+
## 사용 가능한 스크립트
|
|
15
|
+
|
|
16
|
+
| 스크립트 | 용도 |
|
|
17
|
+
|----------|------|
|
|
18
|
+
| `.claude/scripts/git/git-merge.sh <target> <source>` | checkout → merge → push → 원래 브랜치 복귀 |
|
|
19
|
+
|
|
20
|
+
</scripts>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
<workflow>
|
|
25
|
+
|
|
26
|
+
## 워크플로우
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# 인자에서 타겟/소스 브랜치 추출 후 실행
|
|
30
|
+
.claude/scripts/git/git-merge.sh <target-branch> <source-branch>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**스크립트 동작:**
|
|
34
|
+
1. Working directory clean 확인
|
|
35
|
+
2. `git fetch origin`
|
|
36
|
+
3. 타겟 브랜치 checkout + pull
|
|
37
|
+
4. 소스 브랜치 merge (`--no-edit`)
|
|
38
|
+
5. 타겟 브랜치 push
|
|
39
|
+
6. 원래 브랜치로 복귀
|
|
40
|
+
|
|
41
|
+
</workflow>
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
<examples>
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# deploy/prod에 dev 머지
|
|
49
|
+
.claude/scripts/git/git-merge.sh deploy/prod dev
|
|
50
|
+
|
|
51
|
+
# main에 feature/auth 머지
|
|
52
|
+
.claude/scripts/git/git-merge.sh main feature/auth
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
</examples>
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
<error_handling>
|
|
60
|
+
|
|
61
|
+
| 상황 | 대응 |
|
|
62
|
+
|------|------|
|
|
63
|
+
| **Working directory dirty** | 커밋 또는 stash 후 재시도 안내 |
|
|
64
|
+
| **Merge conflict** | 수동 해결 안내 (타겟 브랜치에 머물러 있음) |
|
|
65
|
+
| **브랜치 미존재** | 에러 출력 후 종료 |
|
|
66
|
+
|
|
67
|
+
</error_handling>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Start Ralph Loop in current session"
|
|
3
|
+
argument-hint: "PROMPT [--max-iterations N] [--completion-promise TEXT]"
|
|
4
|
+
allowed-tools: ["Bash(.claude/scripts/setup-ralph-loop.sh:*)"]
|
|
5
|
+
hide-from-slash-command-tool: "true"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Ralph Loop Command
|
|
9
|
+
|
|
10
|
+
Execute the setup script to initialize the Ralph loop:
|
|
11
|
+
|
|
12
|
+
```!
|
|
13
|
+
".claude/scripts/setup-ralph-loop.sh" $ARGUMENTS
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Please work on the task. When you try to exit, the Ralph loop will feed the SAME PROMPT back to you for the next iteration. You'll see your previous work in files and git history, allowing you to iterate and improve.
|
|
17
|
+
|
|
18
|
+
CRITICAL RULE: If a completion promise is set, you may ONLY output it when the statement is completely and unequivocally TRUE. Do not output false promises to escape the loop, even if you think you're stuck or should exit for other reasons. The loop is designed to continue until genuine completion.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Ralph Loop Stop Hook
|
|
4
|
+
# Prevents session exit when a ralph-loop is active
|
|
5
|
+
# Feeds Claude's output back as input to continue the loop
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
# Read hook input from stdin (advanced stop hook API)
|
|
10
|
+
HOOK_INPUT=$(cat)
|
|
11
|
+
|
|
12
|
+
# Check if ralph-loop is active
|
|
13
|
+
RALPH_STATE_FILE=".claude/ralph-loop.local.md"
|
|
14
|
+
|
|
15
|
+
if [[ ! -f "$RALPH_STATE_FILE" ]]; then
|
|
16
|
+
# No active loop - allow exit
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Parse markdown frontmatter (YAML between ---) and extract values
|
|
21
|
+
FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$RALPH_STATE_FILE")
|
|
22
|
+
ITERATION=$(echo "$FRONTMATTER" | grep '^iteration:' | sed 's/iteration: *//')
|
|
23
|
+
MAX_ITERATIONS=$(echo "$FRONTMATTER" | grep '^max_iterations:' | sed 's/max_iterations: *//')
|
|
24
|
+
# Extract completion_promise and strip surrounding quotes if present
|
|
25
|
+
COMPLETION_PROMISE=$(echo "$FRONTMATTER" | grep '^completion_promise:' | sed 's/completion_promise: *//' | sed 's/^"\(.*\)"$/\1/')
|
|
26
|
+
|
|
27
|
+
# Validate numeric fields before arithmetic operations
|
|
28
|
+
if [[ ! "$ITERATION" =~ ^[0-9]+$ ]]; then
|
|
29
|
+
echo "Warning: Ralph loop state file corrupted (iteration: '$ITERATION')" >&2
|
|
30
|
+
rm "$RALPH_STATE_FILE"
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
|
|
35
|
+
echo "Warning: Ralph loop state file corrupted (max_iterations: '$MAX_ITERATIONS')" >&2
|
|
36
|
+
rm "$RALPH_STATE_FILE"
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Check if max iterations reached
|
|
41
|
+
if [[ $MAX_ITERATIONS -gt 0 ]] && [[ $ITERATION -ge $MAX_ITERATIONS ]]; then
|
|
42
|
+
echo "Ralph loop: Max iterations ($MAX_ITERATIONS) reached."
|
|
43
|
+
rm "$RALPH_STATE_FILE"
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Get transcript path from hook input
|
|
48
|
+
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path')
|
|
49
|
+
|
|
50
|
+
if [[ ! -f "$TRANSCRIPT_PATH" ]]; then
|
|
51
|
+
echo "Warning: Ralph loop transcript not found" >&2
|
|
52
|
+
rm "$RALPH_STATE_FILE"
|
|
53
|
+
exit 0
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Read last assistant message from transcript (JSONL format)
|
|
57
|
+
if ! grep -q '"role":"assistant"' "$TRANSCRIPT_PATH"; then
|
|
58
|
+
echo "Warning: No assistant messages in transcript" >&2
|
|
59
|
+
rm "$RALPH_STATE_FILE"
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
LAST_LINE=$(grep '"role":"assistant"' "$TRANSCRIPT_PATH" | tail -1)
|
|
64
|
+
if [[ -z "$LAST_LINE" ]]; then
|
|
65
|
+
rm "$RALPH_STATE_FILE"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
LAST_OUTPUT=$(echo "$LAST_LINE" | jq -r '
|
|
70
|
+
.message.content |
|
|
71
|
+
map(select(.type == "text")) |
|
|
72
|
+
map(.text) |
|
|
73
|
+
join("\n")
|
|
74
|
+
' 2>&1)
|
|
75
|
+
|
|
76
|
+
if [[ $? -ne 0 ]] || [[ -z "$LAST_OUTPUT" ]]; then
|
|
77
|
+
rm "$RALPH_STATE_FILE"
|
|
78
|
+
exit 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Check for completion promise (only if set)
|
|
82
|
+
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
83
|
+
PROMISE_TEXT=$(echo "$LAST_OUTPUT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")
|
|
84
|
+
|
|
85
|
+
if [[ -n "$PROMISE_TEXT" ]] && [[ "$PROMISE_TEXT" = "$COMPLETION_PROMISE" ]]; then
|
|
86
|
+
echo "Ralph loop: Detected <promise>$COMPLETION_PROMISE</promise>"
|
|
87
|
+
rm "$RALPH_STATE_FILE"
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Not complete - continue loop with SAME PROMPT
|
|
93
|
+
NEXT_ITERATION=$((ITERATION + 1))
|
|
94
|
+
|
|
95
|
+
PROMPT_TEXT=$(awk '/^---$/{i++; next} i>=2' "$RALPH_STATE_FILE")
|
|
96
|
+
|
|
97
|
+
if [[ -z "$PROMPT_TEXT" ]]; then
|
|
98
|
+
echo "Warning: Ralph loop state file has no prompt" >&2
|
|
99
|
+
rm "$RALPH_STATE_FILE"
|
|
100
|
+
exit 0
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Update iteration (atomic write)
|
|
104
|
+
TEMP_FILE="${RALPH_STATE_FILE}.tmp.$$"
|
|
105
|
+
sed "s/^iteration: .*/iteration: $NEXT_ITERATION/" "$RALPH_STATE_FILE" > "$TEMP_FILE"
|
|
106
|
+
mv "$TEMP_FILE" "$RALPH_STATE_FILE"
|
|
107
|
+
|
|
108
|
+
# Build system message
|
|
109
|
+
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
|
|
110
|
+
SYSTEM_MSG="Ralph iteration $NEXT_ITERATION | To stop: output <promise>$COMPLETION_PROMISE</promise> (ONLY when TRUE)"
|
|
111
|
+
else
|
|
112
|
+
SYSTEM_MSG="Ralph iteration $NEXT_ITERATION | No completion promise - loop runs until max iterations"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
jq -n \
|
|
116
|
+
--arg prompt "$PROMPT_TEXT" \
|
|
117
|
+
--arg msg "$SYSTEM_MSG" \
|
|
118
|
+
'{
|
|
119
|
+
"decision": "block",
|
|
120
|
+
"reason": $prompt,
|
|
121
|
+
"systemMessage": $msg
|
|
122
|
+
}'
|
|
123
|
+
|
|
124
|
+
exit 0
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# git-merge.sh - 타겟 브랜치에 소스 브랜치를 merge 후 push
|
|
3
|
+
# Usage: ./git-merge.sh <target-branch> <source-branch>
|
|
4
|
+
# Example: ./git-merge.sh deploy/prod dev
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# Git 저장소 확인
|
|
9
|
+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
10
|
+
echo "Error: Not a git repository"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if [ $# -lt 2 ]; then
|
|
15
|
+
echo "Usage: $0 <target-branch> <source-branch>"
|
|
16
|
+
echo "Example: $0 deploy/prod dev"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
TARGET="$1"
|
|
21
|
+
SOURCE="$2"
|
|
22
|
+
ORIGINAL_BRANCH=$(git branch --show-current)
|
|
23
|
+
|
|
24
|
+
# Working directory clean 확인
|
|
25
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
26
|
+
echo "Error: Working directory is not clean. Commit or stash changes first."
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# 소스 브랜치 존재 확인
|
|
31
|
+
if ! git rev-parse --verify "$SOURCE" >/dev/null 2>&1; then
|
|
32
|
+
echo "Error: Source branch '$SOURCE' does not exist"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# 타겟 브랜치 존재 확인
|
|
37
|
+
if ! git rev-parse --verify "$TARGET" >/dev/null 2>&1; then
|
|
38
|
+
echo "Error: Target branch '$TARGET' does not exist"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo "=== Merging '$SOURCE' into '$TARGET' ==="
|
|
43
|
+
|
|
44
|
+
# remote 최신화
|
|
45
|
+
echo "--- Fetching origin ---"
|
|
46
|
+
git fetch origin
|
|
47
|
+
|
|
48
|
+
# 타겟 브랜치로 전환
|
|
49
|
+
echo "--- Checkout '$TARGET' ---"
|
|
50
|
+
git checkout "$TARGET"
|
|
51
|
+
|
|
52
|
+
# 타겟 브랜치 최신화
|
|
53
|
+
echo "--- Pulling latest '$TARGET' ---"
|
|
54
|
+
git pull origin "$TARGET" --ff-only || git pull origin "$TARGET"
|
|
55
|
+
|
|
56
|
+
# 머지 실행
|
|
57
|
+
echo "--- Merging '$SOURCE' into '$TARGET' ---"
|
|
58
|
+
if ! git merge "$SOURCE" --no-edit; then
|
|
59
|
+
echo "Error: Merge conflict detected. Resolve manually."
|
|
60
|
+
echo "You are now on '$TARGET' branch."
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 푸시
|
|
65
|
+
echo "--- Pushing '$TARGET' ---"
|
|
66
|
+
git push origin "$TARGET"
|
|
67
|
+
|
|
68
|
+
# 원래 브랜치로 복귀
|
|
69
|
+
echo "--- Returning to '$ORIGINAL_BRANCH' ---"
|
|
70
|
+
git checkout "$ORIGINAL_BRANCH"
|
|
71
|
+
|
|
72
|
+
echo ""
|
|
73
|
+
echo "Done: Merged '$SOURCE' into '$TARGET' and pushed."
|