3 Commits

Author SHA1 Message Date
e4f8e6ef53 revert(bridge): discord.js 봇 전면 제거 — OpenClaw 가 봇 소유자
이전 커밋 08ea92f 은 잘못된 접근이었음. OpenClaw 가 이미 Discord 게이트웨이를
띄우고 있고 자매들의 봇 identity 는 거기 하나로 통일되어야 함. rails 가
discord.js 로 별도 봇을 등록하면 두 봇이 같은 채널에 공존하는 기이한 구조가
된다.

올바른 경로는 OpenClaw skill 의 user-invocable frontmatter 로 슬래시 커맨드를
노출하는 것이고, 이건 별도 커밋으로 ~/.openclaw/skills/hanarang-rails/ 에
반영됨.

삭제:
- src/bridge/ 전체 (discord-client, discord-commands, discord-notifier, index)
- tests/discord-notifier.test.ts
- package.json 의 discord.js 의존성
- src/cli/serve.ts 의 bridge 부트스트랩
- .env.example 의 DISCORD_* 블록

보존:
- runner.ts 의 PipelineLifecycleEvent + onEvent 훅 — 유닛 테스트/대시보드
  WebSocket 등에 재사용 가능
- POST /pipelines/start-async 엔드포인트 — skill 의 polling wrapper 가 이걸 씀
- runner opts.pipelineId 지원 — async start 가 의존함
- http.ts ServerOpts 의 onPipelineEvent/notifier 파라미터 — 추상화는 유지,
  serve.ts 가 주입을 안 할 뿐

테스트: 118 → 111 (discord-notifier 7 개 삭제), 나머지 그대로 통과.
2026-04-10 22:35:24 +09:00
08ea92f540 feat(bridge): Discord 봇 — 슬래시 커맨드 트리거 + 실시간 알림
v0.1.4 — 옵션 3 (outbound + inbound). DISCORD_TOKEN 이 설정되지 않으면
bridge 는 no-op 이라 기존 배포는 영향 없음.

## Outbound (rails → Discord)

- runner.ts: PipelineLifecycleEvent emitter 추가
    started / stage-done / stage-failed / completed / failed / escalated
- DiscordNotifier: 이벤트 → Discord 메시지 렌더링
    thread mode (슬래시 커맨드 트리거) vs channel mode (CLI/HTTP 트리거)
- EscalationNotifier 인터페이스도 구현 — escalate.ts 에서 사용자에게 알림
- runPipeline opts 에 onEvent + notifier 주입

## Inbound (Discord → rails)

- /rails start project:<name> requirements:<text> — 파이프라인 기동
    → defer reply → POST /pipelines/start-async → thread 생성 → 실시간 업데이트
- /rails status <id> — 상태 조회 (ephemeral)
- /rails abort <id> — 강제 종료 (ephemeral)

## Async start 엔드포인트

- POST /pipelines/start-async: pipelineId 즉시 리턴 후 background 에서
  runPipeline 실행. Discord 의 3초 ACK 타임아웃을 회피.
- runPipeline 에 opts.pipelineId 지원: async 엔드포인트가 미리 만든
  row 위에 파이프라인을 그대로 얹을 수 있게.

## 부트스트랩

- rails serve 가 DISCORD_TOKEN/GUILD_ID/NOTIFY_CHANNEL_ID 세 개가 모두
  있으면 DiscordBridge 를 자동 시작. 없으면 "skip" 로그 남기고 무시.
- discord.js ^14.26 의존성 추가.

## 문서/테스트

- .env.example: Discord 섹션 전면 재작성 (동작 설명 포함)
- tests/discord-notifier.test.ts (7 tests): fake DiscordClientWrapper 로
  라우팅/렌더링/바인딩 해제 로직 검증
- 총 111 → 118 테스트 통과
2026-04-10 22:13:26 +09:00
0af4bbc685 feat(sprint-001): XState FSM + Prisma + CLI 뼈대 — 결정론적 파이프라인 코어
Sprint 001 전체 구현:

Foundation:
- package.json (pnpm + Node 22 + TypeScript strict)
- tsconfig.json (strict + noUncheckedIndexedAccess)
- .env.example (DATABASE_URL, DISCORD_TOKEN, etc.)
- vitest.config.ts

Core:
- src/env.ts — Zod 환경변수 검증
- src/logger.ts — pino 구조화 로거
- src/orchestrator/events.ts — Zod discriminated union 이벤트 스키마
- src/orchestrator/context.ts — PipelineContext 타입 + 팩토리
- src/orchestrator/machine.ts — XState v5 결정론적 FSM
  States: idle → planning → implementing → reviewing → deploying → done
  + retrying (exponential backoff 준비) + escalated + aborted
- src/orchestrator/persist.ts — Prisma 기반 상태 영속화
- prisma/schema.prisma — MariaDB 스키마 (pipelines, state_transitions, actor_spawns, contracts)

CLI (citty):
- rails start <project> — 파이프라인 생성
- rails status [id] — 상태 조회 + 타임라인
- rails serve — 오케스트레이터 서버 (Sprint 004 에서 완성)

Tests (9/9 pass):
- happy path (idle → done)
- REQUEST_CHANGES 재작업 루프 + max review round escalation
- retryable/non-retryable 에러 분기
- RESUME / ABORT
- context 추적

검증: pnpm tsc --noEmit ✓ | pnpm vitest run 9/9 ✓ | pnpm build ✓ | rails --help ✓

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:46:13 +09:00