relayax-cli 0.1.98 → 0.1.99
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/dist/commands/install.js +43 -1
- package/dist/lib/api.d.ts +1 -0
- package/dist/lib/api.js +19 -0
- package/dist/lib/command-adapter.js +24 -7
- package/dist/types.d.ts +15 -0
- package/package.json +1 -1
package/dist/commands/install.js
CHANGED
|
@@ -84,7 +84,10 @@ function registerInstall(program) {
|
|
|
84
84
|
console.log(JSON.stringify(result));
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
|
-
|
|
87
|
+
const authorUsername = team.author?.username;
|
|
88
|
+
const authorDisplayName = team.author?.display_name ?? authorUsername ?? '';
|
|
89
|
+
const authorSuffix = authorUsername ? ` \x1b[90mby @${authorUsername}\x1b[0m` : '';
|
|
90
|
+
console.log(`\n\x1b[32m✓ ${team.name} 다운로드 완료\x1b[0m v${team.version}${authorSuffix}`);
|
|
88
91
|
console.log(` 위치: \x1b[36m${teamDir}\x1b[0m`);
|
|
89
92
|
console.log(` 파일: ${fileCount}개`);
|
|
90
93
|
if (team.commands.length > 0) {
|
|
@@ -93,6 +96,45 @@ function registerInstall(program) {
|
|
|
93
96
|
console.log(` \x1b[33m/${cmd.name}\x1b[0m - ${cmd.description}`);
|
|
94
97
|
}
|
|
95
98
|
}
|
|
99
|
+
// Builder info block
|
|
100
|
+
if (team.welcome) {
|
|
101
|
+
console.log(`\n ┌─ 💬 ${authorDisplayName}님의 메시지 ${'─'.repeat(Math.max(0, 38 - authorDisplayName.length))}┐`);
|
|
102
|
+
const lines = team.welcome.match(/.{1,50}/g) ?? [team.welcome];
|
|
103
|
+
for (const line of lines) {
|
|
104
|
+
console.log(` │ "${line}"`);
|
|
105
|
+
}
|
|
106
|
+
console.log(` └${'─'.repeat(44)}┘`);
|
|
107
|
+
}
|
|
108
|
+
const contactLinks = team.author?.contact_links ?? {};
|
|
109
|
+
const contactEntries = Object.entries(contactLinks);
|
|
110
|
+
if (contactEntries.length > 0) {
|
|
111
|
+
const parts = contactEntries.map(([key, val]) => `${key}: ${val}`);
|
|
112
|
+
console.log(`\n 연락처: ${parts.join(' | ')}`);
|
|
113
|
+
}
|
|
114
|
+
if (authorUsername) {
|
|
115
|
+
console.log(`\n \x1b[90m👤 프로필: relayax.com/@${authorUsername}\x1b[0m`);
|
|
116
|
+
}
|
|
117
|
+
if (team.latest_post && authorUsername) {
|
|
118
|
+
console.log(` \x1b[90m📝 활용 팁: relayax.com/@${authorUsername}/posts/${team.latest_post.slug}\x1b[0m`);
|
|
119
|
+
}
|
|
120
|
+
// Follow prompt (only when logged in)
|
|
121
|
+
const token = (0, config_js_1.loadToken)();
|
|
122
|
+
if (authorUsername && token) {
|
|
123
|
+
try {
|
|
124
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
125
|
+
const shouldFollow = await confirm({
|
|
126
|
+
message: `@${authorUsername}을 팔로우하시겠습니까? (이메일로 새 소식을 받습니다)`,
|
|
127
|
+
default: true,
|
|
128
|
+
});
|
|
129
|
+
if (shouldFollow) {
|
|
130
|
+
await (0, api_js_1.followBuilder)(authorUsername);
|
|
131
|
+
console.log(`\x1b[32m ✓ @${authorUsername} 팔로우 완료\x1b[0m`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// non-critical: skip on error or non-interactive terminal
|
|
136
|
+
}
|
|
137
|
+
}
|
|
96
138
|
console.log('\n 에이전트가 /relay-install로 환경을 구성합니다.');
|
|
97
139
|
}
|
|
98
140
|
}
|
package/dist/lib/api.d.ts
CHANGED
package/dist/lib/api.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.fetchTeamInfo = fetchTeamInfo;
|
|
|
4
4
|
exports.searchTeams = searchTeams;
|
|
5
5
|
exports.fetchTeamVersions = fetchTeamVersions;
|
|
6
6
|
exports.reportInstall = reportInstall;
|
|
7
|
+
exports.followBuilder = followBuilder;
|
|
7
8
|
const config_js_1 = require("./config.js");
|
|
8
9
|
async function fetchTeamInfo(slug) {
|
|
9
10
|
const url = `${config_js_1.API_URL}/api/registry/${slug}`;
|
|
@@ -42,3 +43,21 @@ async function reportInstall(slug) {
|
|
|
42
43
|
// non-critical: ignore errors
|
|
43
44
|
});
|
|
44
45
|
}
|
|
46
|
+
async function followBuilder(username) {
|
|
47
|
+
const token = (0, config_js_1.loadToken)();
|
|
48
|
+
const headers = {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
};
|
|
51
|
+
if (token) {
|
|
52
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
53
|
+
}
|
|
54
|
+
const res = await fetch(`https://www.relayax.com/api/follows`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers,
|
|
57
|
+
body: JSON.stringify({ following_username: username, email_opt_in: true }),
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) {
|
|
60
|
+
const body = await res.text();
|
|
61
|
+
throw new Error(`팔로우 실패 (${res.status}): ${body}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -300,13 +300,30 @@ requires:
|
|
|
300
300
|
- .relay/portfolio/cover.png에 저장합니다.
|
|
301
301
|
- 사용자에게 "이 cover를 사용할까요?" 확인. 직접 제공도 가능.
|
|
302
302
|
|
|
303
|
-
#### 슬롯 2: demo (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
-
|
|
303
|
+
#### 슬롯 2: demo (자동 생성 — 동작 시연)
|
|
304
|
+
에이전트가 **직접 팀의 커맨드를 실행하여** demo를 자동 생성합니다. 사용자에게 묻기 전에 먼저 만듭니다.
|
|
305
|
+
|
|
306
|
+
**생성 절차:**
|
|
307
|
+
1. .relay/commands/ 의 커맨드 목록을 읽고, 가장 대표적인 커맨드를 선택합니다.
|
|
308
|
+
2. 해당 커맨드를 예시 주제/데이터로 실행합니다.
|
|
309
|
+
- 콘텐츠 팀: "라즈베리파이5 신제품 소개" 같은 예시 주제로 커맨드 실행
|
|
310
|
+
- 크롤링 팀: 예시 URL로 실행하며 브라우저 동작을 녹화
|
|
311
|
+
- 분석 팀: 샘플 데이터로 실행하여 결과 캡처
|
|
312
|
+
3. 실행 결과물로 demo를 생성합니다:
|
|
313
|
+
- 여러 장 이미지 (카드뉴스 등): 슬라이드쇼 GIF (각 장 2초 간격)
|
|
314
|
+
- 브라우저 동작: 동작 녹화 GIF
|
|
315
|
+
- 단일 결과물: 결과 이미지를 demo로 사용
|
|
316
|
+
4. 생성된 demo를 사용자에게 보여줍니다: "이 demo를 사용할까요?"
|
|
317
|
+
- 수정 요청 가능: "다른 주제로 다시 만들어줘", "좀 더 짧게"
|
|
318
|
+
- 확정 시 .relay/portfolio/demo.gif에 저장
|
|
319
|
+
|
|
320
|
+
**예시 주제 선택 기준:**
|
|
321
|
+
- relay.yaml의 description, tags에서 도메인 힌트 추출
|
|
322
|
+
- 기존 output/에 결과물이 있으면 같은 주제 활용
|
|
323
|
+
- 없으면 팀 설명에서 가장 그럴듯한 예시 주제를 자체 생성
|
|
324
|
+
|
|
325
|
+
**GIF 규격:** 최대 5MB, .relay/portfolio/demo.gif
|
|
326
|
+
**대안:** 외부 영상 URL (YouTube, Loom)도 가능 — relay.yaml에 기록
|
|
310
327
|
|
|
311
328
|
#### 슬롯 3: gallery (선택 — 결과물 쇼케이스, 최대 5장)
|
|
312
329
|
- 규격: 800x600px 이하, WebP, 각 500KB 이하
|
package/dist/types.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface InstalledRegistry {
|
|
|
9
9
|
export interface TeamRegistryInfo {
|
|
10
10
|
slug: string;
|
|
11
11
|
name: string;
|
|
12
|
+
description?: string;
|
|
12
13
|
version: string;
|
|
13
14
|
package_url: string;
|
|
14
15
|
commands: {
|
|
@@ -20,7 +21,21 @@ export interface TeamRegistryInfo {
|
|
|
20
21
|
rules: number;
|
|
21
22
|
skills: number;
|
|
22
23
|
};
|
|
24
|
+
tags?: string[];
|
|
25
|
+
install_count?: number;
|
|
26
|
+
requires?: Record<string, unknown>;
|
|
23
27
|
visibility?: "public" | "login-only" | "invite-only";
|
|
28
|
+
welcome?: string | null;
|
|
29
|
+
contact?: Record<string, string> | null;
|
|
30
|
+
author?: {
|
|
31
|
+
username: string;
|
|
32
|
+
display_name: string | null;
|
|
33
|
+
contact_links: Record<string, string>;
|
|
34
|
+
} | null;
|
|
35
|
+
latest_post?: {
|
|
36
|
+
title: string;
|
|
37
|
+
slug: string;
|
|
38
|
+
} | null;
|
|
24
39
|
}
|
|
25
40
|
export interface SearchResult {
|
|
26
41
|
slug: string;
|