From bef68bab2266a56cb2d468a060bd9793cda99675 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:10:18 +0000 Subject: [PATCH 1/2] Initial plan From 66bd1d4713b1a1ba9fe2867f11c8f77aedfba80a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:14:43 +0000 Subject: [PATCH 2/2] docs: add onboarding docs and setup scripts (fix missing files from #6) Co-authored-by: redsunjin <17919877+redsunjin@users.noreply.github.com> --- .env.example | 15 ++ README.md | 411 ++++-------------------------------------- USER_GUIDE.md | 94 ++++++++++ docs/PLAN.md | 380 ++++++++++++++++++++++++++++++++++++++ package.json | 6 +- scripts/configure.js | 62 +++++++ scripts/setup_env.ps1 | 25 +++ scripts/setup_env.sh | 28 +++ 8 files changed, 648 insertions(+), 373 deletions(-) create mode 100644 .env.example create mode 100644 USER_GUIDE.md create mode 100644 docs/PLAN.md create mode 100644 scripts/configure.js create mode 100644 scripts/setup_env.ps1 create mode 100755 scripts/setup_env.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7f57ca3 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# .env.example — 환경변수 설정 예시 +# 이 파일을 복사하여 .env 로 이름을 변경하고 실제 값을 입력하세요. +# .env 파일은 절대 커밋하지 마세요. + +# 병합을 수행할 메인 레포지토리의 로컬 절대 경로 (필수) +MAIN_REPO_PATH=/path/to/your/main/repo + +# 서버 리스닝 포트 (선택, 기본값: 8080) +PORT=8080 + +# 프론트엔드가 연결할 WebSocket 주소 (선택, 기본값: ws://localhost:8080) +VITE_WS_URL=ws://localhost:8080 + +# API 인증 토큰 (선택, 설정 시 /api/request 에 Bearer 인증 활성화) +MAESTRO_SERVER_TOKEN=your-secret-token-here diff --git a/README.md b/README.md index 89991ad..f3261c0 100644 --- a/README.md +++ b/README.md @@ -1,373 +1,42 @@ # Maestro Coding -

- - Demo - -

- -## 🎼 '마에스트로 코딩(Maestro Coding)' - -### 1. 핵심 메시지 (Core Message) - -* **Before:** 여러 에이전트와 창을 띄워놓고 쏟아지는 PR과 커밋 알림에 쫓기며 클릭질하는 스트레스 넘치는 개발자. -* **After:** 바흐의 선율 속에서, 투명하게 오버레이된 건반형 대시보드를 통해 리드미컬하게 다수의 에이전트를 지휘하는 우아한 개발자. -* **Slogan:** "코딩을 지휘하다, AI 에이전트와 함께하는 코드 심포니." - -### 2. 단계별 콘텐츠 전개 전략 - -#### Phase 1: 시각적 쾌감을 극대화한 숏폼 (YouTube Shorts / Reels) - -바흐의 음악과 UI의 타격감을 동기화하여 개발자들의 로망을 자극하는 30~60초 분량의 영상입니다. - -* **오디오:** 바흐의 인벤션(Invention)이나 평균율 클라비어 곡집처럼 규칙적이고 경쾌한 피아노/하프시코드 연주곡. -* **화면 구성 (분할 화면):** - * **상단/배경:** 다크 모드의 세련된 개발 환경. 투명한 '건반형 대시보드' 위로 에이전트들의 코드 리뷰 요청(Diff 요약본)이 위에서 아래로 리듬 게임의 노트처럼 떨어집니다. - * **하단/실사:** 여유롭게 커피를 마시며, 키보드 특정 키(예: A, S, D, F)를 음악 비트에 맞춰 가볍게 탭(Tap)하는 손. - - -* **포인트:** 키를 누를 때마다 화면의 코드 노드가 경쾌한 파동을 일으키며 'Merged(승인)' 상태로 변하고, 브랜치들이 메인 트리에 깔끔하게 합쳐지는 애니메이션을 연출합니다. - -#### Phase 2: 기술 블로그 아티클 (The Architecture of Flow) - -영상을 보고 "저거 어떻게 세팅한 거지?"라고 궁금해할 개발자들을 위한 딥다이브 콘텐츠입니다. - -* **주제:** Git Worktree와 다중 AI 에이전트를 활용한 병렬 개발 워크플로우 구축기. -* **내용:** - * 왜 디렉토리를 복사하지 않고 Git Worktree를 사용하여 여러 에이전트를 독립적으로 띄웠는지에 대한 기술적 이점 설명. - * 에이전트들의 승인 대기 상태를 가로채서(Intercept) 하나의 중앙 대시보드(건반 패널)로 모으는 이벤트 루프 아키텍처. - * 알림의 파편화를 막고 컨텍스트 스위칭을 최소화한 UX 설계 철학. - - - -#### Phase 3: 인터랙티브 웹 데모 및 오픈소스/컴포넌트 공개 - -단순한 영상 콘텐츠로 끝내는 것이 아니라, 직접 경험해 볼 수 있는 미니 데모를 제공하여 기술력을 증명합니다. - -* 웹 브라우저에서 바흐 음악과 함께 가짜(Mock) 에이전트 커밋들이 내려오고, 사용자가 직접 키보드로 승인해 보는 리듬 게임 형태의 랜딩 페이지 제작. -* 이 '건반형 승인 대시보드'를 AI 보조 코딩을 위해 설계된 전체 풀스택 프레임워크 내에서 언제든 꺼내 쓸 수 있는 핵심 **재사용 UI/UX 컴포넌트**로 패키징하여 소개합니다. - ---- - -## 🔌 `maestro-server.js` 동작 원리 - -프론트엔드 데모만으로는 실제 에이전트 승인 요청을 받을 수 없습니다. -`maestro-server.js`는 **에이전트 ↔ 대시보드** 사이를 연결하는 경량 Node.js 서버입니다. - -### 전체 아키텍처 흐름 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ Maestro 시스템 전체 흐름 │ -│ │ -│ AI 에이전트 │ -│ (Codex / Claude / │ -│ 터미널 스크립트 등) │ -│ │ │ -│ │ ① 작업 완료 후 │ -│ │ POST /api/request │ -│ ▼ │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ maestro-server.js (포트 8080) │ │ -│ │ │ │ -│ │ HTTP 서버 WebSocket 서버 │ │ -│ │ ┌──────────────┐ ┌──────────────────┐ │ │ -│ │ │POST /api/req │──②──▶ │broadcast() │ │ │ -│ │ │GET /health │ │AGENT_TASK_READY │ │ │ -│ │ └──────────────┘ └────────┬─────────┘ │ │ -│ │ │ │ │ -│ │ Git 실행 (execFile) ◀──⑤────── │ │ │ -│ │ git merge / reset │ │ │ -│ └───────────────────────────────────┼─────────────┘ │ -│ │ ③ WebSocket │ -│ ▼ ws://localhost:8080 │ -│ ┌────────────────────────┐ │ -│ │ 브라우저 대시보드 │ │ -│ │ (React / App.jsx) │ │ -│ │ │ │ -│ │ 노트가 레인으로 떨어짐 🎵 │ │ -│ │ │ │ -│ │ 키보드 D/F/J/K 입력 ④ │ │ -│ └────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -### 단계별 이벤트 흐름 - -| 단계 | 주체 | 동작 | -|------|------|------| -| ① | AI 에이전트 | 작업(커밋) 완료 후 `POST /api/request` 로 승인 요청 전송 | -| ② | 서버 | JSON 파싱 → `AGENT_TASK_READY` 이벤트를 연결된 모든 대시보드로 브로드캐스트 | -| ③ | 대시보드 | WebSocket 메시지 수신 → 해당 레인에 노트(음표)가 화면 위에서 아래로 낙하 | -| ④ | 사용자 | 키보드(`D` `F` `J` `K`)로 노트 승인 → `APPROVE` 이벤트를 서버로 전송 | -| ⑤ | 서버 | `git merge ` 실행 → 성공 시 `MERGE_SUCCESS` 응답 | - -> **`Ctrl+Z` 롤백 흐름:** 사용자가 `Ctrl+Z`를 누르면 `UNDO` 이벤트가 서버로 전송되고, 서버는 `git reset --hard HEAD~1`을 실행합니다. - ---- - -### 실행 방법 - -```bash -# 1. 의존성 설치 (ws 패키지 포함) -npm install - -# 2. 서버 시작 -npm run server -# 또는 -node maestro-server.js - -# 3. 프론트엔드 개발 서버 (별도 터미널) -npm run dev -``` - -서버가 시작되면 대시보드에서 "지휘 시작" 버튼을 눌렀을 때 자동으로 `ws://localhost:8080`에 연결을 시도합니다. -연결에 성공하면 헤더에 **🔴 LIVE** 배지가 표시됩니다. 연결 실패 시에는 자동으로 Mock 모드로 동작합니다. - -#### 환경 변수 - -| 변수 | 기본값 | 설명 | -|------|--------|------| -| `PORT` | `8080` | 서버 리스닝 포트 | -| `MAIN_REPO_PATH` | `process.cwd()` | `git merge`/`git reset` 을 실행할 메인 레포지토리 경로 | -| `VITE_WS_URL` | `ws://localhost:8080` | 프론트엔드가 연결할 WebSocket 주소 (`.env` 파일에 설정) | - -예시: -```bash -MAIN_REPO_PATH=/home/user/my-project PORT=9090 node maestro-server.js -``` - ---- - -### HTTP API 레퍼런스 - -#### `POST /api/request` — 에이전트 승인 요청 - -에이전트(또는 완료 훅 스크립트)가 작업 완료 시 이 엔드포인트로 요청을 보냅니다. - -**요청 본문 (`application/json`)** - -```json -{ - "requestId": "req_abc123", - "agentId": "agent_backend_01", - "branchName": "feature/jwt-optimization", - "projectId": "proj_b2c", - "laneIndex": 2, - "diffSummary": { - "title": "JWT 검증 로직 최적화", - "impact": "Medium", - "shortDescription": "auth.js 45-60 라인 수정. 예외 처리 추가." - } -} -``` - -| 필드 | 필수 | 설명 | -|------|------|------| -| `agentId` | 권장 | 에이전트 식별자 | -| `branchName` | 권장 | 실제 git merge 대상 브랜치 이름 | -| `projectId` | 선택 | 프론트엔드 탭 선택에 사용 (`proj_b2c`, `proj_admin`, `proj_api`) | -| `laneIndex` | 선택 | UI 레인 번호 1~4. 생략 시 서버가 랜덤 배정 | -| `diffSummary` | 선택 | 생략 시 `title` / `description` 최상위 필드를 대체 사용 | - -**curl 예시** - -```bash -curl -X POST http://localhost:8080/api/request \ - -H 'Content-Type: application/json' \ - -d '{ - "agentId": "my_agent", - "branchName": "feature/my-branch", - "laneIndex": 1, - "diffSummary": { - "title": "작업 완료", - "shortDescription": "변경 내용 요약" - } - }' -``` - -**응답** - -```json -{ "success": true, "requestId": "req_1748392839201" } -``` - -#### `GET /health` — 서버 상태 확인 - -```bash -curl http://localhost:8080/health -# {"status":"ok","clients":1} -``` - ---- - -### WebSocket 이벤트 목록 - -#### 서버 → 대시보드 (수신 이벤트) - -| 이벤트 | 설명 | -|--------|------| -| `AGENT_TASK_READY` | 에이전트 승인 요청. 이 이벤트의 페이로드가 노트(음표)로 화면에 표시됩니다. | -| `MERGE_SUCCESS` | `git merge` 성공. 노트가 화면에서 사라집니다. | -| `MERGE_FAILED` | `git merge` 실패. 서버 로그를 확인하세요. | -| `UNDO_SUCCESS` | `git reset --hard HEAD~1` 성공. | -| `UNDO_FAILED` | 롤백 실패. | -| `AGENT_RESTARTED` | 반려(REJECT) 처리 완료 확인. | - -#### 대시보드 → 서버 (송신 이벤트) - -| 액션 | 설명 | -|------|------| -| `APPROVE` | 노트 승인. `branchName`이 있으면 `git merge` 실행. | -| `REJECT` | 노트 반려. `feedback` 필드로 에이전트에 수정 지시 전달 가능. | -| `UNDO` | 직전 병합 롤백 (`git reset --hard HEAD~1`). | - ---- - -## 🤖 실제 AI 개발툴과 연동하기 - -> **"API 통해서 네트워크 타고 갔다 오는 게 맞나요? 실제 개발툴하고 통신이 되는 건가요?"** -> **네, 맞습니다.** `localhost:8080`을 통한 진짜 HTTP/WebSocket 통신입니다. -> AI 도구가 작업을 마치는 순간, 실제로 승인 요청이 대시보드에 날아옵니다. - -### 전체 통신 흐름 (네트워크 레벨) - -``` -[AI 개발툴 (Cursor / Claude Code / aider 등)] - │ - │ ① 작업 완료 → 훅 스크립트 실행 - │ hooks/notify-maestro.sh - │ - │ ② 진짜 HTTP POST 요청 (로컬호스트) - ▼ - POST http://localhost:8080/api/request - │ - │ ③ JSON 파싱 → WebSocket 브로드캐스트 - ▼ - ws://localhost:8080 ───────────────────▶ [브라우저 대시보드] - │ - 노트가 레인으로 떨어짐 🎵 - │ - D / F / J / K 키 입력 ④ - │ - ◀───────────────── WebSocket APPROVE ──────┘ - │ - │ ⑤ git merge - ▼ - 브랜치가 메인으로 실제 병합됩니다 ✅ -``` - -> **"로컬호스트니까 사실상 인터넷은 아니지 않나요?"** -> 맞습니다 — 같은 머신 안의 루프백(loopback) 통신입니다. 덕분에 외부 서버 없이, 인터넷 연결 없이도 동작합니다. -> 원격 에이전트(다른 PC, 클라우드 서버 등)가 필요하다면 ngrok 등으로 터널링하면 됩니다. - ---- - -### 방법 1 — Claude Code 훅 (가장 쉬움 ⭐) - -Claude Code는 에이전트가 작업을 마칠 때 자동으로 쉘 명령을 실행하는 **Stop 훅**을 지원합니다. - -**설정 방법 (프로젝트 루트에서):** - -```bash -# .claude 디렉토리가 없으면 생성 -mkdir -p .claude - -# 훅 설정 파일 복사 -cp hooks/claude-settings-example.json .claude/settings.json -``` - -**.claude/settings.json 내용:** - -```json -{ - "hooks": { - "Stop": [ - { - "matcher": "", - "hooks": [ - { - "type": "command", - "command": "sh hooks/notify-maestro.sh" - } - ] - } - ] - } -} -``` - -이후 Claude Code에서 작업이 완료될 때마다 **자동으로** 대시보드에 승인 요청이 나타납니다. - ---- - -### 방법 2 — 터미널에서 직접 호출 - -어떤 AI 도구든, 어떤 스크립트든 작업 완료 후 한 줄만 추가하면 됩니다: - -```bash -# 가장 간단한 형태 (브랜치·커밋 메시지 자동 감지) -sh hooks/notify-maestro.sh - -# 명시적으로 정보를 전달하는 형태 -sh hooks/notify-maestro.sh feature/auth "JWT 검증 로직 추가" "auth.js 45-60 수정" - -# 환경변수로 제어 -AGENT_ID=my_agent LANE_INDEX=2 sh hooks/notify-maestro.sh -``` - ---- - -### 방법 3 — aider, 기타 CLI 에이전트 래퍼 - -`aider`처럼 반복 실행되는 AI 에이전트라면 완료 후 훅을 래퍼 스크립트로 감쌀 수 있습니다: - -```bash -#!/bin/bash -# run-agent.sh — aider 실행 후 Maestro 에 알림 - -aider --model gpt-4o "$@" -EXIT_CODE=$? - -if [ $EXIT_CODE -eq 0 ]; then - sh hooks/notify-maestro.sh -fi -``` - ---- - -### 방법 4 — git post-commit 훅 - -커밋이 생성될 때마다 자동으로 승인 요청을 보내려면: - -```bash -# .git/hooks/post-commit 파일에 추가 -echo '#!/bin/sh' > .git/hooks/post-commit -echo 'sh "$(git rev-parse --show-toplevel)/hooks/notify-maestro.sh"' >> .git/hooks/post-commit -chmod +x .git/hooks/post-commit -``` - ---- - -### 실제 동작 확인 (30초 테스트) - -```bash -# 터미널 1: 서버 시작 -npm run server - -# 터미널 2: 브라우저에서 대시보드 열고 "지휘 시작" 클릭 -npm run dev - -# 터미널 3: 승인 요청 직접 발사 — 대시보드에 노트가 나타나는지 확인! -sh hooks/notify-maestro.sh feature/test-branch "테스트 커밋" "실제 통신 확인" -``` - -브라우저 대시보드에 노트가 나타나면, **실제 HTTP → WebSocket 통신**이 작동하는 것입니다. -이제 `D` `F` `J` `K` 키를 누르면 서버에서 `git merge` 가 실행됩니다. 🎼 - ---- - -### 3. 성공적인 연출을 위한 UX 디테일 - -* **Diff 하이라이트의 추상화:** 승인 화면에서 코드를 한 줄 한 줄 읽게 하면 리듬이 깨집니다. 에이전트가 "어떤 의도"로 "어느 로직"을 건드렸는지만 3줄 이내의 자연어나 미니 맵 형태로 보여주어 직관적인 판단을 돕습니다. -* **되감기(Undo) 기능:** 리듬에 맞춰 빠르게 승인하다 실수했을 때, 음악의 리와인드 효과음과 함께 방금 병합한 커밋을 취소하는 단축키(`Ctrl+Z` 등)를 지원하여 심리적 안정감을 제공합니다. +코딩을 지휘하다 — AI 에이전트와 함께하는 코드 심포니 🎼 + +## 컨셉(Concept) +Maestro는 AI 에이전트가 생성하거나 수정한 코드 변경을 "승인 노트" 형태로 제시하고, 사람이 빠르게 승인/반려하여 안전하게 병합하도록 돕는 개발 보조 도구입니다. + +## 만든 목적(Purpose) +- AI 에이전트 자동 생성 코드를 인간이 빠르게 확인하고 승인할 수 있도록 가시화 +- 승인(merge) 워크플로우를 단순화하여 생산성 향상 +- 로컬 개발 환경에서 안전하게 에이전트와 협업할 수 있는 도구 제공 + +## 주요 기능(At a glance) +- 에이전트가 POST /api/request 로 승인 요청 전송 +- Maestro 서버는 WebSocket으로 대시보드에 알림 브로드캐스트 +- 사용자가 대시보드에서 APPROVE/REJECT/UNDO 조작 가능 +- 승인 시 서버에서 로컬 git 병합(merge)을 수행 + +## 빠른 시작(Quick Start) +1. 레포지토리 클론 + git clone https://github.com/redsunjin/maestro-coding.git +2. 의존성 설치 (필요한 경우) + npm install +3. 설정 파일(.env) 준비 + - 루트에 `.env` 또는 환경변수로 설정. + - 예: `MAIN_REPO_PATH=/path/to/your/main/repo` +4. 서버 실행 + MAIN_REPO_PATH=/path/to/your/main/repo node maestro-server.js +5. 에이전트(또는 훅)에서 승인 요청 전송 (예시) + curl -X POST http://localhost:8080/api/request \ + -H 'Content-Type: application/json' \ + -d '{"agentId":"local_agent","branchName":"feature/x","diffSummary":{"title":"작업 완료","shortDescription":"변경요약"}}' + +## 설치 가이드(Installation) +자세한 설치/사용법은 USER_GUIDE.md를 참고하세요. + +## 기획 문서 / 아키텍처 +기획 및 아키텍처 문서는 `docs/PLAN.md`로 분리되어 있습니다. + +## 기여 방법(Contributing) +- 이 레포는 오픈 실험용입니다. 기여하려면 이슈를 남기고 PR을 보내주세요. +- 민감 정보(토큰 등)는 절대 커밋하지 마세요. `.env`를 사용하세요. diff --git a/USER_GUIDE.md b/USER_GUIDE.md new file mode 100644 index 0000000..83e4b46 --- /dev/null +++ b/USER_GUIDE.md @@ -0,0 +1,94 @@ +# 사용자 가이드 (User Guide) + +이 문서는 로컬에서 Maestro를 설치하고, 에이전트(예: VS Code, 훅 스크립트)와 연동해 승인 플로우를 테스트하는 방법을 단계별로 안내합니다. + +목차 +- 요구사항(Prerequisites) +- 빠른 설치(Quick install & run) +- 환경변수(.env) 설정 방법 +- 에이전트 연동 예제 (curl / 훅 / VS Code) +- 승인(Approve) 시나리오 테스트 +- 롤백(UNDO) 사용법 +- 보안 권장사항 + +--- + +## 요구사항 +- Node.js (v16+ 권장) +- Git (로컬에 병합 가능한 레포가 있어야 함) + +## 빠른 설치 & 실행 +1. 소스 클론 + git clone https://github.com/redsunjin/maestro-coding.git + cd maestro-coding + +2. (선택) 의존성 설치 + npm install + +3. .env 준비 + - 루트에 `.env` 파일을 생성하거나 환경변수로 설정. + - 최소값: + - MAIN_REPO_PATH: 병합을 수행할 메인 레포지토리의 로컬 경로 + - PORT (선택, 기본 8080) + - MAESTRO_SERVER_TOKEN (선택, 인증을 사용할 경우) + 예시 `.env`: + ``` + MAIN_REPO_PATH=/home/user/projects/my-main-repo + PORT=8080 + MAESTRO_SERVER_TOKEN=very-secret-token + ``` + +4. 서버 실행 + - 환경변수 방식: + MAIN_REPO_PATH=/path/to/main/repo node maestro-server.js + - 또는 dotenv 사용: + node -r dotenv/config maestro-server.js + +## 에이전트 연동 예제 +1) curl로 승인 요청 보내기 +``` +curl -X POST http://localhost:8080/api/request \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ${MAESTRO_SERVER_TOKEN}' \ + -d '{ + "agentId": "my_agent", + "branchName": "feature/my-branch", + "diffSummary": { + "title": "작업 완료", + "shortDescription": "변경 내용 요약" + } + }' +``` + +2) 훅 스크립트로 자동 알림 (Claude Code 등) + - `hooks/notify-maestro.sh` 를 작업 완료 훅에 등록 + - 예: `.claude/settings.json` 의 Stop 훅에 `sh hooks/notify-maestro.sh` 추가 + +3) VS Code 태스크로 호출 + `.vscode/tasks.json` 에 아래와 같이 추가: + ```json + { + "label": "Notify Maestro", + "type": "shell", + "command": "sh hooks/notify-maestro.sh" + } + ``` + +## 승인(Approve) 시나리오 테스트 +1. `npm run server` 로 서버 시작 +2. `npm run dev` 로 대시보드 실행 후 브라우저 오픈 +3. 대시보드에서 "지휘 시작" 클릭 → `🔴 LIVE` 배지 확인 +4. 별도 터미널에서 `sh hooks/notify-maestro.sh feature/test "테스트"` 실행 +5. 대시보드 레인에 노트 출현 확인 → D/F/J/K 키로 승인 + +## 롤백(UNDO) 사용법 +- 승인 직후 실수한 경우: `Ctrl+Z` 를 누르면 서버에서 `git reset --hard HEAD~1` 실행 +- 대시보드 UNDO 버튼으로도 동일 동작 가능 +- 주의: 롤백 후에는 해당 브랜치의 커밋이 메인에서 제거됩니다 + +## 보안 권장사항 +- `.env` 파일을 절대 커밋하지 마세요 (`.gitignore` 에 이미 포함되어 있습니다) +- `MAESTRO_SERVER_TOKEN` 을 설정하면 `/api/request` 엔드포인트에 Bearer 인증이 활성화됩니다 +- 로컬 개발용 도구이므로 외부 네트워크에 노출하지 않도록 주의하세요 +- 외부 접근이 필요한 경우 ngrok 등 터널링 도구 사용 시 토큰 인증을 반드시 설정하세요 +- `.env.example` 을 참고하여 환경변수 구성을 확인하고 실제 값은 `.env` 에만 입력하세요 diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 0000000..0c0db3a --- /dev/null +++ b/docs/PLAN.md @@ -0,0 +1,380 @@ +# 기획 / 아키텍처 문서 보관소 (PLAN) + +이 파일은 기존 README.md(기획 문서)를 보관하는 용도로 사용합니다. +프로젝트 초기 기획, 아키텍처, 실험 메모, 설계 결정 사항 등 변경·보존해야 하는 문서를 이곳으로 옮겨주세요. + +--- + +# Maestro Coding + +

+ + Demo + +

+ +## 🎼 '마에스트로 코딩(Maestro Coding)' + +### 1. 핵심 메시지 (Core Message) + +* **Before:** 여러 에이전트와 창을 띄워놓고 쏟아지는 PR과 커밋 알림에 쫓기며 클릭질하는 스트레스 넘치는 개발자. +* **After:** 바흐의 선율 속에서, 투명하게 오버레이된 건반형 대시보드를 통해 리드미컬하게 다수의 에이전트를 지휘하는 우아한 개발자. +* **Slogan:** "코딩을 지휘하다, AI 에이전트와 함께하는 코드 심포니." + +### 2. 단계별 콘텐츠 전개 전략 + +#### Phase 1: 시각적 쾌감을 극대화한 숏폼 (YouTube Shorts / Reels) + +바흐의 음악과 UI의 타격감을 동기화하여 개발자들의 로망을 자극하는 30~60초 분량의 영상입니다. + +* **오디오:** 바흐의 인벤션(Invention)이나 평균율 클라비어 곡집처럼 규칙적이고 경쾌한 피아노/하프시코드 연주곡. +* **화면 구성 (분할 화면):** + * **상단/배경:** 다크 모드의 세련된 개발 환경. 투명한 '건반형 대시보드' 위로 에이전트들의 코드 리뷰 요청(Diff 요약본)이 위에서 아래로 리듬 게임의 노트처럼 떨어집니다. + * **하단/실사:** 여유롭게 커피를 마시며, 키보드 특정 키(예: A, S, D, F)를 음악 비트에 맞춰 가볍게 탭(Tap)하는 손. + + +* **포인트:** 키를 누를 때마다 화면의 코드 노드가 경쾌한 파동을 일으키며 'Merged(승인)' 상태로 변하고, 브랜치들이 메인 트리에 깔끔하게 합쳐지는 애니메이션을 연출합니다. + +#### Phase 2: 기술 블로그 아티클 (The Architecture of Flow) + +영상을 보고 "저거 어떻게 세팅한 거지?"라고 궁금해할 개발자들을 위한 딥다이브 콘텐츠입니다. + +* **주제:** Git Worktree와 다중 AI 에이전트를 활용한 병렬 개발 워크플로우 구축기. +* **내용:** + * 왜 디렉토리를 복사하지 않고 Git Worktree를 사용하여 여러 에이전트를 독립적으로 띄웠는지에 대한 기술적 이점 설명. + * 에이전트들의 승인 대기 상태를 가로채서(Intercept) 하나의 중앙 대시보드(건반 패널)로 모으는 이벤트 루프 아키텍처. + * 알림의 파편화를 막고 컨텍스트 스위칭을 최소화한 UX 설계 철학. + + + +#### Phase 3: 인터랙티브 웹 데모 및 오픈소스/컴포넌트 공개 + +단순한 영상 콘텐츠로 끝내는 것이 아니라, 직접 경험해 볼 수 있는 미니 데모를 제공하여 기술력을 증명합니다. + +* 웹 브라우저에서 바흐 음악과 함께 가짜(Mock) 에이전트 커밋들이 내려오고, 사용자가 직접 키보드로 승인해 보는 리듬 게임 형태의 랜딩 페이지 제작. +* 이 '건반형 승인 대시보드'를 AI 보조 코딩을 위해 설계된 전체 풀스택 프레임워크 내에서 언제든 꺼내 쓸 수 있는 핵심 **재사용 UI/UX 컴포넌트**로 패키징하여 소개합니다. + +--- + +## 🔌 `maestro-server.js` 동작 원리 + +프론트엔드 데모만으로는 실제 에이전트 승인 요청을 받을 수 없습니다. +`maestro-server.js`는 **에이전트 ↔ 대시보드** 사이를 연결하는 경량 Node.js 서버입니다. + +### 전체 아키텍처 흐름 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Maestro 시스템 전체 흐름 │ +│ │ +│ AI 에이전트 │ +│ (Codex / Claude / │ +│ 터미널 스크립트 등) │ +│ │ │ +│ │ ① 작업 완료 후 │ +│ │ POST /api/request │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ maestro-server.js (포트 8080) │ │ +│ │ │ │ +│ │ HTTP 서버 WebSocket 서버 │ │ +│ │ ┌──────────────┐ ┌──────────────────┐ │ │ +│ │ │POST /api/req │──②──▶ │broadcast() │ │ │ +│ │ │GET /health │ │AGENT_TASK_READY │ │ │ +│ │ └──────────────┘ └────────┬─────────┘ │ │ +│ │ │ │ │ +│ │ Git 실행 (execFile) ◀──⑤────── │ │ │ +│ │ git merge / reset │ │ │ +│ └───────────────────────────────────┼─────────────┘ │ +│ │ ③ WebSocket │ +│ ▼ ws://localhost:8080 │ +│ ┌────────────────────────┐ │ +│ │ 브라우저 대시보드 │ │ +│ │ (React / App.jsx) │ │ +│ │ │ │ +│ │ 노트가 레인으로 떨어짐 🎵 │ │ +│ │ │ │ +│ │ 키보드 D/F/J/K 입력 ④ │ │ +│ └────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### 단계별 이벤트 흐름 + +| 단계 | 주체 | 동작 | +|------|------|------| +| ① | AI 에이전트 | 작업(커밋) 완료 후 `POST /api/request` 로 승인 요청 전송 | +| ② | 서버 | JSON 파싱 → `AGENT_TASK_READY` 이벤트를 연결된 모든 대시보드로 브로드캐스트 | +| ③ | 대시보드 | WebSocket 메시지 수신 → 해당 레인에 노트(음표)가 화면 위에서 아래로 낙하 | +| ④ | 사용자 | 키보드(`D` `F` `J` `K`)로 노트 승인 → `APPROVE` 이벤트를 서버로 전송 | +| ⑤ | 서버 | `git merge ` 실행 → 성공 시 `MERGE_SUCCESS` 응답 | + +> **`Ctrl+Z` 롤백 흐름:** 사용자가 `Ctrl+Z`를 누르면 `UNDO` 이벤트가 서버로 전송되고, 서버는 `git reset --hard HEAD~1`을 실행합니다. + +--- + +### 실행 방법 + +```bash +# 1. 의존성 설치 (ws 패키지 포함) +npm install + +# 2. 서버 시작 +npm run server +# 또는 +node maestro-server.js + +# 3. 프론트엔드 개발 서버 (별도 터미널) +npm run dev +``` + +서버가 시작되면 대시보드에서 "지휘 시작" 버튼을 눌렀을 때 자동으로 `ws://localhost:8080`에 연결을 시도합니다. +연결에 성공하면 헤더에 **🔴 LIVE** 배지가 표시됩니다. 연결 실패 시에는 자동으로 Mock 모드로 동작합니다. + +#### 환경 변수 + +| 변수 | 기본값 | 설명 | +|------|--------|------| +| `PORT` | `8080` | 서버 리스닝 포트 | +| `MAIN_REPO_PATH` | `process.cwd()` | `git merge`/`git reset` 을 실행할 메인 레포지토리 경로 | +| `VITE_WS_URL` | `ws://localhost:8080` | 프론트엔드가 연결할 WebSocket 주소 (`.env` 파일에 설정) | + +예시: +```bash +MAIN_REPO_PATH=/home/user/my-project PORT=9090 node maestro-server.js +``` + +--- + +### HTTP API 레퍼런스 + +#### `POST /api/request` — 에이전트 승인 요청 + +에이전트(또는 완료 훅 스크립트)가 작업 완료 시 이 엔드포인트로 요청을 보냅니다. + +**요청 본문 (`application/json`)** + +```json +{ + "requestId": "req_abc123", + "agentId": "agent_backend_01", + "branchName": "feature/jwt-optimization", + "projectId": "proj_b2c", + "laneIndex": 2, + "diffSummary": { + "title": "JWT 검증 로직 최적화", + "impact": "Medium", + "shortDescription": "auth.js 45-60 라인 수정. 예외 처리 추가." + } +} +``` + +| 필드 | 필수 | 설명 | +|------|------|------| +| `agentId` | 권장 | 에이전트 식별자 | +| `branchName` | 권장 | 실제 git merge 대상 브랜치 이름 | +| `projectId` | 선택 | 프론트엔드 탭 선택에 사용 (`proj_b2c`, `proj_admin`, `proj_api`) | +| `laneIndex` | 선택 | UI 레인 번호 1~4. 생략 시 서버가 랜덤 배정 | +| `diffSummary` | 선택 | 생략 시 `title` / `description` 최상위 필드를 대체 사용 | + +**curl 예시** + +```bash +curl -X POST http://localhost:8080/api/request \ + -H 'Content-Type: application/json' \ + -d '{ + "agentId": "my_agent", + "branchName": "feature/my-branch", + "laneIndex": 1, + "diffSummary": { + "title": "작업 완료", + "shortDescription": "변경 내용 요약" + } + }' +``` + +**응답** + +```json +{ "success": true, "requestId": "req_1748392839201" } +``` + +#### `GET /health` — 서버 상태 확인 + +```bash +curl http://localhost:8080/health +# {"status":"ok","clients":1} +``` + +--- + +### WebSocket 이벤트 목록 + +#### 서버 → 대시보드 (수신 이벤트) + +| 이벤트 | 설명 | +|--------|------| +| `AGENT_TASK_READY` | 에이전트 승인 요청. 이 이벤트의 페이로드가 노트(음표)로 화면에 표시됩니다. | +| `MERGE_SUCCESS` | `git merge` 성공. 노트가 화면에서 사라집니다. | +| `MERGE_FAILED` | `git merge` 실패. 서버 로그를 확인하세요. | +| `UNDO_SUCCESS` | `git reset --hard HEAD~1` 성공. | +| `UNDO_FAILED` | 롤백 실패. | +| `AGENT_RESTARTED` | 반려(REJECT) 처리 완료 확인. | + +#### 대시보드 → 서버 (송신 이벤트) + +| 액션 | 설명 | +|------|------| +| `APPROVE` | 노트 승인. `branchName`이 있으면 `git merge` 실행. | +| `REJECT` | 노트 반려. `feedback` 필드로 에이전트에 수정 지시 전달 가능. | +| `UNDO` | 직전 병합 롤백 (`git reset --hard HEAD~1`). | + +--- + +## 🤖 실제 AI 개발툴과 연동하기 + +> **"API 통해서 네트워크 타고 갔다 오는 게 맞나요? 실제 개발툴하고 통신이 되는 건가요?"** +> **네, 맞습니다.** `localhost:8080`을 통한 진짜 HTTP/WebSocket 통신입니다. +> AI 도구가 작업을 마치는 순간, 실제로 승인 요청이 대시보드에 날아옵니다. + +### 전체 통신 흐름 (네트워크 레벨) + +``` +[AI 개발툴 (Cursor / Claude Code / aider 등)] + │ + │ ① 작업 완료 → 훅 스크립트 실행 + │ hooks/notify-maestro.sh + │ + │ ② 진짜 HTTP POST 요청 (로컬호스트) + ▼ + POST http://localhost:8080/api/request + │ + │ ③ JSON 파싱 → WebSocket 브로드캐스트 + ▼ + ws://localhost:8080 ───────────────────▶ [브라우저 대시보드] + │ + 노트가 레인으로 떨어짐 🎵 + │ + D / F / J / K 키 입력 ④ + │ + ◀───────────────── WebSocket APPROVE ──────┘ + │ + │ ⑤ git merge + ▼ + 브랜치가 메인으로 실제 병합됩니다 ✅ +``` + +> **"로컬호스트니까 사실상 인터넷은 아니지 않나요?"** +> 맞습니다 — 같은 머신 안의 루프백(loopback) 통신입니다. 덕분에 외부 서버 없이, 인터넷 연결 없이도 동작합니다. +> 원격 에이전트(다른 PC, 클라우드 서버 등)가 필요하다면 ngrok 등으로 터널링하면 됩니다. + +--- + +### 방법 1 — Claude Code 훅 (가장 쉬움 ⭐) + +Claude Code는 에이전트가 작업을 마칠 때 자동으로 쉘 명령을 실행하는 **Stop 훅**을 지원합니다. + +**설정 방법 (프로젝트 루트에서):** + +```bash +# .claude 디렉토리가 없으면 생성 +mkdir -p .claude + +# 훅 설정 파일 복사 +cp hooks/claude-settings-example.json .claude/settings.json +``` + +**.claude/settings.json 내용:** + +```json +{ + "hooks": { + "Stop": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "sh hooks/notify-maestro.sh" + } + ] + } + ] + } +} +``` + +이후 Claude Code에서 작업이 완료될 때마다 **자동으로** 대시보드에 승인 요청이 나타납니다. + +--- + +### 방법 2 — 터미널에서 직접 호출 + +어떤 AI 도구든, 어떤 스크립트든 작업 완료 후 한 줄만 추가하면 됩니다: + +```bash +# 가장 간단한 형태 (브랜치·커밋 메시지 자동 감지) +sh hooks/notify-maestro.sh + +# 명시적으로 정보를 전달하는 형태 +sh hooks/notify-maestro.sh feature/auth "JWT 검증 로직 추가" "auth.js 45-60 수정" + +# 환경변수로 제어 +AGENT_ID=my_agent LANE_INDEX=2 sh hooks/notify-maestro.sh +``` + +--- + +### 방법 3 — aider, 기타 CLI 에이전트 래퍼 + +`aider`처럼 반복 실행되는 AI 에이전트라면 완료 후 훅을 래퍼 스크립트로 감쌀 수 있습니다: + +```bash +#!/bin/bash +# run-agent.sh — aider 실행 후 Maestro 에 알림 + +aider --model gpt-4o "$@" +EXIT_CODE=$? + +if [ $EXIT_CODE -eq 0 ]; then + sh hooks/notify-maestro.sh +fi +``` + +--- + +### 방법 4 — git post-commit 훅 + +커밋이 생성될 때마다 자동으로 승인 요청을 보내려면: + +```bash +# .git/hooks/post-commit 파일에 추가 +echo '#!/bin/sh' > .git/hooks/post-commit +echo 'sh "$(git rev-parse --show-toplevel)/hooks/notify-maestro.sh"' >> .git/hooks/post-commit +chmod +x .git/hooks/post-commit +``` + +--- + +### 실제 동작 확인 (30초 테스트) + +```bash +# 터미널 1: 서버 시작 +npm run server + +# 터미널 2: 브라우저에서 대시보드 열고 "지휘 시작" 클릭 +npm run dev + +# 터미널 3: 승인 요청 직접 발사 — 대시보드에 노트가 나타나는지 확인! +sh hooks/notify-maestro.sh feature/test-branch "테스트 커밋" "실제 통신 확인" +``` + +브라우저 대시보드에 노트가 나타나면, **실제 HTTP → WebSocket 통신**이 작동하는 것입니다. +이제 `D` `F` `J` `K` 키를 누르면 서버에서 `git merge` 가 실행됩니다. 🎼 + +--- + +### 3. 성공적인 연출을 위한 UX 디테일 + +* **Diff 하이라이트의 추상화:** 승인 화면에서 코드를 한 줄 한 줄 읽게 하면 리듬이 깨집니다. 에이전트가 "어떤 의도"로 "어느 로직"을 건드렸는지만 3줄 이내의 자연어나 미니 맵 형태로 보여주어 직관적인 판단을 돕습니다. +* **되감기(Undo) 기능:** 리듬에 맞춰 빠르게 승인하다 실수했을 때, 음악의 리와인드 효과음과 함께 방금 병합한 커밋을 취소하는 단축키(`Ctrl+Z` 등)를 지원하여 심리적 안정감을 제공합니다. diff --git a/package.json b/package.json index f3e19b6..b74bb1f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "vite build", "preview": "vite preview", - "server": "node maestro-server.js" + "server": "node maestro-server.js", + "configure": "node scripts/configure.js" }, "dependencies": { "lucide-react": "^0.511.0", @@ -19,6 +20,7 @@ "@vitejs/plugin-react": "^4.4.1", "tailwindcss": "^4.1.6", "vite": "^6.3.5", - "ws": "^8.19.0" + "ws": "^8.19.0", + "prompts": "^2.4.2" } } diff --git a/scripts/configure.js b/scripts/configure.js new file mode 100644 index 0000000..84b51b8 --- /dev/null +++ b/scripts/configure.js @@ -0,0 +1,62 @@ +#!/usr/bin/env node +// scripts/configure.js — .env 파일 대화형 설정 스크립트 (Node.js / prompts) +import prompts from 'prompts'; +import { readFileSync, writeFileSync, existsSync } from 'fs'; +import { resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const rootDir = resolve(__dirname, '..'); +const envFile = resolve(rootDir, '.env'); +const exampleFile = resolve(rootDir, '.env.example'); + +if (existsSync(envFile)) { + const { overwrite } = await prompts({ + type: 'confirm', + name: 'overwrite', + message: '.env 파일이 이미 존재합니다. 덮어쓰시겠습니까?', + initial: false, + }); + if (!overwrite) { + console.log('취소되었습니다.'); + process.exit(0); + } +} + +const response = await prompts([ + { + type: 'text', + name: 'MAIN_REPO_PATH', + message: 'git merge를 수행할 메인 레포지토리의 로컬 경로를 입력하세요', + initial: process.env.MAIN_REPO_PATH || '', + validate: (v) => v.trim() !== '' || '경로는 필수입니다.', + }, + { + type: 'text', + name: 'PORT', + message: '서버 포트를 입력하세요', + initial: '8080', + }, + { + type: 'text', + name: 'VITE_WS_URL', + message: 'WebSocket URL을 입력하세요', + initial: 'ws://localhost:8080', + }, + { + type: 'password', + name: 'MAESTRO_SERVER_TOKEN', + message: 'API 인증 토큰을 입력하세요 (선택, 비워두면 인증 비활성화)', + initial: '', + }, +]); + +// Read example as base then overwrite values +let content = readFileSync(exampleFile, 'utf8'); +for (const [key, value] of Object.entries(response)) { + const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + content = content.replace(new RegExp(`^${escapedKey}=.*`, 'm'), `${key}=${value}`); +} + +writeFileSync(envFile, content, 'utf8'); +console.log(`\n.env 파일이 저장되었습니다: ${envFile}`); diff --git a/scripts/setup_env.ps1 b/scripts/setup_env.ps1 new file mode 100644 index 0000000..db78dc6 --- /dev/null +++ b/scripts/setup_env.ps1 @@ -0,0 +1,25 @@ +# scripts/setup_env.ps1 — .env 파일 초기 설정 스크립트 (Windows PowerShell) +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RootDir = Split-Path -Parent $ScriptDir +$EnvFile = Join-Path $RootDir ".env" +$ExampleFile = Join-Path $RootDir ".env.example" + +if (Test-Path $EnvFile) { + Write-Host ".env 파일이 이미 존재합니다: $EnvFile" + $answer = Read-Host "덮어쓰시겠습니까? (y/N)" + if ($answer -notmatch "^[yY]$") { + Write-Host "취소되었습니다." + exit 0 + } +} + +Copy-Item -Path $ExampleFile -Destination $EnvFile -Force +Write-Host ".env 파일이 생성되었습니다: $EnvFile" +Write-Host "" +Write-Host "다음 항목을 편집하여 실제 값을 입력하세요:" +Write-Host " MAIN_REPO_PATH — git merge를 수행할 로컬 레포지토리 경로" +Write-Host " MAESTRO_SERVER_TOKEN — API 인증 토큰 (선택)" +Write-Host "" +Write-Host "편집 예시:" +Write-Host " notepad $EnvFile" +Write-Host " 또는: code $EnvFile" diff --git a/scripts/setup_env.sh b/scripts/setup_env.sh new file mode 100755 index 0000000..1d9aa47 --- /dev/null +++ b/scripts/setup_env.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# scripts/setup_env.sh — .env 파일 초기 설정 스크립트 (Linux/macOS) +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +ENV_FILE="$ROOT_DIR/.env" +EXAMPLE_FILE="$ROOT_DIR/.env.example" + +if [ -f "$ENV_FILE" ]; then + echo ".env 파일이 이미 존재합니다: $ENV_FILE" + read -r -p "덮어쓰시겠습니까? (y/N) " answer + case "$answer" in + [yY]) ;; + *) echo "취소되었습니다."; exit 0 ;; + esac +fi + +cp "$EXAMPLE_FILE" "$ENV_FILE" +echo ".env 파일이 생성되었습니다: $ENV_FILE" +echo "" +echo "다음 항목을 편집하여 실제 값을 입력하세요:" +echo " MAIN_REPO_PATH — git merge를 수행할 로컬 레포지토리 경로" +echo " MAESTRO_SERVER_TOKEN — API 인증 토큰 (선택)" +echo "" +echo "편집 예시:" +echo " nano $ENV_FILE" +echo " 또는: code $ENV_FILE"