@elyun/bylane 1.27.0 → 1.29.0
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/commands/bylane-code-agent.md +155 -44
- package/commands/bylane-orchestrator.md +80 -50
- package/commands/bylane-review-agent.md +11 -2
- package/commands/bylane-setup.md +13 -4
- package/package.json +1 -1
- package/src/cli.js +43 -5
- package/src/config.js +2 -1
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bylane-code-agent
|
|
3
|
-
description: issue-agent가 작성한 전략
|
|
3
|
+
description: issue-agent가 작성한 전략 스펙을 기반으로 코드를 구현한다. 내부적으로 분석/구현/리뷰 서브에이전트를 활용하며, 서브에이전트 간 피드백 루프(Ralph Loop)로 품질을 보장한다. 부모 에이전트에게는 최종 결과만 반환한다.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Code Agent
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
> **설계 원칙**: code-agent 본체는 **오케스트레이션만** 담당한다. 실제 파일 읽기/수정/분석은 전부 서브에이전트가 수행한다. 부모(orchestrator)에게는 `changedFiles` 결과만 돌려준다.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 실행 전 상태 기록
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @elyun/bylane state write code-agent '{"status":"in_progress","startedAt":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","progress":0,"currentTask":"서브에이전트 초기화","retries":0,"log":[]}'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
9
19
|
|
|
10
|
-
|
|
20
|
+
## 입력 읽기
|
|
11
21
|
|
|
12
22
|
`.bylane/state/issue-agent.json`에서 다음 필드를 읽는다:
|
|
13
23
|
|
|
@@ -19,73 +29,172 @@ description: issue-agent가 작성한 전략 스펙(이슈 본문)을 기반으
|
|
|
19
29
|
| `spec.checklist` | 구현 체크리스트 |
|
|
20
30
|
| `spec.figmaSpec` | Figma 컬러토큰·컴포넌트 구조 |
|
|
21
31
|
| `issueType` | `new-feature` / `bug` / `improvement` / `chore` |
|
|
32
|
+
| `issueNumber` | GitHub 이슈 번호 |
|
|
22
33
|
|
|
23
|
-
없으면 GitHub 이슈 본문을 직접 로드하여
|
|
24
|
-
|
|
25
|
-
### 2. issueMemory 로드
|
|
26
|
-
|
|
27
|
-
이슈 번호를 알고 있으면 이전 세션 컨텍스트를 확인한다:
|
|
34
|
+
없으면 GitHub 이슈 본문을 직접 로드하여 파싱한다.
|
|
28
35
|
|
|
36
|
+
issueMemory 로드:
|
|
29
37
|
```bash
|
|
30
38
|
npx @elyun/bylane memory read ISSUE_NUMBER
|
|
31
39
|
```
|
|
32
40
|
|
|
33
|
-
아키텍처 결정이나 트러블슈팅 기록이 있으면 구현에 반영한다.
|
|
34
|
-
|
|
35
41
|
---
|
|
36
42
|
|
|
37
|
-
##
|
|
43
|
+
## Phase 1 — 병렬 분석 서브에이전트 (3개 동시 실행)
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
Agent 도구로 3개를 **동시에** 호출한다.
|
|
46
|
+
각 서브에이전트는 결과만 텍스트로 반환하고, code-agent 본체는 취합한다.
|
|
47
|
+
|
|
48
|
+
### 서브에이전트 A — 파일 현황 분석
|
|
49
|
+
```
|
|
50
|
+
prompt: |
|
|
51
|
+
다음 파일들의 현재 구현 상태를 분석해줘:
|
|
52
|
+
대상: {spec.affectedFiles}
|
|
53
|
+
issueType: {issueType}
|
|
54
|
+
|
|
55
|
+
각 파일에 대해:
|
|
56
|
+
- 현재 구현 방식 요약 (있는 경우)
|
|
57
|
+
- 변경이 필요한 라인/영역
|
|
58
|
+
- 의존하는 import 목록
|
|
59
|
+
|
|
60
|
+
결과만 간결하게 텍스트로 반환. 파일을 직접 수정하지 마라.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 서브에이전트 B — 코드 패턴 샘플링
|
|
64
|
+
```
|
|
65
|
+
prompt: |
|
|
66
|
+
이 프로젝트에서 유사한 구현 패턴을 찾아줘.
|
|
67
|
+
구현할 기능: {spec.title}
|
|
68
|
+
issueType: {issueType}
|
|
69
|
+
|
|
70
|
+
찾아야 할 것:
|
|
71
|
+
- 유사한 컴포넌트/함수 구현 예시 (파일경로:라인번호)
|
|
72
|
+
- 사용 중인 네이밍 컨벤션
|
|
73
|
+
- 테스트 파일 위치와 작성 패턴
|
|
74
|
+
- 상태 관리 / API 호출 방식
|
|
75
|
+
|
|
76
|
+
결과만 간결하게 텍스트로 반환. 파일을 수정하지 마라.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 서브에이전트 C — 영향 범위 확인
|
|
80
|
+
```
|
|
81
|
+
prompt: |
|
|
82
|
+
다음 파일들을 수정할 때 영향받는 코드를 파악해줘:
|
|
83
|
+
대상: {spec.affectedFiles}
|
|
84
|
+
|
|
85
|
+
찾아야 할 것:
|
|
86
|
+
- 이 파일들을 import/사용하는 파일 목록
|
|
87
|
+
- 공유 컴포넌트/훅인 경우 사이드 이펙트 위험도
|
|
88
|
+
- bug/improvement인 경우: 현재 문제 지점 (파일:라인)
|
|
89
|
+
|
|
90
|
+
결과만 간결하게 텍스트로 반환. 파일을 수정하지 마라.
|
|
41
91
|
```
|
|
42
92
|
|
|
43
93
|
---
|
|
44
94
|
|
|
45
|
-
##
|
|
95
|
+
## Phase 2 — Ralph Loop: 구현 → 리뷰 → 피드백 사이클
|
|
96
|
+
|
|
97
|
+
`spec.checklist` 항목을 순서대로 처리한다.
|
|
98
|
+
각 항목마다 **구현 서브에이전트 → 리뷰 서브에이전트** 쌍으로 실행하며,
|
|
99
|
+
리뷰가 통과될 때까지 피드백을 실어 구현 서브에이전트를 재호출한다.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
for each checklistItem in spec.checklist:
|
|
103
|
+
|
|
104
|
+
feedback = null
|
|
105
|
+
retries = 0
|
|
46
106
|
|
|
47
|
-
|
|
107
|
+
while true:
|
|
108
|
+
[구현 서브에이전트 호출]
|
|
109
|
+
[리뷰 서브에이전트 호출]
|
|
48
110
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
- 유사 구현 패턴(이슈 본문 "코드 패턴 참고" 섹션) 따르기
|
|
52
|
-
- Figma 스펙이 있으면 컬러토큰 → CSS 변수/Tailwind config 변환
|
|
111
|
+
if 리뷰 통과 → break
|
|
112
|
+
if retries >= 2 → 상태에 경고 기록 후 break
|
|
53
113
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- 재현 케이스를 테스트로 먼저 작성 (TDD)
|
|
114
|
+
feedback = 리뷰 결과
|
|
115
|
+
retries++
|
|
116
|
+
```
|
|
58
117
|
|
|
59
|
-
|
|
60
|
-
- 기존 구현 파악 후 변경 범위 최소화
|
|
61
|
-
- 사이드 이펙트 발생 가능 파일은 이슈 본문 "영향 범위" 기준으로 확인
|
|
118
|
+
### 구현 서브에이전트 프롬프트
|
|
62
119
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
120
|
+
```
|
|
121
|
+
prompt: |
|
|
122
|
+
다음 체크리스트 항목을 구현해줘.
|
|
123
|
+
|
|
124
|
+
[컨텍스트]
|
|
125
|
+
- 작업: {spec.title}
|
|
126
|
+
- issueType: {issueType}
|
|
127
|
+
- 구현 방향: {spec.approach}
|
|
128
|
+
- 현재 항목: {checklistItem}
|
|
129
|
+
- 관련 파일: {spec.affectedFiles에서 이 항목과 관련된 파일}
|
|
130
|
+
|
|
131
|
+
[분석 결과]
|
|
132
|
+
- 파일 현황: {서브에이전트 A 결과}
|
|
133
|
+
- 참고 패턴: {서브에이전트 B 결과}
|
|
134
|
+
- 영향 범위: {서브에이전트 C 결과}
|
|
135
|
+
|
|
136
|
+
{feedback이 있으면 추가:}
|
|
137
|
+
[이전 리뷰 피드백 — 이 내용을 반드시 반영해야 함]
|
|
138
|
+
{feedback}
|
|
139
|
+
|
|
140
|
+
[코딩 원칙]
|
|
141
|
+
- 함수형 컴포넌트 + hooks 우선
|
|
142
|
+
- 파일당 단일 책임
|
|
143
|
+
- 200줄 초과 시 분리 고려
|
|
144
|
+
- 불변성 패턴 유지 (객체 직접 수정 금지)
|
|
145
|
+
- issueType이 bug라면 최소 변경으로 수정
|
|
146
|
+
- issueType이 chore라면 기능 변경 없음 확인
|
|
147
|
+
|
|
148
|
+
구현 완료 후 변경한 파일 목록만 반환해줘.
|
|
149
|
+
```
|
|
66
150
|
|
|
67
|
-
###
|
|
151
|
+
### 리뷰 서브에이전트 프롬프트
|
|
68
152
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
153
|
+
```
|
|
154
|
+
prompt: |
|
|
155
|
+
방금 구현된 코드를 리뷰해줘.
|
|
156
|
+
|
|
157
|
+
[검토 대상]
|
|
158
|
+
- 항목: {checklistItem}
|
|
159
|
+
- 변경 파일: {구현 서브에이전트가 반환한 파일 목록}
|
|
160
|
+
|
|
161
|
+
[체크리스트]
|
|
162
|
+
1. spec.approach 방향과 일치하는가?
|
|
163
|
+
2. 코딩 원칙(불변성, 단일책임, 200줄) 준수했는가?
|
|
164
|
+
3. issueType별 주의사항 지켰는가?
|
|
165
|
+
- new-feature: 신규 파일 패턴이 기존 패턴과 일치하는가
|
|
166
|
+
- bug: 최소 변경인가, 다른 동작 변경 없는가
|
|
167
|
+
- improvement: 사이드 이펙트 없는가
|
|
168
|
+
- chore: 기능 변경 없는가
|
|
169
|
+
4. 명백한 버그나 누락 없는가?
|
|
170
|
+
|
|
171
|
+
응답 형식:
|
|
172
|
+
PASS — 문제 없음 (한 줄 요약)
|
|
173
|
+
FAIL — {구체적인 문제점과 수정 방향}
|
|
174
|
+
|
|
175
|
+
코드를 직접 수정하지 마라. 판정만 내려줘.
|
|
176
|
+
```
|
|
75
177
|
|
|
76
|
-
###
|
|
178
|
+
### 상태 로그 (각 항목 완료 시)
|
|
77
179
|
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
- 불변성 패턴 유지 (객체 직접 수정 금지)
|
|
180
|
+
```bash
|
|
181
|
+
npx @elyun/bylane state append code-agent "{checklistItem} 구현 완료 (리뷰 통과)"
|
|
182
|
+
```
|
|
82
183
|
|
|
83
184
|
---
|
|
84
185
|
|
|
85
|
-
## 완료 처리
|
|
186
|
+
## Phase 3 — 완료 처리
|
|
187
|
+
|
|
188
|
+
모든 체크리스트 항목이 완료되면:
|
|
86
189
|
|
|
87
190
|
```bash
|
|
88
|
-
npx @elyun/bylane state write code-agent '{
|
|
191
|
+
npx @elyun/bylane state write code-agent '{
|
|
192
|
+
"status": "completed",
|
|
193
|
+
"progress": 100,
|
|
194
|
+
"currentTask": "구현 완료",
|
|
195
|
+
"retries": 0,
|
|
196
|
+
"changedFiles": CHANGED_FILES_ARRAY
|
|
197
|
+
}'
|
|
89
198
|
```
|
|
90
199
|
|
|
91
200
|
---
|
|
@@ -105,7 +214,9 @@ npx @elyun/bylane memory append ISSUE_NUMBER code-agent "구현 요약: SUMMARY
|
|
|
105
214
|
|
|
106
215
|
## 출력
|
|
107
216
|
|
|
108
|
-
|
|
217
|
+
부모(orchestrator)에게 돌려주는 값:
|
|
218
|
+
- `.bylane/state/code-agent.json`의 `changedFiles` 배열
|
|
219
|
+
- `status: "completed"` 또는 `"failed"`
|
|
109
220
|
|
|
110
221
|
## 수동 실행
|
|
111
222
|
|
|
@@ -1,51 +1,50 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bylane-orchestrator
|
|
3
|
-
description: byLane 메인 오케스트레이터. 자연어 의도를 파싱하여 4가지 파이프라인(새 기능/기존 이슈/리뷰/단일 에이전트) 중 하나를
|
|
3
|
+
description: byLane 메인 오케스트레이터. 자연어 의도를 파싱하여 4가지 파이프라인(새 기능/기존 이슈/리뷰/단일 에이전트) 중 하나를 선택하고, 각 단계를 **서브에이전트**로 위임하여 실행한다. 오케스트레이터 본체는 상태 파일만 읽고 판단하며, 직접 구현하지 않는다.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# byLane Orchestrator
|
|
7
7
|
|
|
8
8
|
## 역할
|
|
9
9
|
|
|
10
|
-
사용자 의도를 파싱하고,
|
|
10
|
+
사용자 의도를 파싱하고, 파이프라인을 결정한 뒤 **각 에이전트를 서브에이전트로 위임**한다.
|
|
11
|
+
오케스트레이터 자신은 **상태 조회와 다음 단계 결정**만 담당한다. 직접 코드를 수정하거나 이슈를 작성하지 않는다.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
> **Hang 방지 원칙**: 오케스트레이터는 Agent 도구로 서브에이전트를 호출하고 결과만 받는다.
|
|
14
|
+
> 긴 작업(코드 구현, 분석, 테스트 등)을 직접 수행하면 Claude Code가 hang될 수 있다.
|
|
15
|
+
|
|
16
|
+
---
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npx @elyun/bylane preflight
|
|
17
|
-
```
|
|
18
|
-
실패 시 안내 메시지 출력 후 **중단**. `.bylane/bylane.json` 없으면 즉시 `bylane-setup` 스킬 실행.
|
|
18
|
+
## 실행 전 체크
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npx @elyun/bylane preflight
|
|
22
|
+
```
|
|
23
|
+
실패 시 안내 메시지 출력 후 **중단**. `.bylane/bylane.json` 없으면 즉시 `bylane-setup` 스킬 실행.
|
|
21
24
|
|
|
22
25
|
## 에이전트별 모델 결정
|
|
23
26
|
|
|
24
27
|
```bash
|
|
25
28
|
npx @elyun/bylane models
|
|
26
29
|
```
|
|
30
|
+
출력 형식: `AGENT_NAME=MODEL_ID`. 서브에이전트 호출 시 `model` 파라미터로 전달.
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
---
|
|
29
33
|
|
|
30
34
|
## 의도 파싱 규칙
|
|
31
35
|
|
|
32
|
-
오케스트레이터는 `/bylane`에서 **복합 의도** 또는 **기능 요청 자연어**가 넘어올 때 실행된다.
|
|
33
|
-
단일 에이전트 키워드는 `/bylane`이 직접 라우팅하므로, 오케스트레이터는 **파이프라인 실행**에 집중한다.
|
|
34
|
-
|
|
35
36
|
### 파이프라인 A — 새 기능 / 이슈 없는 구현 요청
|
|
36
37
|
|
|
37
38
|
**감지 키워드**: `만들어`, `추가해`, `구현해`, `개발해`, `넣어줘`, `바꿔줘`, `변경해`, `개선해`, `수정해`,
|
|
38
39
|
`리팩터`, `리팩토링`, `마이그레이션`, `~해줘` (기능 설명 포함), 이슈 번호 없음
|
|
39
40
|
|
|
40
|
-
**실행 흐름**:
|
|
41
|
-
전략 수립 → `issue-agent` → `code-agent` → `test-agent` → `commit-agent` → `pr-agent` → `review-agent` → `notify-agent`
|
|
41
|
+
**실행 흐름**: `issue-agent` → `code-agent` → `test-agent` → `commit-agent` → `pr-agent` → `review-agent` → `notify-agent`
|
|
42
42
|
|
|
43
43
|
### 파이프라인 B — 기존 이슈 구현
|
|
44
44
|
|
|
45
45
|
**감지 키워드**: `#N`, `이슈 #N`, `issue #N`, `#N 구현`, `#N 작업`, `#N 해줘`, `#N 처리`
|
|
46
46
|
|
|
47
|
-
**실행 흐름**:
|
|
48
|
-
전략 수립(기존 이슈 분석) → `code-agent` → `test-agent` → `commit-agent` → `pr-agent` → `review-agent` → `notify-agent`
|
|
47
|
+
**실행 흐름**: `code-agent` → `test-agent` → `commit-agent` → `pr-agent` → `review-agent` → `notify-agent`
|
|
49
48
|
|
|
50
49
|
### 파이프라인 C — 리뷰 관련
|
|
51
50
|
|
|
@@ -53,62 +52,93 @@ npx @elyun/bylane models
|
|
|
53
52
|
|---|---|
|
|
54
53
|
| `PR #N 리뷰`, `리뷰해줘`, `코드 리뷰`, `#N 봐줘` | `review-agent`(PR번호 전달) |
|
|
55
54
|
| `리뷰 반영`, `수락`, `accept`, `LGTM 반영`, `코멘트 반영` | `respond-agent`(모드=accept) |
|
|
56
|
-
| `반박`, `rebut`, `동의 안 해`, `이유
|
|
55
|
+
| `반박`, `rebut`, `동의 안 해`, `이유 설명` | `respond-agent`(모드=rebut) |
|
|
57
56
|
|
|
58
|
-
### 파이프라인 D — 단일 에이전트
|
|
57
|
+
### 파이프라인 D — 단일 에이전트
|
|
59
58
|
|
|
60
59
|
| 감지 키워드 | 실행 |
|
|
61
60
|
|---|---|
|
|
62
|
-
| `커밋`, `commit
|
|
63
|
-
| `PR`, `풀리퀘`, `PR
|
|
64
|
-
| `테스트`, `test`,
|
|
65
|
-
| `분석`,
|
|
66
|
-
| `알림`, `notify
|
|
67
|
-
|
|
68
|
-
### 파이프라인 판단 기준
|
|
61
|
+
| `커밋`, `commit` | `commit-agent` |
|
|
62
|
+
| `PR`, `풀리퀘`, `PR 만들어` | `pr-agent` |
|
|
63
|
+
| `테스트`, `test`, `검증` | `test-agent` |
|
|
64
|
+
| `분석`, `구조 파악` | `analyze-agent` |
|
|
65
|
+
| `알림`, `notify` | `notify-agent` |
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
2. 기능/변경 요청 키워드가 있고 이슈 번호 없으면 → **파이프라인 A**
|
|
72
|
-
3. 리뷰/대응 키워드가 있으면 → **파이프라인 C**
|
|
73
|
-
4. 단일 에이전트 키워드만 있으면 → **파이프라인 D**
|
|
74
|
-
5. 복합 키워드 ("이슈 만들고 구현까지", "테스트하고 커밋") → 파이프라인 A 또는 해당 에이전트 순차 실행
|
|
75
|
-
6. 판단 불가 → 사용자에게 의도 확인
|
|
67
|
+
### 판단 기준
|
|
76
68
|
|
|
77
|
-
|
|
69
|
+
1. 이슈 번호(`#N`) → 파이프라인 B
|
|
70
|
+
2. 기능/변경 키워드 + 이슈 번호 없음 → 파이프라인 A
|
|
71
|
+
3. 리뷰/대응 키워드 → 파이프라인 C
|
|
72
|
+
4. 단일 에이전트 키워드만 → 파이프라인 D
|
|
73
|
+
5. 판단 불가 → 사용자에게 의도 확인
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
---
|
|
80
76
|
|
|
81
|
-
|
|
77
|
+
## 파이프라인 실행 방식 (핵심)
|
|
82
78
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
3. 이슈 분류 및 작성
|
|
79
|
+
오케스트레이터는 각 에이전트를 **Agent 도구로 서브에이전트 호출**한다.
|
|
80
|
+
서브에이전트가 완료되면 `.bylane/state/{name}.json`의 `status`만 확인하고 다음 단계로 진행한다.
|
|
86
81
|
|
|
87
|
-
|
|
82
|
+
```
|
|
83
|
+
[오케스트레이터]
|
|
84
|
+
↓ Agent 도구 호출 (bylane-issue-agent 스킬)
|
|
85
|
+
[issue-agent 서브에이전트] — 내부에서 3개 병렬 분석 서브에이전트 실행
|
|
86
|
+
↓ 완료 → .bylane/state/issue-agent.json 에 결과 기록
|
|
87
|
+
[오케스트레이터] state 확인 → issueNumber, spec 읽기
|
|
88
|
+
↓ Agent 도구 호출 (bylane-code-agent 스킬)
|
|
89
|
+
[code-agent 서브에이전트] — 내부에서 구현/리뷰 피드백 루프 실행
|
|
90
|
+
↓ 완료 → .bylane/state/code-agent.json 에 결과 기록
|
|
91
|
+
[오케스트레이터] state 확인 → changedFiles 읽기
|
|
92
|
+
↓ ... (이하 동일)
|
|
93
|
+
```
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
### 각 에이전트 호출 방법
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
**config에서 읽은 모델을 `model` 파라미터로 반드시 전달.**
|
|
97
|
+
Agent 도구에 아래 형식으로 전달한다:
|
|
93
98
|
|
|
94
|
-
상태 기록 (각 에이전트 시작 전):
|
|
95
|
-
```bash
|
|
96
|
-
npx @elyun/bylane state write AGENT_NAME '{"status":"in_progress","startedAt":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","progress":0,"currentTask":"TASK_DESCRIPTION","retries":0,"log":[]}'
|
|
97
99
|
```
|
|
100
|
+
subagent_type: "general-purpose"
|
|
101
|
+
model: {models 명령으로 확인한 해당 에이전트 모델}
|
|
102
|
+
prompt: |
|
|
103
|
+
다음 bylane 스킬을 실행해줘: bylane-{에이전트명}
|
|
104
|
+
|
|
105
|
+
[컨텍스트]
|
|
106
|
+
- 이슈 번호: {issueNumber} (있는 경우)
|
|
107
|
+
- 이슈 URL: {issueUrl} (있는 경우)
|
|
108
|
+
- 이전 단계 출력: {이전 state 파일 핵심 필드}
|
|
109
|
+
|
|
110
|
+
스킬 완료 후 .bylane/state/{에이전트명}.json 에 결과가 기록된다.
|
|
111
|
+
결과 파일의 status, 핵심 출력 필드만 응답으로 돌려줘.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
98
115
|
|
|
99
|
-
## 피드백 루프
|
|
116
|
+
## 피드백 루프 (오케스트레이터 레벨)
|
|
100
117
|
|
|
101
118
|
test-agent가 FAIL 반환 시:
|
|
119
|
+
|
|
102
120
|
1. `.bylane/state/test-agent.json`에서 `failureDetails` 읽기
|
|
103
|
-
2. `retries < config.workflow.maxRetries` → code-agent
|
|
121
|
+
2. `retries < config.workflow.maxRetries` → **code-agent 서브에이전트 재호출** (failureDetails 포함, retries+1)
|
|
104
122
|
3. `retries >= maxRetries` → notify-agent에 "개입 필요" 메시지 후 중단
|
|
105
123
|
|
|
106
|
-
respond-agent가 "수정 필요" 반환 시 동일
|
|
124
|
+
respond-agent가 "수정 필요" 반환 시 동일 로직.
|
|
125
|
+
|
|
126
|
+
> 재호출 시 code-agent에 전달할 추가 컨텍스트:
|
|
127
|
+
> `"이전 테스트 실패 내용: {failureDetails}. 해당 부분을 중점적으로 수정해줘."`
|
|
128
|
+
|
|
129
|
+
---
|
|
107
130
|
|
|
108
131
|
## 완료 처리
|
|
109
132
|
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
각 에이전트 완료 후 notify-agent 서브에이전트 호출:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
prompt: |
|
|
137
|
+
bylane-notify-agent 스킬 실행.
|
|
138
|
+
type: completed
|
|
139
|
+
summary: {전체 파이프라인 요약}
|
|
140
|
+
url: {PR URL}
|
|
141
|
+
```
|
|
112
142
|
|
|
113
143
|
## 수동 실행
|
|
114
144
|
|
|
@@ -158,7 +158,16 @@ curl -s -X POST \
|
|
|
158
158
|
}'
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
`event`
|
|
161
|
+
`event` 값 결정:
|
|
162
|
+
|
|
163
|
+
| 조건 | `review.autoApprove` | event |
|
|
164
|
+
|------|---------------------|-------|
|
|
165
|
+
| 지적사항 있음 | 무관 | `"REQUEST_CHANGES"` |
|
|
166
|
+
| 지적사항 없음 | `true` | `"APPROVE"` |
|
|
167
|
+
| 지적사항 없음 | `false` (기본) | `"COMMENT"` — 사람이 직접 Approve 판단 |
|
|
168
|
+
| 코멘트만 | 무관 | `"COMMENT"` |
|
|
169
|
+
|
|
170
|
+
`review.autoApprove`가 `false`(기본값)이면 AI가 Approve를 내리지 않고 코멘트만 남긴다.
|
|
162
171
|
|
|
163
172
|
### 4. 전체 요약 (PR 전체 코멘트)
|
|
164
173
|
|
|
@@ -175,7 +184,7 @@ curl -s -X POST \
|
|
|
175
184
|
```
|
|
176
185
|
|
|
177
186
|
푸터: `review.footer`의 `{model}`을 실제 모델명으로, `{date}`를 현재 날짜로 치환.
|
|
178
|
-
기본 푸터:
|
|
187
|
+
기본 푸터: `🤖 {model} · {date}` — 모델명 앞에 🤖 이모지로 AI 리뷰임을 표시
|
|
179
188
|
|
|
180
189
|
### 5. 상태 업데이트
|
|
181
190
|
|
package/commands/bylane-setup.md
CHANGED
|
@@ -83,7 +83,16 @@ Linear API Key는 환경변수명(`LINEAR_API_KEY`)으로 저장. 실제 키값
|
|
|
83
83
|
|
|
84
84
|
`permissions.scope`에 저장.
|
|
85
85
|
|
|
86
|
-
## Step 5/
|
|
86
|
+
## Step 5/9 — 리뷰 자동 Approve
|
|
87
|
+
|
|
88
|
+
> AI 리뷰에서 지적사항이 없을 때 자동으로 Approve할까요? (y/n, 기본: n)
|
|
89
|
+
|
|
90
|
+
- `n` (기본) → `review.autoApprove = false` — AI는 코멘트만 남기고, Approve는 사람이 직접 판단
|
|
91
|
+
- `y` → `review.autoApprove = true` — 지적사항 없으면 AI가 자동 Approve
|
|
92
|
+
|
|
93
|
+
대부분의 팀에서는 사람이 최종 Approve하는 것을 권장한다.
|
|
94
|
+
|
|
95
|
+
## Step 6/9 — Loop 실행 모드
|
|
87
96
|
|
|
88
97
|
> Loop 실행 모드를 선택하세요:
|
|
89
98
|
> 1. tmux — tmux 세션에서 백그라운드 실행 (터미널 종료 후에도 유지, 권장)
|
|
@@ -108,7 +117,7 @@ bylane loop stop # loop 종료
|
|
|
108
117
|
bylane loop status # 상태 확인
|
|
109
118
|
```
|
|
110
119
|
|
|
111
|
-
## Step
|
|
120
|
+
## Step 7/9 — 고급 설정
|
|
112
121
|
|
|
113
122
|
> 고급 설정을 변경하시겠습니까? (Enter = 기본값 사용)
|
|
114
123
|
|
|
@@ -117,7 +126,7 @@ bylane loop status # 상태 확인
|
|
|
117
126
|
- `loopTimeoutMinutes` (기본: 30): 루프 타임아웃 (분)
|
|
118
127
|
- Figma MCP 활성화? (y/n, 기본: n)
|
|
119
128
|
|
|
120
|
-
## Step
|
|
129
|
+
## Step 8/9 — 브랜치 네이밍
|
|
121
130
|
|
|
122
131
|
> 브랜치 네이밍 패턴을 선택하세요:
|
|
123
132
|
> 1. {tracker}-{issue-number} 예) issues-32
|
|
@@ -132,7 +141,7 @@ bylane loop status # 상태 확인
|
|
|
132
141
|
직접 입력 시 사용 가능한 토큰 목록 안내:
|
|
133
142
|
`{tracker}`, `{type}`, `{issue-number}`, `{custom-id}`, `{title-slug}`, `{date}`, `{username}`
|
|
134
143
|
|
|
135
|
-
## Step
|
|
144
|
+
## Step 9/9 — 에이전트 모델 설정
|
|
136
145
|
|
|
137
146
|
> 각 에이전트에 사용할 AI 모델을 설정하시겠습니까? (Enter = 기본값 사용)
|
|
138
147
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { mkdirSync, symlinkSync, existsSync, readdirSync, copyFileSync, renameSync, readFileSync, writeFileSync } from 'fs'
|
|
2
|
+
import { mkdirSync, symlinkSync, existsSync, readdirSync, copyFileSync, renameSync, readFileSync, writeFileSync, rmSync } from 'fs'
|
|
3
3
|
import { join, dirname } from 'path'
|
|
4
4
|
import { fileURLToPath } from 'url'
|
|
5
5
|
import { homedir } from 'os'
|
|
@@ -33,10 +33,8 @@ function backupAndCopy(src, dest, file, label) {
|
|
|
33
33
|
console.log(` = ${label}: ${file} (변경 없음, 건너뜀)`)
|
|
34
34
|
return
|
|
35
35
|
}
|
|
36
|
-
const backupPath = `${destFile}.bak`
|
|
37
|
-
renameSync(destFile, backupPath)
|
|
38
36
|
copyFileSync(srcFile, destFile)
|
|
39
|
-
console.log(` ~ ${label}: ${file} (
|
|
37
|
+
console.log(` ~ ${label}: ${file} (업데이트됨)`)
|
|
40
38
|
} else {
|
|
41
39
|
copyFileSync(srcFile, destFile)
|
|
42
40
|
console.log(` + ${label}: ${file}`)
|
|
@@ -139,8 +137,48 @@ function install() {
|
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
139
|
|
|
140
|
+
function uninstall() {
|
|
141
|
+
console.log('\n byLane 제거 중...\n')
|
|
142
|
+
|
|
143
|
+
for (const { src, dest, label } of TARGETS) {
|
|
144
|
+
if (!existsSync(dest)) continue
|
|
145
|
+
const files = readdirSync(src)
|
|
146
|
+
for (const file of files) {
|
|
147
|
+
const destFile = join(dest, file)
|
|
148
|
+
if (existsSync(destFile)) {
|
|
149
|
+
rmSync(destFile)
|
|
150
|
+
console.log(` - ${label}: ${file}`)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// settings.json에서 bylane 훅 제거
|
|
156
|
+
const settingsPath = join(CLAUDE_DIR, 'settings.json')
|
|
157
|
+
if (existsSync(settingsPath)) {
|
|
158
|
+
try {
|
|
159
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'))
|
|
160
|
+
const stripBylane = (arr) =>
|
|
161
|
+
(arr ?? []).filter(h => !h.hooks?.some(hh => hh.command?.includes('bylane-agent-tracker')))
|
|
162
|
+
settings.hooks = settings.hooks ?? {}
|
|
163
|
+
settings.hooks.PreToolUse = stripBylane(settings.hooks.PreToolUse)
|
|
164
|
+
settings.hooks.PostToolUse = stripBylane(settings.hooks.PostToolUse)
|
|
165
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2))
|
|
166
|
+
console.log(' - Hook: bylane-agent-tracker 제거')
|
|
167
|
+
} catch {}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log(`
|
|
171
|
+
byLane 제거 완료.
|
|
172
|
+
|
|
173
|
+
사용자 설정(.bylane/bylane.json)은 유지됩니다.
|
|
174
|
+
Claude Code를 재시작하면 변경사항이 적용됩니다.
|
|
175
|
+
`)
|
|
176
|
+
}
|
|
177
|
+
|
|
142
178
|
if (command === 'install') {
|
|
143
179
|
install()
|
|
180
|
+
} else if (command === 'uninstall') {
|
|
181
|
+
uninstall()
|
|
144
182
|
} else if (command === 'preflight') {
|
|
145
183
|
const { runPreflight, formatPreflight } = await import('./preflight.js')
|
|
146
184
|
const result = runPreflight()
|
|
@@ -320,6 +358,6 @@ if (command === 'install') {
|
|
|
320
358
|
child.on('exit', code => process.exit(code ?? 0))
|
|
321
359
|
} else {
|
|
322
360
|
console.error(`알 수 없는 명령: ${command}`)
|
|
323
|
-
console.error('사용법: npx @elyun/bylane [install|loop|monitor|preflight|state|memory|cleanup] [--symlink]')
|
|
361
|
+
console.error('사용법: npx @elyun/bylane [install|uninstall|loop|monitor|preflight|state|memory|cleanup] [--symlink]')
|
|
324
362
|
process.exit(1)
|
|
325
363
|
}
|
package/src/config.js
CHANGED
|
@@ -67,6 +67,7 @@ export const DEFAULT_CONFIG = {
|
|
|
67
67
|
language: 'ko',
|
|
68
68
|
includeModel: true,
|
|
69
69
|
includeCodeExample: true,
|
|
70
|
+
autoApprove: false,
|
|
70
71
|
templateFile: '',
|
|
71
72
|
severityEmoji: {
|
|
72
73
|
CRITICAL: '[CRITICAL]',
|
|
@@ -74,7 +75,7 @@ export const DEFAULT_CONFIG = {
|
|
|
74
75
|
MEDIUM: '[MEDIUM]',
|
|
75
76
|
LOW: '[LOW]'
|
|
76
77
|
},
|
|
77
|
-
footer: '
|
|
78
|
+
footer: '🤖 {model} · {date}'
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|