@elyun/bylane 1.28.0 → 1.30.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 +18 -0
- package/commands/bylane-issue-agent.md +46 -1
- package/commands/bylane-setup.md +23 -5
- package/package.json +1 -1
- package/src/cli.js +43 -5
- package/src/config.js +4 -0
|
@@ -30,9 +30,27 @@ npx @elyun/bylane state write code-agent '{"status":"in_progress","startedAt":"'
|
|
|
30
30
|
| `spec.figmaSpec` | Figma 컬러토큰·컴포넌트 구조 |
|
|
31
31
|
| `issueType` | `new-feature` / `bug` / `improvement` / `chore` |
|
|
32
32
|
| `issueNumber` | GitHub 이슈 번호 |
|
|
33
|
+
| `branchName` | issue-agent가 생성한 브랜치명 |
|
|
34
|
+
| `worktreePath` | 워크트리 경로 (없으면 `null`) |
|
|
33
35
|
|
|
34
36
|
없으면 GitHub 이슈 본문을 직접 로드하여 파싱한다.
|
|
35
37
|
|
|
38
|
+
### 브랜치/워크트리 확인
|
|
39
|
+
|
|
40
|
+
issue-agent가 이미 브랜치를 생성했는지 확인한다:
|
|
41
|
+
|
|
42
|
+
1. `branchName`이 있으면 → 해당 브랜치로 checkout
|
|
43
|
+
2. `worktreePath`가 있으면 → 해당 워크트리 디렉토리에서 작업
|
|
44
|
+
3. 둘 다 없으면 (`issue.autoCreateBranch: false`) → code-agent가 직접 브랜치 생성
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# branchName이 있는 경우
|
|
48
|
+
git checkout "$BRANCH_NAME"
|
|
49
|
+
|
|
50
|
+
# worktreePath가 있는 경우 — 해당 디렉토리에서 모든 작업 수행
|
|
51
|
+
cd "$WORKTREE_PATH"
|
|
52
|
+
```
|
|
53
|
+
|
|
36
54
|
issueMemory 로드:
|
|
37
55
|
```bash
|
|
38
56
|
npx @elyun/bylane memory read ISSUE_NUMBER
|
|
@@ -211,6 +211,49 @@ curl -s -X POST \
|
|
|
211
211
|
|
|
212
212
|
---
|
|
213
213
|
|
|
214
|
+
### Phase 5 — 브랜치/워크트리 생성 (설정에 따라)
|
|
215
|
+
|
|
216
|
+
이슈 생성 직후, `issue.autoCreateBranch`가 `true`이면 브랜치를 자동 생성한다.
|
|
217
|
+
브랜치명은 `branch.pattern` 설정에 따라 결정된다.
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# 브랜치명 생성 (src/branch.js 활용)
|
|
221
|
+
BRANCH_NAME=$(node -e "
|
|
222
|
+
import('./src/branch.js').then(({buildBranchNameFromConfig}) => {
|
|
223
|
+
import('./src/config.js').then(({loadConfig}) => {
|
|
224
|
+
const config = loadConfig()
|
|
225
|
+
const name = buildBranchNameFromConfig(config, {
|
|
226
|
+
issueNumber: ISSUE_NUMBER,
|
|
227
|
+
type: 'ISSUE_TYPE',
|
|
228
|
+
title: 'ISSUE_TITLE'
|
|
229
|
+
})
|
|
230
|
+
process.stdout.write(name)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
")
|
|
234
|
+
|
|
235
|
+
git checkout -b "$BRANCH_NAME"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### 워크트리 생성 (`issue.autoCreateWorktree: true`인 경우)
|
|
239
|
+
|
|
240
|
+
브랜치 대신 워크트리를 생성하여 독립된 작업 디렉토리를 만든다:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
WORKTREE_DIR=".bylane/worktrees/$BRANCH_NAME"
|
|
244
|
+
git worktree add "$WORKTREE_DIR" -b "$BRANCH_NAME"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
이후 모든 에이전트(code-agent, test-agent, commit-agent 등)는 이 워크트리 경로에서 작업한다.
|
|
248
|
+
state에 `branchName`과 `worktreePath`를 기록하여 후속 에이전트가 참조할 수 있게 한다.
|
|
249
|
+
|
|
250
|
+
#### 설정이 꺼져 있는 경우
|
|
251
|
+
|
|
252
|
+
`issue.autoCreateBranch: false`이면 이 단계를 건너뛴다.
|
|
253
|
+
code-agent가 실행 시점에 브랜치를 직접 생성한다.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
214
257
|
## 출력
|
|
215
258
|
|
|
216
259
|
`.bylane/state/issue-agent.json`:
|
|
@@ -230,7 +273,9 @@ curl -s -X POST \
|
|
|
230
273
|
"affectedFiles": ["src/hooks/useTheme.ts", "src/components/Header/"],
|
|
231
274
|
"checklist": ["ThemeToggle 컴포넌트 생성", "useTheme hook 수정", "테스트 작성"],
|
|
232
275
|
"figmaSpec": { "enabled": false, "components": [], "colorTokens": {} }
|
|
233
|
-
}
|
|
276
|
+
},
|
|
277
|
+
"branchName": "issues-123-dark-mode-toggle",
|
|
278
|
+
"worktreePath": null
|
|
234
279
|
}
|
|
235
280
|
```
|
|
236
281
|
|
package/commands/bylane-setup.md
CHANGED
|
@@ -83,7 +83,25 @@ Linear API Key는 환경변수명(`LINEAR_API_KEY`)으로 저장. 실제 키값
|
|
|
83
83
|
|
|
84
84
|
`permissions.scope`에 저장.
|
|
85
85
|
|
|
86
|
-
## Step 5/
|
|
86
|
+
## Step 5/10 — 이슈 생성 시 브랜치/워크트리
|
|
87
|
+
|
|
88
|
+
> 이슈 생성 후 자동으로 브랜치를 만들까요? (y/n, 기본: y)
|
|
89
|
+
|
|
90
|
+
- `y` (기본) → `issue.autoCreateBranch = true` — 이슈 생성 직후 브랜치 네이밍 패턴에 따라 브랜치 자동 생성
|
|
91
|
+
- `n` → `issue.autoCreateBranch = false` — code-agent 실행 시 수동 생성
|
|
92
|
+
|
|
93
|
+
`y` 선택 시 추가 질문:
|
|
94
|
+
|
|
95
|
+
> 브랜치와 함께 git worktree도 생성할까요? (y/n, 기본: n)
|
|
96
|
+
> worktree를 사용하면 이슈별로 독립된 작업 디렉토리가 생성됩니다.
|
|
97
|
+
> 여러 이슈를 동시에 작업할 때 유용합니다.
|
|
98
|
+
|
|
99
|
+
- `y` → `issue.autoCreateWorktree = true` — `.bylane/worktrees/{branch-name}/`에 워크트리 생성
|
|
100
|
+
- `n` (기본) → `issue.autoCreateWorktree = false` — 브랜치만 생성하고 checkout
|
|
101
|
+
|
|
102
|
+
모든 후속 에이전트(code-agent, test-agent, commit-agent 등)는 이슈 번호 기준으로 해당 브랜치/워크트리에서 작업한다.
|
|
103
|
+
|
|
104
|
+
## Step 6/10 — 리뷰 자동 Approve
|
|
87
105
|
|
|
88
106
|
> AI 리뷰에서 지적사항이 없을 때 자동으로 Approve할까요? (y/n, 기본: n)
|
|
89
107
|
|
|
@@ -92,7 +110,7 @@ Linear API Key는 환경변수명(`LINEAR_API_KEY`)으로 저장. 실제 키값
|
|
|
92
110
|
|
|
93
111
|
대부분의 팀에서는 사람이 최종 Approve하는 것을 권장한다.
|
|
94
112
|
|
|
95
|
-
## Step
|
|
113
|
+
## Step 7/10 — Loop 실행 모드
|
|
96
114
|
|
|
97
115
|
> Loop 실행 모드를 선택하세요:
|
|
98
116
|
> 1. tmux — tmux 세션에서 백그라운드 실행 (터미널 종료 후에도 유지, 권장)
|
|
@@ -117,7 +135,7 @@ bylane loop stop # loop 종료
|
|
|
117
135
|
bylane loop status # 상태 확인
|
|
118
136
|
```
|
|
119
137
|
|
|
120
|
-
## Step
|
|
138
|
+
## Step 8/10 — 고급 설정
|
|
121
139
|
|
|
122
140
|
> 고급 설정을 변경하시겠습니까? (Enter = 기본값 사용)
|
|
123
141
|
|
|
@@ -126,7 +144,7 @@ bylane loop status # 상태 확인
|
|
|
126
144
|
- `loopTimeoutMinutes` (기본: 30): 루프 타임아웃 (분)
|
|
127
145
|
- Figma MCP 활성화? (y/n, 기본: n)
|
|
128
146
|
|
|
129
|
-
## Step
|
|
147
|
+
## Step 9/10 — 브랜치 네이밍
|
|
130
148
|
|
|
131
149
|
> 브랜치 네이밍 패턴을 선택하세요:
|
|
132
150
|
> 1. {tracker}-{issue-number} 예) issues-32
|
|
@@ -141,7 +159,7 @@ bylane loop status # 상태 확인
|
|
|
141
159
|
직접 입력 시 사용 가능한 토큰 목록 안내:
|
|
142
160
|
`{tracker}`, `{type}`, `{issue-number}`, `{custom-id}`, `{title-slug}`, `{date}`, `{username}`
|
|
143
161
|
|
|
144
|
-
## Step
|
|
162
|
+
## Step 10/10 — 에이전트 모델 설정
|
|
145
163
|
|
|
146
164
|
> 각 에이전트에 사용할 AI 모델을 설정하시겠습니까? (Enter = 기본값 사용)
|
|
147
165
|
|
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
|
}
|