relayax-cli 0.2.26 → 0.2.27

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.
@@ -7,6 +7,8 @@ exports.BUILDER_COMMANDS = exports.USER_COMMANDS = void 0;
7
7
  exports.createAdapter = createAdapter;
8
8
  exports.getGlobalCommandPath = getGlobalCommandPath;
9
9
  exports.getGlobalCommandDir = getGlobalCommandDir;
10
+ exports.getGlobalCommandDirForTool = getGlobalCommandDirForTool;
11
+ exports.getGlobalCommandPathForTool = getGlobalCommandPathForTool;
10
12
  exports.formatCommandFile = formatCommandFile;
11
13
  const os_1 = __importDefault(require("os"));
12
14
  const path_1 = __importDefault(require("path"));
@@ -24,18 +26,31 @@ function createAdapter(tool) {
24
26
  };
25
27
  }
26
28
  /**
27
- * 글로벌 슬래시 커맨드 파일 경로.
29
+ * 글로벌 슬래시 커맨드 파일 경로 (Claude Code 기본).
28
30
  * ~/.claude/commands/relay/{id}.md
29
31
  */
30
32
  function getGlobalCommandPath(commandId) {
31
33
  return path_1.default.join(os_1.default.homedir(), '.claude', 'commands', 'relay', `${commandId}.md`);
32
34
  }
33
35
  /**
34
- * 글로벌 슬래시 커맨드 디렉토리.
36
+ * 글로벌 슬래시 커맨드 디렉토리 (Claude Code 기본).
35
37
  */
36
38
  function getGlobalCommandDir() {
37
39
  return path_1.default.join(os_1.default.homedir(), '.claude', 'commands', 'relay');
38
40
  }
41
+ /**
42
+ * 특정 AI 도구의 글로벌 커맨드 디렉토리.
43
+ * ~/{skillsDir}/commands/relay/
44
+ */
45
+ function getGlobalCommandDirForTool(skillsDir) {
46
+ return path_1.default.join(os_1.default.homedir(), skillsDir, 'commands', 'relay');
47
+ }
48
+ /**
49
+ * 특정 AI 도구의 글로벌 커맨드 파일 경로.
50
+ */
51
+ function getGlobalCommandPathForTool(skillsDir, commandId) {
52
+ return path_1.default.join(os_1.default.homedir(), skillsDir, 'commands', 'relay', `${commandId}.md`);
53
+ }
39
54
  /**
40
55
  * 커맨드 콘텐츠를 파일 형식으로 포맷.
41
56
  */
@@ -95,36 +110,71 @@ JSON 결과 예시:
95
110
  // ─── User Commands (글로벌 설치) ───
96
111
  exports.USER_COMMANDS = [
97
112
  {
98
- id: 'relay-explore',
99
- description: 'relay 마켓플레이스를 탐색하고 프로젝트에 맞는 팀을 찾습니다',
100
- body: `사용자의 요청이나 현재 프로젝트 맥락에 맞는 에이전트 팀을 relay 마켓플레이스에서 탐색합니다.
113
+ id: 'relay-install',
114
+ description: 'relay 마켓플레이스에서 에이전트 팀을 설치합니다',
115
+ body: `요청된 에이전트 팀을 relay 마켓플레이스에서 다운로드하고, 현재 에이전트 환경에 맞게 구성합니다.
116
+ 인자 없이 호출하면 인터랙티브 탐색 모드로 진입합니다.
101
117
 
102
- ## 실행 방법
118
+ ## 인터랙션 플로우
103
119
 
104
- 1. 사용자의 요청에서 키워드를 추출합니다. 명시적 키워드가 없으면 현재 프로젝트를 분석하여 적절한 검색어를 판단합니다.
105
- 2. \`relay search <keyword>\` 명령어를 실행합니다 (필요하면 여러 키워드로 반복).
106
- 3. 결과를 현재 프로젝트 맥락과 대조하여 가장 도움될 팀을 추천합니다:
107
- - 팀 이름과 설명
108
- - 제공하는 커맨드 목록
109
- - 왜 이 팀이 지금 프로젝트에 맞는지 설명
110
- 4. 관심 있는 팀이 있다면 \`/relay-install <@author/slug>\`로 바로 설치할 수 있다고 안내합니다.
120
+ 커맨드는 3단계 인터랙션으로 진행됩니다. 단계에서 반드시 AskUserQuestion 도구를 사용하세요.
111
121
 
112
- ## 예시
122
+ ### Step 1. 공간 선택 & 팀 탐색 (slug가 없을 때만)
113
123
 
114
- 사용자: /relay-explore 콘텐츠 만들 있는 있어?
115
- → relay search 콘텐츠 실행
116
- → 결과 해석: "contents-team이 카드뉴스, PDF, PPT를 만들 수 있어요"
117
- → 프로젝트 맥락 기반 추천
118
- → "/relay-install @example/contents-team으로 설치할 수 있어요"`,
119
- },
120
- {
121
- id: 'relay-install',
122
- description: 'relay 마켓플레이스에서 에이전트 팀을 설치합니다',
123
- body: `요청된 에이전트 팀을 relay 마켓플레이스에서 다운로드하고, 현재 에이전트 환경에 맞게 구성합니다.
124
+ slug가 직접 주어지면 (\`/relay-install @alice/doc-writer\`) 단계를 건너뛰고 Step 2로 갑니다.
124
125
 
125
- ## 실행 방법
126
+ #### 1-1. 공간 선택
127
+ \`relay spaces --json\` 을 실행하여 사용자의 Space 목록을 가져옵니다.
128
+
129
+ **AskUserQuestion 호출:**
130
+ - question: "어디서 팀을 찾을까요?"
131
+ - options: Space가 있으면 \`["마켓플레이스 (공개)", "<space1_name>", "<space2_name>", ...]\`, 없으면 이 단계를 건너뛰고 바로 마켓 검색으로 진행
132
+
133
+ **응답 처리:**
134
+ - "마켓플레이스 (공개)" → 1-2. 마켓 검색으로 진행
135
+ - Space 이름 선택 → 1-3. Space 팀 목록으로 진행
136
+
137
+ #### 1-2. 마켓 검색
138
+ 사용자의 요청에서 키워드를 추출합니다. 명시적 키워드가 없으면 현재 프로젝트를 분석하여 적절한 검색어를 판단합니다.
139
+ \`relay search <keyword>\` 명령어를 실행합니다 (필요하면 여러 키워드로 반복).
140
+
141
+ 검색 결과를 번호 리스트로 보여줍니다:
142
+
143
+ \`\`\`
144
+ 검색 결과 (3개)
145
+
146
+ 1. @alice/doc-writer — 기술 문서 자동화
147
+ /write-doc, /api-doc
148
+
149
+ 2. @bob/code-reviewer — PR 리뷰 자동화
150
+ /review, /suggest
151
+
152
+ 3. @carol/test-gen — 테스트 코드 생성
153
+ /gen-test, /coverage
154
+ \`\`\`
155
+
156
+ **AskUserQuestion 호출:**
157
+ - question: "어떤 팀을 설치할까요?"
158
+ - options: \`["1", "2", "3", "다시 검색"]\`
159
+
160
+ "다시 검색" → 새 키워드로 1-2 반복
161
+ 번호 선택 → 해당 팀의 slug로 설치 진행
162
+
163
+ #### 1-3. Space 팀 목록
164
+ \`relay list --space <space-slug> --json\` 을 실행합니다.
165
+
166
+ 팀 목록을 번호 리스트로 보여줍니다 (1-2와 동일 형식).
126
167
 
127
- ### 1. 패키지 다운로드
168
+ **AskUserQuestion 호출:**
169
+ - question: "어떤 팀을 설치할까요?"
170
+ - options: \`["1", "2", ..., "돌아가기"]\`
171
+
172
+ "돌아가기" → 1-1로 돌아감
173
+ 번호 선택 → 해당 팀의 slug로 설치 진행
174
+
175
+ ### Step 2. 설치 & 배치 범위 선택
176
+
177
+ #### 2-1. 패키지 다운로드
128
178
  \`relay install <@author/slug> --json\` 명령어를 실행합니다.
129
179
  - Public 마켓 팀: \`relay install <@author/slug> --json\`
130
180
  - Space 팀: \`relay install @spaces/<space-slug>/<team-slug> --json\`
@@ -133,36 +183,30 @@ exports.USER_COMMANDS = [
133
183
  - CLI가 init과 login을 자동으로 처리합니다 (사용자가 별도 실행할 필요 없음).
134
184
  - JSON 출력에서 \`install_path\` (패키지 경로)를 확인합니다.
135
185
 
136
- ### 2. 배치 범위 선택
137
- 사용자에게 설치 범위를 물어봅니다:
138
-
139
- - **글로벌** (\`~/.claude/\`): 모든 프로젝트에서 사용 가능
140
- - **로컬** (현재 프로젝트 \`.claude/\`): 이 프로젝트에서만 사용
186
+ #### 2-2. 배치 범위 선택
141
187
 
142
- 판단 기준:
143
- - 범용 도구 (카드뉴스, PDF 생성 등): 글로벌 추천
144
- - 프로젝트 전용 팀: 로컬 추천
145
- - Space 비공개 팀: 로컬 추천
188
+ **AskUserQuestion 호출:**
189
+ - question: "어디에 설치할까요?"
190
+ - options: \`["글로벌 (모든 프로젝트)", "로컬 (이 프로젝트만)"]\`
146
191
 
147
- 사용자가 별도 지정하지 않으면 글로벌로 진행합니다.
192
+ **응답 처리:**
193
+ - "글로벌" → \`~/.claude/\`에 배치
194
+ - "로컬" → 현재 프로젝트 \`.claude/\`에 배치
148
195
 
149
- ### 3. 에이전트 환경에 맞게 배치
196
+ #### 2-3. 에이전트 환경에 맞게 배치
150
197
  다운로드된 패키지(\`install_path\`)에서 파일을 읽고 선택된 범위에 배치합니다:
151
- - Claude Code 글로벌: \`<install_path>/commands/\` → \`~/.claude/commands/\`에 복사
152
- - Claude Code 글로벌: \`<install_path>/skills/\` → \`~/.claude/skills/\`에 복사
153
- - Claude Code 로컬: \`<install_path>/commands/\` → \`.claude/commands/\`에 복사
154
- - Claude Code 로컬: \`<install_path>/skills/\` → \`.claude/skills/\`에 복사
198
+ - 글로벌: \`<install_path>/commands/\` → \`~/.claude/commands/\`에 복사, skills/ 동일
199
+ - 로컬: \`<install_path>/commands/\` → \`.claude/commands/\`에 복사, skills/ 동일
155
200
  - agents/, rules/ 파일도 같은 방식으로 배치합니다.
156
201
  - **충돌 확인**: 같은 이름의 파일이 이미 있으면 사용자에게 덮어쓸지 물어봅니다.
157
202
 
158
- ### 4. 배치 정보 기록 (필수)
159
- 배치 완료 후 반드시 \`relay deploy-record\`를 실행하여 배치 정보를 기록합니다:
203
+ #### 2-4. 배치 정보 기록 (필수)
204
+ 배치 완료 후 반드시 \`relay deploy-record\`를 실행합니다:
160
205
  \`\`\`
161
206
  relay deploy-record <slug> --scope <global|local> --files <배치된_파일1> <배치된_파일2> ...
162
207
  \`\`\`
163
- 이 정보는 \`relay uninstall\` 시 배치된 파일까지 정리하는 데 사용됩니다.
164
208
 
165
- ### 5. Requirements 확인 및 설치
209
+ #### 2-5. Requirements 확인 및 설치
166
210
  \`<install_path>/relay.yaml\`의 \`requires\` 섹션을 읽고 처리합니다:
167
211
  - **cli**: \`which <name>\`으로 확인 → 없으면 install 명령 실행 또는 안내
168
212
  - **npm**: \`npm list <package>\`로 확인 → 없으면 \`npm install\`
@@ -172,12 +216,14 @@ relay deploy-record <slug> --scope <global|local> --files <배치된_파일1> <
172
216
  - **teams**: 의존하는 다른 팀 → \`relay install <@author/team>\`으로 재귀 설치
173
217
  ${LOGIN_JIT_GUIDE}
174
218
 
175
- ### 6. 완료 안내
219
+ ### Step 3. 완료 & 팔로우 제안
220
+
221
+ #### 3-1. 완료 안내
176
222
  - 배치된 파일과 활성화된 커맨드 목록을 보여줍니다.
177
223
  ${BUSINESS_CARD_FORMAT}
178
- ### 7. 팔로우 제안 (필수 — 이 단계를 절대 건너뛰지 마세요)
224
+
225
+ #### 3-2. 팔로우 제안 (필수 — 이 단계를 절대 건너뛰지 마세요)
179
226
  명함 표시 직후, 빌더의 username이 JSON 결과에 있으면 **반드시** AskUserQuestion 도구를 호출하세요.
180
- 텍스트로 질문하지 말고, **AskUserQuestion 도구를 직접 호출**해야 합니다.
181
227
 
182
228
  **AskUserQuestion 호출:**
183
229
  - question: \`@{username}을 팔로우할까요? 새 버전 알림을 받을 수 있습니다.\`
@@ -187,122 +233,128 @@ ${BUSINESS_CARD_FORMAT}
187
233
  - "팔로우" → \`relay follow @{username}\` 실행. 로그인이 안 되어 있으면 \`relay login\` 먼저 실행 후 재시도.
188
234
  - "건너뛰기" → 다음 단계로 진행
189
235
 
190
- ### 8. 사용 제안
236
+ #### 3-3. 사용 제안
191
237
  - "바로 사용해볼까요?" 제안
192
238
 
193
- ### 9. 업데이트 확인 (설치 완료 후)
239
+ #### 3-4. 업데이트 확인
194
240
  - \`relay check-update\` 명령어를 실행합니다.
195
241
  - CLI 업데이트가 있으면 안내합니다: "relay v{new} available. Run: npm update -g relayax-cli"
196
242
  - 다른 팀 업데이트가 있으면 안내합니다.
197
243
 
198
244
  ## 예시
199
245
 
200
- 사용자: /relay-install @example/contents-team
201
- → relay install @example/contents-team --json 실행 (패키지 다운로드)
202
- 사용자에게 "글로벌 vs 로컬" 선택 질문 글로벌
203
- .relay/teams/ 내용을 ~/.claude/에 배치
204
- → relay deploy-record @example/contents-team --scope global --files ~/.claude/commands/cardnews.md ...
205
- requires 확인: playwright 설치됨, sharp 설치됨
206
- 명함 표시 (인용 블록)
207
- → AskUserQuestion 호출: "@example을 팔로우할까요? 버전 알림을 받을 있습니다." → 팔로우/건너뛰기
208
- → " 설치 완료! /cardnews를 사용해볼까요?"`,
246
+ ### 인터랙티브 모드 (/relay-install)
247
+ → relay spaces --json 실행
248
+ AskUserQuestion: "어디서 팀을 찾을까요?" ["마켓플레이스 (공개)", "Acme Corp"]
249
+ "마켓플레이스" 선택 "어떤 팀을 찾고 계세요?"
250
+ → relay search "문서" 실행 결과 리스트 표시
251
+ AskUserQuestion: "어떤 팀을 설치할까요?" ["1", "2", "3", "다시 검색"]
252
+ "1" 선택 (@alice/doc-writer)
253
+ → AskUserQuestion: "어디에 설치할까요?" ["글로벌 (모든 프로젝트)", "로컬 (이 프로젝트만)"]
254
+ → "글로벌" 선택
255
+ → 설치 + 배치 + deploy-record
256
+ → 명함 표시
257
+ → AskUserQuestion: "@alice을 팔로우할까요?" → ["팔로우", "건너뛰기"]
258
+ → "✓ 설치 완료! /write-doc를 사용해볼까요?"
259
+
260
+ ### 다이렉트 모드 (/relay-install @alice/doc-writer)
261
+ → relay install @alice/doc-writer --json 실행 (Step 1 건너뜀)
262
+ → AskUserQuestion: "어디에 설치할까요?" → ["글로벌 (모든 프로젝트)", "로컬 (이 프로젝트만)"]
263
+ → 설치 + 배치 + deploy-record
264
+ → 명함 표시
265
+ → AskUserQuestion: "@alice을 팔로우할까요?" → ["팔로우", "건너뛰기"]
266
+ → "✓ 설치 완료! /write-doc를 사용해볼까요?"`,
209
267
  },
210
268
  {
211
- id: 'relay-list',
212
- description: '설치된 에이전트 목록을 확인합니다',
213
- body: `현재 설치된 에이전트 목록을 보여줍니다.
269
+ id: 'relay-status',
270
+ description: '설치된 팀과 Space 현황을 확인합니다',
271
+ body: `현재 설치된 에이전트 팀과 소속 Space 현황을 한눈에 보여줍니다.
214
272
 
215
273
  ## 실행 방법
216
274
 
217
- 1. \`relay list --json\` 명령어를 실행합니다.
218
- 2. 결과를 사용자에게 보기 좋게 정리하여 보여줍니다:
219
- - 팀 이름과 버전
220
- - 설치 날짜
221
- - 사용 가능한 커맨드
222
- 3. 설치된 팀이 없으면 \`/relay-explore\`로 팀을 탐색해보라고 안내합니다.
223
-
224
- ### Space 팀 목록 확인
225
- - 특정 Space에서 사용 가능한 팀 목록을 보려면: \`relay list --space <space-slug> --json\`
226
- - Space에 가입되어 있어야 합니다.
275
+ ### 1. 설치된 목록
227
276
 
228
- ## 예시
277
+ \`relay list --json\` 명령어를 실행합니다.
229
278
 
230
- 사용자: /relay-list
231
- → relay list --json 실행
232
- → "2개 팀이 설치되어 있어요:"
233
- " @example/contents-team v1.2.0 (2일 전 설치) - /cardnews, /pdf-report"
234
- → " qa-team v0.5.1 (1주 전 설치) - /qa, /qa-only"
235
-
236
- 사용자: /relay-list --space bobusan
237
- → relay list --space bobusan --json 실행
238
- → "bobusan Space에서 설치 가능한 팀:"
239
- → " pm-bot — 프로젝트 관리 봇"
240
- → " cs-bot — 고객 응대 봇"`,
241
- },
279
+ **JSON 응답 구조:**
280
+ \`\`\`json
281
+ {
282
+ "installed": [
242
283
  {
243
- id: 'relay-update',
244
- description: '설치된 에이전트 팀을 최신 버전으로 업데이트합니다',
245
- body: `설치된 에이전트 팀의 업데이트를 확인하고 적용합니다.
284
+ "slug": "@author/team-name",
285
+ "version": "1.2.0",
286
+ "installed_at": "2026-03-20T12:00:00.000Z",
287
+ "scope": "global",
288
+ "deploy_scope": "global",
289
+ "space_slug": null
290
+ }
291
+ ]
292
+ }
293
+ \`\`\`
246
294
 
247
- ## 실행 방법
295
+ **각 팀을 아래 형식으로 표시:**
248
296
 
249
- ### 0. CLI 업데이트 확인
250
- - 먼저 \`relay check-update\` 명령어를 실행합니다.
251
- - CLI 업데이트가 있으면 사용자에게 안내합니다: "relay v{new} available. Run: npm update -g relayax-cli"
252
- - 업데이트 여부와 관계없이 팀 업데이트를 계속 진행합니다.
253
-
254
- ### 특정 팀 업데이트
255
- - 사용자가 팀 이름을 지정한 경우: \`relay update <@author/slug> --json\` 실행
256
- - 업데이트 결과를 보여줍니다 (이전 버전 → 새 버전)
257
- - **재배치 필요 확인**: JSON 출력에 \`needs_redeploy: true\`가 있으면:
258
- 1. \`previous_deploy_scope\`를 참고하여 같은 범위(글로벌/로컬)로 파일을 다시 배치합니다.
259
- 2. 배치 후 \`relay deploy-record <slug> --scope <scope> --files <...>\`를 실행하여 기록합니다.
260
- ${BUSINESS_CARD_FORMAT}
297
+ | | 버전 | 배포 | 설치일 |
298
+ |---|---|---|---|
299
+ | @author/team-name | v1.2.0 | 글로벌 | 3/20 |
261
300
 
262
- ### 전체 업데이트 확인
263
- - 이름을 지정하지 않은 경우:
264
- 1. \`relay outdated --json\`으로 업데이트 가능한 팀 목록을 확인합니다.
265
- 2. 업데이트 가능한 팀이 있으면 목록을 보여주고 어떤 팀을 업데이트할지 물어봅니다.
266
- 3. 선택된 팀에 대해 \`relay update <@author/slug> --json\`을 실행합니다.
267
- 4. 모두 최신이면 "모든 팀이 최신 버전입니다"라고 안내합니다.
301
+ - \`deploy_scope\`가 \`"global"\` → 글로벌, \`"local"\` → 로컬, 없으면 → 미배치
302
+ - \`space_slug\`가 있으면 \`[Space: slug]\` 표시
268
303
 
269
- ## 예시
304
+ ### 2. Space 목록
270
305
 
271
- 사용자: /relay-update
272
- → relay outdated --json 실행
273
- → "1개 팀 업데이트 가능:"
274
- → " @example/contents-team: v1.2.0 → v1.3.0"
275
- → "업데이트할까요?"
276
- → relay update @example/contents-team --json 실행
277
- → needs_redeploy: true → 글로벌로 재배치
278
- → relay deploy-record @example/contents-team --scope global --files ...
279
- → "✓ @example/contents-team v1.3.0으로 업데이트 완료"`,
280
- },
281
- {
282
- id: 'relay-spaces',
283
- description: '내 Space 목록을 확인합니다',
284
- body: `사용자의 Space 목록을 조회하고 보여줍니다.
306
+ \`relay spaces --json\` 명령어를 실행합니다.
285
307
 
286
- ## 실행 방법
308
+ **JSON 응답 구조:**
309
+ \`\`\`json
310
+ {
311
+ "spaces": [
312
+ {
313
+ "slug": "my-space",
314
+ "name": "내 스페이스",
315
+ "description": "설명",
316
+ "is_personal": false,
317
+ "role": "owner"
318
+ }
319
+ ]
320
+ }
321
+ \`\`\`
287
322
 
288
- 1. \`relay spaces --json\` 명령어를 실행합니다.
289
- 2. 결과를 사용자에게 보기 좋게 정리합니다:
290
- - 개인 스페이스
291
- - 팀 스페이스 (이름, 역할, 설명)
292
- 3. Space가 있으면 관련 활용법을 안내합니다:
293
- - 팀 목록 보기: \`relay list --space <slug>\`
294
- - 비공개 팀 설치: \`relay install @spaces/<slug>/<team>\`
295
- - Space 관리: www.relayax.com/spaces/<slug>
323
+ **표시:**
324
+ - \`is_personal: true\` 개인 스페이스로 분류
325
+ - \`role\`: owner → 소유자, admin → 관리자, member → 멤버
296
326
  ${LOGIN_JIT_GUIDE}
327
+ - Spaces 조회 실패해도 설치된 팀 목록은 정상 표시합니다 (로컬 데이터).
328
+
329
+ ### 3. Space 팀 목록 (옵션)
330
+ - \`--space <slug>\` 인자가 있으면: \`relay list --space <space-slug> --json\`으로 해당 Space에서 설치 가능한 팀 목록도 보여줍니다.
331
+
332
+ ### 4. 안내
333
+ - 설치된 팀이 없으면 \`/relay-install\`로 팀을 탐색·설치해보라고 안내합니다.
334
+ - Space가 있으면 활용법을 안내합니다:
335
+ - 비공개 팀 설치: \`relay install @spaces/<slug>/<team>\`
336
+ - Space 관리: www.relayax.com/spaces/<slug>
297
337
 
298
338
  ## 예시
299
339
 
300
- 사용자: /relay-spaces
301
- → relay spaces --json 실행
302
- "2개 Space가 있어요:"
303
- → " bobusan — 보부산 (소유자)"
304
- " design-lab — 디자인 랩 (멤버)"
305
- → "💡 Space 팀 보기: relay list --space bobusan"`,
340
+ 사용자: /relay-status
341
+ → relay list --json 실행
342
+ relay spaces --json 실행 (병렬 가능)
343
+
344
+ **설치된 (2개)**
345
+
346
+ | 팀 | 버전 | 배포 | 설치일 |
347
+ |---|---|---|---|
348
+ | @alice/doc-writer | v1.2.0 | 글로벌 | 3/20 |
349
+ | @bob/code-reviewer | v0.5.1 | 로컬 | 3/15 |
350
+
351
+ **내 Space (2개)**
352
+ - acme-corp — Acme Corp (소유자)
353
+ - dev-guild — Dev Guild (멤버)
354
+
355
+ 사용자: /relay-status --space acme-corp
356
+ → 위 정보 + \`relay list --space acme-corp --json\` 실행
357
+ → acme-corp Space에서 설치 가능한 팀 목록 추가 표시`,
306
358
  },
307
359
  {
308
360
  id: 'relay-uninstall',
@@ -321,9 +373,9 @@ ${LOGIN_JIT_GUIDE}
321
373
 
322
374
  ## 예시
323
375
 
324
- 사용자: /relay-uninstall @example/contents-team
325
- → relay uninstall @example/contents-team --json 실행
326
- → "✓ @example/contents-team 삭제 완료 (12개 파일 제거)"`,
376
+ 사용자: /relay-uninstall @alice/doc-writer
377
+ → relay uninstall @alice/doc-writer --json 실행
378
+ → "✓ @alice/doc-writer 삭제 완료 (12개 파일 제거)"`,
327
379
  },
328
380
  ];
329
381
  // ─── Builder Commands (로컬 설치) ───
@@ -333,51 +385,92 @@ exports.BUILDER_COMMANDS = [
333
385
  description: '현재 팀 패키지를 포트폴리오와 함께 relay 마켓플레이스에 배포합니다',
334
386
  body: `현재 디렉토리의 에이전트 팀(.relay/)을 분석하고, 보안 점검 및 requirements를 구성한 뒤, 사용가이드와 포트폴리오를 생성하고 relay 마켓플레이스에 배포합니다.
335
387
 
336
- ## 실행 단계
388
+ ## 사전 준비 (자동)
337
389
 
338
- ### 1. 인증 확인 (가장 먼저)
390
+ ### 0-1. 인증 확인
339
391
  - \`relay status --json\` 명령어를 실행하여 로그인 상태를 확인합니다.
340
392
  - 미인증이면 즉시 \`relay login\`을 실행합니다.
341
- - 로그인 완료 후 다음 단계로 진행합니다.
342
393
  ${LOGIN_JIT_GUIDE}
343
394
 
344
- ### 2. 팀 구조 분석
395
+ ### 0-2. 팀 구조 분석
345
396
  - .relay/ 디렉토리의 skills/, agents/, rules/, commands/를 탐색합니다.
346
397
  - 각 파일의 이름과 description을 추출합니다.
347
398
  - .relay/relay.yaml이 있으면 읽고, 없으면 사용자에게 팀 정보(name, slug, description, tags)를 물어보고 생성합니다.
348
399
 
349
- ### 3. 보안 점검 & Requirements 구성 (HITL)
400
+ ## 인터랙션 플로우
401
+
402
+ 이 커맨드는 5단계 인터랙션으로 진행됩니다. 각 단계에서 반드시 AskUserQuestion 도구를 사용하세요.
403
+
404
+ ### Step 1. 공개 범위 선택
405
+
406
+ relay.yaml의 \`visibility\` 설정을 확인합니다.
407
+
408
+ #### 신규 배포 (visibility 미설정)
409
+
410
+ **AskUserQuestion 호출:**
411
+ - question: "어디에 배포할까요?"
412
+ - options: \`["공개 (마켓플레이스)", "비공개 (Space 전용)"]\`
413
+
414
+ **응답 처리:**
415
+ - "공개" → relay.yaml에 \`visibility: public\` 저장
416
+ - "비공개" → \`relay spaces --json\` 실행 후 Space 목록 표시
417
+
418
+ **AskUserQuestion 호출:**
419
+ - question: "어떤 Space에 배포할까요?"
420
+ - options: \`["<space1_name>", "<space2_name>", ...]\`
421
+
422
+ → relay.yaml에 \`visibility: private\`, \`space: <selected_slug>\` 저장
423
+
424
+ #### 재배포 (visibility 이미 설정됨)
425
+
426
+ 현재 설정을 확인합니다:
427
+
428
+ **AskUserQuestion 호출:**
429
+ - question: 공개일 때 "현재 **공개** 설정입니다. 마켓플레이스에 노출됩니다. 유지할까요?", 비공개일 때 "현재 **비공개** 설정입니다 (Space: {name}). 유지할까요?"
430
+ - options: \`["유지", "변경"]\`
431
+
432
+ "변경" → 신규 배포와 동일한 플로우
433
+
434
+ ### Step 2. 보안 점검 & requires 확인
350
435
 
351
- .relay/ 내 모든 파일을 읽고 아래 항목을 분석합니다.
436
+ .relay/ 내 모든 파일을 자동 분석합니다.
352
437
 
353
- #### 3-1. 시크릿 스캔
438
+ #### 2-1. 시크릿 스캔 (자동)
354
439
  - 하드코딩된 API 키, 토큰, 비밀번호, Private Key 등을 탐색합니다.
355
440
  - 예: sk-..., ghp_..., AKIA..., Bearer 토큰, JWT, -----BEGIN PRIVATE KEY----- 등
356
441
  - 발견 시 **즉시 사용자에게 경고**하고, 환경변수로 대체하도록 안내합니다.
357
442
  - 시크릿이 제거되지 않으면 배포를 진행하지 않습니다.
358
443
 
359
- #### 3-2. 환경변수 감지
360
- - 파일 내 환경변수 참조를 감지합니다 (process.env.*, \${VAR}, os.environ 등).
361
- - 환경변수에 대해 사용자에게 확인합니다:
362
- - "이 환경변수가 필수인가요, 선택인가요?"
363
- - 설명을 추가할 수 있습니다.
364
-
365
- #### 3-3. 의존성 감지
366
- 아래 카테고리별로 분석하고, 사용자에게 필수/선택 여부를 확인합니다:
367
-
368
- - **cli**: 파일에서 참조하는 CLI 도구 (playwright, ffmpeg, sharp 등)
444
+ #### 2-2. 환경변수 & 의존성 분석 (자동)
445
+ 분석 대상:
446
+ - **env**: 환경변수 참조 (process.env.*, \${VAR}, os.environ 등)
447
+ - **cli**: 참조하는 CLI 도구 (playwright, ffmpeg, sharp 등)
369
448
  - **npm**: import/require되는 npm 패키지
370
- - **mcp**: MCP 서버 설정 — 외부 서비스 연결 포함 (name, package, config, 필요한 env)
371
- - **runtime**: Node.js/Python 등 최소 버전 요구
372
- - **permissions**: 필요한 에이전트 권한 (filesystem, network, shell)
449
+ - **mcp**: MCP 서버 설정
450
+ - **runtime**: Node.js/Python 등 최소 버전
373
451
  - **teams**: 의존하는 다른 relay 팀
374
452
 
375
- 항목에 대해:
376
- - \`required: true/false\` — 없으면 팀이 동작하지 않는지, 부분 동작인지
377
- - \`description\` — 왜 필요한지 짧은 설명
453
+ 분석 결과를 요약 표시합니다:
378
454
 
379
- #### 3-4. .relay/relay.yaml에 requires 반영
380
- 분석 결과를 .relay/relay.yaml의 requires 섹션에 저장합니다.
455
+ \`\`\`
456
+ requires 분석 결과
457
+
458
+ 환경변수:
459
+ OPENAI_API_KEY — 필수 (LLM API 호출)
460
+ SLACK_WEBHOOK_URL — 선택 (알림 전송)
461
+
462
+ CLI: playwright (필수)
463
+ npm: sharp (필수)
464
+ MCP: supabase (선택)
465
+ \`\`\`
466
+
467
+ **AskUserQuestion 호출:**
468
+ - question: "requires 설정이 맞나요?"
469
+ - options: \`["확인", "수정"]\`
470
+
471
+ **응답 처리:**
472
+ - "확인" → .relay/relay.yaml에 requires 섹션 저장, 다음 단계로
473
+ - "수정" → 사용자와 텍스트 대화로 수정 후 다시 확인
381
474
 
382
475
  \`\`\`yaml
383
476
  # .relay/relay.yaml requires 구조
@@ -404,95 +497,116 @@ requires:
404
497
  command: "npx"
405
498
  args: ["-y", "@supabase/mcp-server"]
406
499
  env: [SUPABASE_URL, SUPABASE_SECRET_KEY]
407
- - name: notion
408
- package: "@notionhq/mcp-server"
409
- required: false
410
- env: [NOTION_API_KEY]
411
500
  runtime:
412
501
  node: ">=18"
413
502
  permissions:
414
503
  - filesystem
415
504
  - network
416
505
  teams:
417
- - @example/contents-team
506
+ - @alice/doc-writer
507
+ \`\`\`
508
+
509
+ ### Step 3. 포트폴리오 선택
510
+
511
+ output/, results/, examples/, portfolio/ 디렉토리를 스캔하여 결과물(PNG, JPG, HTML, PDF)을 찾습니다.
512
+ HTML 파일은 Playwright 스크린샷으로 변환합니다.
513
+
514
+ 발견된 파일을 번호 리스트로 보여줍니다:
515
+
516
+ \`\`\`
517
+ 포트폴리오 후보 (4개)
518
+
519
+ 1. output/report-example.png — 리포트 예시
520
+ 2. output/dashboard.html → 스크린샷 변환
521
+ 3. examples/result-1.png — 결과물 1
522
+ 4. examples/result-2.png — 결과물 2
418
523
  \`\`\`
419
524
 
420
- ### 4. 포트폴리오 수집
525
+ **AskUserQuestion 호출:**
526
+ - question: "어떤 결과물을 포트폴리오에 포함할까요? (최대 5개)"
527
+ - options: \`["전체 포함", "1", "2", "3", "4", "건너뛰기"]\`
528
+
529
+ **응답 처리:**
530
+ - "전체 포함" → 모든 파일을 .relay/portfolio/에 저장
531
+ - 번호 선택 → 해당 파일만 포함 (여러 번 선택 가능 — 한 번 선택 후 추가 선택 여부를 다시 물어봄)
532
+ - "건너뛰기" → 포트폴리오 없이 진행
533
+
534
+ 선택된 이미지를 .relay/portfolio/에 저장하고 relay.yaml의 portfolio.gallery에 등록합니다.
535
+
536
+ \`\`\`yaml
537
+ portfolio:
538
+ demo: # 선택
539
+ type: gif
540
+ path: portfolio/demo.gif
541
+ gallery: # 선택, 최대 5장
542
+ - path: portfolio/guide-preview.png
543
+ title: "사용가이드 미리보기"
544
+ - path: portfolio/report-example.png
545
+ title: "리포트 예시"
546
+ \`\`\`
421
547
 
422
- - output/, results/, examples/, portfolio/ 디렉토리를 스캔합니다.
423
- - 발견된 결과물(PNG, JPG, HTML, PDF)을 사용자에게 보여줍니다.
424
- - HTML 파일은 Playwright 스크린샷으로 변환합니다.
425
- - 사용자가 포트폴리오에 포함할 항목을 선택합니다.
426
- - 선택된 이미지를 .relay/portfolio/에 저장합니다.
548
+ 파일이 하나도 발견되지 않으면 단계를 건너뜁니다.
427
549
 
428
- ### 5. 사용가이드 생성 (GUIDE.html)
550
+ ### Step 4. GUIDE.html 컨펌
429
551
 
430
552
  설치자가 읽을 수 있는 사용가이드를 HTML로 생성합니다.
431
553
 
432
- #### 5-1. 팀 소스 분석
554
+ #### 4-1. 팀 소스 분석 (자동)
433
555
  - skills/, agents/, commands/ 디렉토리의 **모든 파일 내용**을 읽습니다.
434
556
  - 각 스킬의 SKILL.md, 에이전트 설정, 커맨드 문서를 분석하여 팀의 파이프라인 흐름을 추론합니다.
435
557
 
436
- #### 5-2. GUIDE.html 생성
558
+ #### 4-2. GUIDE.html 생성 (자동)
437
559
  - 팀의 핵심 기능, 시작 방법, 파이프라인 흐름, Q&A를 포함하는 단일 HTML 가이드를 생성합니다.
438
560
  - 디자인: 깔끔한 단일 페이지, 시스템 폰트, 최대 1200px 너비, 라이트 테마.
439
- - 5-1에서 분석한 팀 소스 정보를 기반으로 콘텐츠를 구성합니다.
440
561
  - 파이프라인이 없는 단순한 팀은 시작 방법 + 기능 설명 + Q&A만 포함합니다.
441
562
 
442
- #### 5-3. 미리보기 + 컨펌
443
- - 생성된 GUIDE.html을 브라우저에서 열어 빌더에게 미리보기를 보여줍니다.
444
- - 빌더에게 확인: "사용가이드를 확인해주세요. 이대로 진행할까요?"
563
+ #### 4-3. 미리보기 + 컨펌
564
+ 생성된 GUIDE.html을 브라우저에서 열어 빌더에게 미리보기를 보여줍니다.
445
565
 
446
- #### 5-4. 재생성 루프
447
- - 빌더가 수정을 요청하면 (예: "Q&A 추가해줘", "파이프라인 설명 더 자세히") 요청사항을 반영하여 GUIDE.html을 재생성합니다.
448
- - 재생성 다시 브라우저에서 미리보기를 보여줍니다.
449
- - 빌더가 컨펌할 때까지 반복합니다.
566
+ **AskUserQuestion 호출:**
567
+ - question: "사용가이드를 확인해주세요. 진행할까요?"
568
+ - options: \`["진행", "수정 요청"]\`
450
569
 
451
- #### 5-5. 저장
452
- - 컨펌된 GUIDE.html을 \`.relay/GUIDE.html\`에 저장합니다.
570
+ **응답 처리:**
571
+ - "진행" GUIDE.html을 \`.relay/GUIDE.html\`에 저장
572
+ - "수정 요청" → 사용자와 텍스트 대화로 수정사항 파악 → GUIDE.html 재생성 → 다시 미리보기 → AskUserQuestion 반복
453
573
 
454
- #### 5-6. GUIDE.html 스크린샷 → gallery 등록
455
- - GUIDE.html을 Playwright로 열어 첫 화면(뷰포트 1200x630)을 스크린샷 캡처합니다. (gstack 또는 webapp-testing 스킬 활용)
574
+ #### 4-4. GUIDE.html 스크린샷 → gallery 등록 (자동)
575
+ - GUIDE.html을 Playwright로 열어 첫 화면(뷰포트 1200x630)을 스크린샷 캡처합니다.
456
576
  - 결과 PNG를 \`./portfolio/guide-preview.png\`에 저장합니다.
457
577
  - relay.yaml의 portfolio gallery 첫 번째 항목으로 자동 등록합니다.
458
578
  - 이 이미지는 마켓플레이스 카드 및 OG 이미지의 fallback으로 사용됩니다 (demo > gallery 순).
459
579
 
460
- ### 6. 메타데이터 생성
580
+ ### Step 5. 최종 확인 & 배포
581
+
582
+ #### 5-1. 메타데이터 생성 (자동)
461
583
  - description: skills 내용 기반으로 자동 생성합니다.
462
584
  - long_description: 팀 소개 마크다운을 자동 생성합니다 (README.md가 있으면 활용).
463
585
  - tags: 팀 특성에 맞는 태그를 추천합니다.
464
- - 사용자에게 확인: "이대로 배포할까요?"
465
586
 
466
- ### 7. 공개 범위 확인 (필수)
467
- - .relay/relay.yaml에 \`visibility\`가 반드시 설정되어 있어야 합니다.
468
- - 설정되어 있지 않으면 빌더에게 반드시 물어봅니다:
469
- - "공개 (마켓플레이스에 누구나 검색·설치 가능)" vs "비공개 (Space 멤버만 접근)"
470
- - 선택 결과를 relay.yaml에 저장합니다.
471
- - 이미 설정되어 있으면 현재 값을 확인합니다:
472
- - 공개인 경우: "⚠ 이 팀은 **공개**로 설정되어 있어 마켓플레이스에 노출됩니다. 맞나요?"
473
- - 비공개인 경우: "이 팀은 **비공개**로 설정되어 Space 멤버만 접근 가능합니다."
474
- - 빌더가 변경을 원하면 relay.yaml을 업데이트합니다.
587
+ #### 5-2. 배포 요약 + 최종 확인
588
+ 배포할 내용을 요약 표시합니다:
475
589
 
476
- ### 8. .relay/relay.yaml 업데이트
477
- - 메타데이터, requires, 포트폴리오 슬롯을 .relay/relay.yaml에 반영합니다.
590
+ \`\`\`
591
+ 배포 요약
478
592
 
479
- \`\`\`yaml
480
- portfolio:
481
- demo: # 선택
482
- type: gif
483
- path: portfolio/demo.gif
484
- gallery: # 선택, 최대 5장
485
- - path: portfolio/guide-preview.png
486
- title: "사용가이드 미리보기"
487
- - path: portfolio/example-1.png
488
- title: "카드뉴스 예시"
593
+ 팀: my-team v1.0.0
594
+ 공개: 마켓플레이스 (공개)
595
+ Skills: 3개, Commands: 5개
596
+ 포트폴리오: 2장
597
+ requires: env 2개, cli 1개
489
598
  \`\`\`
490
599
 
491
- ### 9. 배포
492
- - \`relay publish\` 명령어를 실행합니다.
493
- - 배포 결과와 마켓플레이스 URL을 보여줍니다.
600
+ **AskUserQuestion 호출:**
601
+ - question: "이대로 배포할까요?"
602
+ - options: \`["배포", "취소"]\`
603
+
604
+ **응답 처리:**
605
+ - "배포" → \`relay publish\` 실행
606
+ - "취소" → 중단
494
607
 
495
- ### 10. 공유용 온보딩 가이드 제공
608
+ #### 5-3. 배포 완료 & 온보딩 가이드
609
+ - 배포 결과와 마켓플레이스 URL을 보여줍니다.
496
610
  - \`relay publish\` 출력 끝에 코드블록 형태의 온보딩 가이드가 포함됩니다.
497
611
  - 이 코드블록을 사용자에게 그대로 보여줍니다.
498
612
  - 출력에 코드블록이 없으면 아래 형태로 직접 생성합니다:
@@ -510,16 +624,22 @@ ${BUSINESS_CARD_FORMAT}
510
624
  ## 예시
511
625
 
512
626
  사용자: /relay-publish
513
- → 팀 구조 분석: skills 3개, commands 5개
514
- 보안 스캔: 시크릿 없음
515
- 환경변수 감지: OPENAI_API_KEY (필수), DATABASE_URL (선택)
516
- → requires 업데이트 완료
517
- 포트폴리오: output/ 스캔 → "카드뉴스 예시.png 포함?" → Yes
518
- GUIDE.html 생성 → 브라우저에서 미리보기 → 빌더 컨펌
519
- GUIDE.html 스크린샷gallery 첫 번째 이미지로 등록
520
- relay publish 실행
627
+ 인증 확인 ✓, 팀 구조 분석 (skills 3개, commands 5개)
628
+ AskUserQuestion: "어디에 배포할까요?" ["공개 (마켓플레이스)", "비공개 (Space 전용)"]
629
+ "공개" 선택
630
+ 보안 스캔 ✓ 시크릿 없음 → requires 분석 결과 표시
631
+ AskUserQuestion: "requires 설정이 맞나요?" ["확인", "수정"]
632
+ "확인"
633
+ 포트폴리오 후보 스캔 리스트 표시
634
+ AskUserQuestion: "어떤 결과물을 포함할까요?" → ["전체 포함", "1", "2", "건너뛰기"]
635
+ → "1" 선택
636
+ → GUIDE.html 생성 → 브라우저 미리보기
637
+ → AskUserQuestion: "사용가이드 진행할까요?" → ["진행", "수정 요청"]
638
+ → "진행"
639
+ → 배포 요약 표시
640
+ → AskUserQuestion: "이대로 배포할까요?" → ["배포", "취소"]
641
+ → "배포" → relay publish 실행
521
642
  → "배포 완료! URL: https://relayax.com/teams/my-team"
522
- → 온보딩 가이드 코드블록 표시
523
- → "이 블록을 팀원에게 공유하면 바로 설치할 수 있습니다"`,
643
+ → 온보딩 가이드 코드블록 표시`,
524
644
  },
525
645
  ];