@elyun/bylane 1.34.0 → 1.37.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.
@@ -217,6 +217,28 @@ npx @elyun/bylane state write code-agent '{
217
217
 
218
218
  ---
219
219
 
220
+ ## Slack 완료 알림
221
+
222
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
223
+
224
+ ```bash
225
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
226
+
227
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
228
+ -H "Content-Type: application/json" \
229
+ -d "{
230
+ \"title\": \"[code-agent] #ISSUE_NUMBER 구현 완료\",
231
+ \"status\": \"completed\",
232
+ \"url\": \"ISSUE_URL\",
233
+ \"elapsed\": \"ELAPSED\",
234
+ \"reason\": \"\"
235
+ }"
236
+ ```
237
+
238
+ `ISSUE_URL`은 `.bylane/state/issue-agent.json`의 `issueUrl`.
239
+
240
+ ---
241
+
220
242
  ## issueMemory 기록
221
243
 
222
244
  ```bash
@@ -66,6 +66,26 @@ ls .gitmessage .github/commit-template.txt .github/COMMIT_TEMPLATE.md 2>/dev/nul
66
66
  npx @elyun/bylane state write commit-agent '{"status":"completed","progress":100,"branchName":"BRANCH_NAME","commitSha":"COMMIT_SHA"}'
67
67
  ```
68
68
 
69
+ ## Slack 완료 알림
70
+
71
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
72
+
73
+ ```bash
74
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
75
+
76
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
77
+ -H "Content-Type: application/json" \
78
+ -d "{
79
+ \"title\": \"[commit-agent] 커밋 완료 (BRANCH_NAME)\",
80
+ \"status\": \"completed\",
81
+ \"url\": \"\",
82
+ \"elapsed\": \"ELAPSED\",
83
+ \"reason\": \"\"
84
+ }"
85
+ ```
86
+
87
+ ---
88
+
69
89
  ## 출력
70
90
 
71
91
  `.bylane/state/commit-agent.json`:
@@ -296,6 +296,28 @@ npx @elyun/bylane memory append ISSUE_NUMBER issue-agent "유형: ISSUE_TYPE
296
296
 
297
297
  ---
298
298
 
299
+ ## Slack 완료 알림
300
+
301
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
302
+
303
+ ```bash
304
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
305
+
306
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
307
+ -H "Content-Type: application/json" \
308
+ -d "{
309
+ \"title\": \"[issue-agent] #ISSUE_NUMBER SPEC_TITLE\",
310
+ \"status\": \"completed\",
311
+ \"url\": \"ISSUE_URL\",
312
+ \"elapsed\": \"ELAPSED\",
313
+ \"reason\": \"\"
314
+ }"
315
+ ```
316
+
317
+ `ELAPSED`는 `startedAt`부터 현재까지의 소요 시간(예: `1m 23s`).
318
+
319
+ ---
320
+
299
321
  ## 수동 실행
300
322
 
301
323
  `/bylane issue #123` 또는 `/bylane issue 다크모드 토글 추가해줘`
@@ -93,6 +93,26 @@ npx @elyun/bylane state write pr-agent '{"status":"in_progress","startedAt":"'$(
93
93
  npx @elyun/bylane state write pr-agent '{"status":"completed","progress":100,"prNumber":PR_NUMBER,"prUrl":"PR_URL"}'
94
94
  ```
95
95
 
96
+ ## Slack 완료 알림
97
+
98
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
99
+
100
+ ```bash
101
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
102
+
103
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
104
+ -H "Content-Type: application/json" \
105
+ -d "{
106
+ \"title\": \"[pr-agent] PR #PR_NUMBER 생성\",
107
+ \"status\": \"completed\",
108
+ \"url\": \"PR_URL\",
109
+ \"elapsed\": \"ELAPSED\",
110
+ \"reason\": \"\"
111
+ }"
112
+ ```
113
+
114
+ ---
115
+
96
116
  ## 출력
97
117
 
98
118
  `.bylane/state/pr-agent.json`:
@@ -129,6 +129,26 @@ curl -s \
129
129
  }
130
130
  ```
131
131
 
132
+ ## Slack 완료 알림
133
+
134
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
135
+
136
+ ```bash
137
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
138
+
139
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
140
+ -H "Content-Type: application/json" \
141
+ -d "{
142
+ \"title\": \"[respond-agent] PR #PR_NUMBER 리뷰 대응 완료 (RESOLVED_COUNT건)\",
143
+ \"status\": \"completed\",
144
+ \"url\": \"PR_URL\",
145
+ \"elapsed\": \"ELAPSED\",
146
+ \"reason\": \"\"
147
+ }"
148
+ ```
149
+
150
+ ---
151
+
132
152
  ## 수동 실행
133
153
 
134
154
  `/bylane respond #45`
@@ -200,6 +200,26 @@ curl -s -X POST \
200
200
  npx @elyun/bylane state write review-agent '{"status":"completed","progress":100,"approved":APPROVED_BOOL,"commentCount":COMMENT_COUNT}'
201
201
  ```
202
202
 
203
+ ## Slack 완료 알림
204
+
205
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
206
+
207
+ ```bash
208
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
209
+
210
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
211
+ -H "Content-Type: application/json" \
212
+ -d "{
213
+ \"title\": \"[review-agent] PR #PR_NUMBER 리뷰 완료 (COMMENT_COUNT건)\",
214
+ \"status\": \"completed\",
215
+ \"url\": \"PR_URL\",
216
+ \"elapsed\": \"ELAPSED\",
217
+ \"reason\": \"\"
218
+ }"
219
+ ```
220
+
221
+ ---
222
+
203
223
  ## 출력
204
224
 
205
225
  `.bylane/state/review-agent.json`:
@@ -58,6 +58,38 @@ npx @elyun/bylane state write test-agent '{"status":"in_progress","startedAt":"'
58
58
  }
59
59
  ```
60
60
 
61
+ ## Slack 완료 알림
62
+
63
+ `.bylane/bylane.json`의 `notifications.slack.enabled: true`이고 `webhookUrl`이 있으면 전송:
64
+
65
+ ```bash
66
+ SLACK_WEBHOOK_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.bylane/bylane.json','utf8'));const s=c.notifications?.slack;process.stdout.write(s?.enabled&&s?.webhookUrl?s.webhookUrl:'')}catch(e){}" 2>/dev/null)
67
+
68
+ # 통과 시
69
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
70
+ -H "Content-Type: application/json" \
71
+ -d "{
72
+ \"title\": \"[test-agent] 테스트 통과 (PASSED/TOTAL)\",
73
+ \"status\": \"completed\",
74
+ \"url\": \"\",
75
+ \"elapsed\": \"ELAPSED\",
76
+ \"reason\": \"\"
77
+ }"
78
+
79
+ # 실패 시 — status를 escalated로
80
+ [ -n "$SLACK_WEBHOOK_URL" ] && curl -s -X POST "$SLACK_WEBHOOK_URL" \
81
+ -H "Content-Type: application/json" \
82
+ -d "{
83
+ \"title\": \"[test-agent] 테스트 실패 (FAILED/TOTAL)\",
84
+ \"status\": \"escalated\",
85
+ \"url\": \"\",
86
+ \"elapsed\": \"\",
87
+ \"reason\": \"FAILURE_SUMMARY\"
88
+ }"
89
+ ```
90
+
91
+ ---
92
+
61
93
  ## 수동 실행
62
94
 
63
95
  `/bylane test`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elyun/bylane",
3
- "version": "1.34.0",
3
+ "version": "1.37.0",
4
4
  "description": "Frontend development harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -286,14 +286,14 @@ if (command === 'install') {
286
286
  const mode = resolveLoopMode()
287
287
 
288
288
  if (mode === 'tmux') {
289
- startTmuxLoops(sessionName)
289
+ startTmuxLoops(sessionName, { packageRoot: ROOT, projectDir: process.cwd() })
290
290
  console.log(`\n tmux 세션에 접속하려면: tmux attach -t ${sessionName}\n`)
291
291
  } else {
292
292
  // process 모드: 현재 프로세스에서 직접 실행
293
293
  console.log('\n process 모드: review-loop + respond-loop 실행\n')
294
294
  const { spawn } = await import('child_process')
295
- const review = spawn(process.execPath, ['src/review-loop.js'], { stdio: 'inherit', detached: false })
296
- const respond = spawn(process.execPath, ['src/respond-loop.js'], { stdio: 'inherit', detached: false })
295
+ const review = spawn(process.execPath, [join(ROOT, 'src', 'review-loop.js')], { stdio: 'inherit', detached: false, cwd: process.cwd() })
296
+ const respond = spawn(process.execPath, [join(ROOT, 'src', 'respond-loop.js')], { stdio: 'inherit', detached: false, cwd: process.cwd() })
297
297
 
298
298
  function shutdownAll() {
299
299
  review.kill('SIGTERM')
package/src/loop-utils.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * 루프 프로세스 공통 유틸
4
4
  */
5
5
  import { execSync } from 'child_process'
6
+ import { join } from 'path'
6
7
  import { readState, writeState } from './state.js'
7
8
  import { loadConfig } from './config.js'
8
9
 
@@ -152,22 +153,34 @@ export function verifyTmuxLoops(sessionName = 'bylane-loops', stateDir = '.bylan
152
153
  /**
153
154
  * tmux 세션에서 review-loop + respond-loop을 실행
154
155
  * @param {string} sessionName
155
- * @param {string} stateDir
156
+ * @param {object} opts
157
+ * @param {string} [opts.stateDir] 상태 디렉토리 (상대경로)
158
+ * @param {string} [opts.packageRoot] 패키지 루트 경로 (스크립트 절대경로 해석용)
159
+ * @param {string} [opts.projectDir] 프로젝트 디렉토리 (tmux CWD, .bylane/ 기준)
156
160
  */
157
- export function startTmuxLoops(sessionName = 'bylane-loops', stateDir = '.bylane/state') {
161
+ export function startTmuxLoops(sessionName = 'bylane-loops', opts = {}) {
162
+ const {
163
+ stateDir = '.bylane/state',
164
+ packageRoot = process.cwd(),
165
+ projectDir = process.cwd()
166
+ } = typeof opts === 'string' ? { stateDir: opts } : opts
167
+
158
168
  if (isTmuxSessionAlive(sessionName)) {
159
169
  console.log(`[tmux] 세션 '${sessionName}'이 이미 실행 중입니다.`)
160
170
  return { started: false, reason: 'already_running' }
161
171
  }
162
172
 
163
- // 번째 윈도우: review-loop
173
+ const reviewScript = join(packageRoot, 'src', 'review-loop.js')
174
+ const respondScript = join(packageRoot, 'src', 'respond-loop.js')
175
+
176
+ // 첫 번째 윈도우: review-loop (-c 로 프로젝트 디렉토리에서 실행)
164
177
  execSync(
165
- `tmux new-session -d -s ${sessionName} -n review 'node src/review-loop.js'`,
178
+ `tmux new-session -d -s ${sessionName} -n review -c '${projectDir}' 'node ${reviewScript}'`,
166
179
  { stdio: 'inherit' }
167
180
  )
168
181
  // 두 번째 윈도우: respond-loop
169
182
  execSync(
170
- `tmux new-window -t ${sessionName} -n respond 'node src/respond-loop.js'`,
183
+ `tmux new-window -t ${sessionName} -n respond -c '${projectDir}' 'node ${respondScript}'`,
171
184
  { stdio: 'inherit' }
172
185
  )
173
186