relayax-cli 0.2.30 → 0.2.34
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 +5 -4
- package/dist/commands/ping.js +6 -3
- package/dist/commands/publish.js +6 -3
- package/dist/commands/update.js +3 -2
- package/dist/lib/api.d.ts +2 -2
- package/dist/lib/api.js +22 -19
- package/dist/lib/command-adapter.js +59 -8
- package/dist/lib/version-check.js +4 -1
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/dist/commands/install.js
CHANGED
|
@@ -181,18 +181,19 @@ function registerInstall(program) {
|
|
|
181
181
|
return count;
|
|
182
182
|
}
|
|
183
183
|
const fileCount = countFiles(teamDir);
|
|
184
|
-
// 6. Record in installed.json (space_slug 포함)
|
|
184
|
+
// 6. Record in installed.json (team_id, space_slug 포함)
|
|
185
185
|
const installed = (0, config_js_1.loadInstalled)();
|
|
186
186
|
installed[slug] = {
|
|
187
|
+
team_id: team.id,
|
|
187
188
|
version: team.version,
|
|
188
189
|
installed_at: new Date().toISOString(),
|
|
189
190
|
files: [teamDir],
|
|
190
191
|
...(spaceTarget ? { space_slug: spaceTarget.spaceSlug } : {}),
|
|
191
192
|
};
|
|
192
193
|
(0, config_js_1.saveInstalled)(installed);
|
|
193
|
-
// 7. Report install + usage ping (non-blocking)
|
|
194
|
-
await (0, api_js_1.reportInstall)(slug, team.version);
|
|
195
|
-
(0, api_js_1.sendUsagePing)(slug, team.version);
|
|
194
|
+
// 7. Report install + usage ping (non-blocking, team_id 기반)
|
|
195
|
+
await (0, api_js_1.reportInstall)(team.id, slug, team.version);
|
|
196
|
+
(0, api_js_1.sendUsagePing)(team.id, slug, team.version);
|
|
196
197
|
const result = {
|
|
197
198
|
status: 'ok',
|
|
198
199
|
team: team.name,
|
package/dist/commands/ping.js
CHANGED
|
@@ -25,13 +25,16 @@ function registerPing(program) {
|
|
|
25
25
|
});
|
|
26
26
|
slug = match ?? slugInput;
|
|
27
27
|
}
|
|
28
|
-
// Resolve version from installed registry
|
|
28
|
+
// Resolve version and team_id from installed registry
|
|
29
29
|
const local = (0, config_js_1.loadInstalled)();
|
|
30
30
|
const global = (0, config_js_1.loadGlobalInstalled)();
|
|
31
31
|
const entry = local[slug] ?? global[slug];
|
|
32
32
|
const version = entry?.version;
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const teamId = entry?.team_id;
|
|
34
|
+
// Fire-and-forget ping (team_id 기반, 없으면 skip)
|
|
35
|
+
if (teamId) {
|
|
36
|
+
await (0, api_js_1.sendUsagePing)(teamId, slug, version);
|
|
37
|
+
}
|
|
35
38
|
if (!opts.quiet) {
|
|
36
39
|
console.log(`RELAY_READY: ${slug}`);
|
|
37
40
|
}
|
package/dist/commands/publish.js
CHANGED
|
@@ -249,10 +249,13 @@ function resolveLongDescription(teamDir, yamlValue) {
|
|
|
249
249
|
async function createTarball(teamDir) {
|
|
250
250
|
const tmpFile = path_1.default.join(os_1.default.tmpdir(), `relay-publish-${Date.now()}.tar.gz`);
|
|
251
251
|
const dirsToInclude = VALID_DIRS.filter((d) => fs_1.default.existsSync(path_1.default.join(teamDir, d)));
|
|
252
|
-
// Include
|
|
252
|
+
// Include root-level files if they exist
|
|
253
253
|
const entries = [...dirsToInclude];
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
const rootFiles = ['relay.yaml', 'GUIDE.html', 'SKILL.md'];
|
|
255
|
+
for (const file of rootFiles) {
|
|
256
|
+
if (fs_1.default.existsSync(path_1.default.join(teamDir, file))) {
|
|
257
|
+
entries.push(file);
|
|
258
|
+
}
|
|
256
259
|
}
|
|
257
260
|
await (0, tar_1.create)({
|
|
258
261
|
gzip: true,
|
package/dist/commands/update.js
CHANGED
|
@@ -67,6 +67,7 @@ function registerUpdate(program) {
|
|
|
67
67
|
const hadDeployedFiles = (currentEntry?.deployed_files?.length ?? 0) > 0;
|
|
68
68
|
// Update installed.json with new version
|
|
69
69
|
installed[slug] = {
|
|
70
|
+
team_id: team.id,
|
|
70
71
|
version: latestVersion,
|
|
71
72
|
installed_at: new Date().toISOString(),
|
|
72
73
|
files,
|
|
@@ -75,8 +76,8 @@ function registerUpdate(program) {
|
|
|
75
76
|
// Clear deployed_files — agent must re-deploy and call deploy-record
|
|
76
77
|
};
|
|
77
78
|
(0, config_js_1.saveInstalled)(installed);
|
|
78
|
-
// Report install (non-blocking)
|
|
79
|
-
await (0, api_js_1.reportInstall)(slug);
|
|
79
|
+
// Report install (non-blocking, team_id 기반)
|
|
80
|
+
await (0, api_js_1.reportInstall)(team.id, slug, latestVersion);
|
|
80
81
|
const result = {
|
|
81
82
|
status: 'updated',
|
|
82
83
|
slug,
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface TeamVersionInfo {
|
|
|
7
7
|
created_at: string;
|
|
8
8
|
}
|
|
9
9
|
export declare function fetchTeamVersions(slug: string): Promise<TeamVersionInfo[]>;
|
|
10
|
-
export declare function reportInstall(slug: string, version?: string): Promise<void>;
|
|
10
|
+
export declare function reportInstall(teamId: string, slug: string, version?: string): Promise<void>;
|
|
11
11
|
/**
|
|
12
12
|
* Space 팀 설치: 멤버십 검증 + install count 증가 + 팀 메타데이터 반환을 한 번에 처리.
|
|
13
13
|
* POST /api/spaces/{spaceSlug}/teams/{teamSlug}/install
|
|
@@ -19,5 +19,5 @@ export interface ResolvedSlug {
|
|
|
19
19
|
full: string;
|
|
20
20
|
}
|
|
21
21
|
export declare function resolveSlugFromServer(name: string): Promise<ResolvedSlug[]>;
|
|
22
|
-
export declare function sendUsagePing(slug: string, version?: string): Promise<void>;
|
|
22
|
+
export declare function sendUsagePing(teamId: string, slug: string, version?: string): Promise<void>;
|
|
23
23
|
export declare function followBuilder(username: string): Promise<void>;
|
package/dist/lib/api.js
CHANGED
|
@@ -42,26 +42,30 @@ async function fetchTeamVersions(slug) {
|
|
|
42
42
|
}
|
|
43
43
|
return res.json();
|
|
44
44
|
}
|
|
45
|
-
async function reportInstall(slug, version) {
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
if (version) {
|
|
51
|
-
headers['Content-Type'] = 'application/json';
|
|
45
|
+
async function reportInstall(teamId, slug, version) {
|
|
46
|
+
const url = `${config_js_1.API_URL}/api/teams/${teamId}/install`;
|
|
47
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
48
|
+
const body = { slug };
|
|
49
|
+
if (version)
|
|
52
50
|
body.version = version;
|
|
53
|
-
}
|
|
54
51
|
const token = await (0, config_js_1.getValidToken)();
|
|
55
52
|
if (token) {
|
|
56
53
|
headers['Authorization'] = `Bearer ${token}`;
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers,
|
|
59
|
+
body: JSON.stringify(body),
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
const text = await res.text().catch(() => '');
|
|
63
|
+
console.error(`\x1b[33m⚠ 설치 카운트 업데이트 실패 (${res.status}): ${text}\x1b[0m`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// network error: ignore silently
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
70
|
/**
|
|
67
71
|
* Space 팀 설치: 멤버십 검증 + install count 증가 + 팀 메타데이터 반환을 한 번에 처리.
|
|
@@ -97,15 +101,14 @@ async function resolveSlugFromServer(name) {
|
|
|
97
101
|
const data = (await res.json());
|
|
98
102
|
return data.results;
|
|
99
103
|
}
|
|
100
|
-
async function sendUsagePing(slug, version) {
|
|
101
|
-
const registrySlug = slug.startsWith('@') ? slug.slice(1) : slug;
|
|
104
|
+
async function sendUsagePing(teamId, slug, version) {
|
|
102
105
|
const { createHash } = await import('crypto');
|
|
103
106
|
const { hostname, userInfo } = await import('os');
|
|
104
107
|
const deviceHash = createHash('sha256')
|
|
105
108
|
.update(`${hostname()}:${userInfo().username}`)
|
|
106
109
|
.digest('hex');
|
|
107
|
-
const url = `${config_js_1.API_URL}/api/
|
|
108
|
-
const payload = { device_hash: deviceHash };
|
|
110
|
+
const url = `${config_js_1.API_URL}/api/teams/${teamId}/ping`;
|
|
111
|
+
const payload = { device_hash: deviceHash, slug };
|
|
109
112
|
if (version)
|
|
110
113
|
payload.installed_version = version;
|
|
111
114
|
const headers = { 'Content-Type': 'application/json' };
|
|
@@ -223,14 +223,65 @@ slug가 직접 주어지면 (\`/relay-install @alice/doc-writer\`) 이 단계를
|
|
|
223
223
|
relay deploy-record <slug> --scope <global|local> --files <배치된_파일1> <배치된_파일2> ...
|
|
224
224
|
\`\`\`
|
|
225
225
|
|
|
226
|
-
#### 2-5. Requirements
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
226
|
+
#### 2-5. Requirements 체크리스트 (필수 — 항목이 있으면 반드시 수행)
|
|
227
|
+
|
|
228
|
+
\`<install_path>/relay.yaml\`의 \`requires\` 섹션을 읽고, **각 항목을 하나씩 확인하여 체크리스트로 표시**합니다.
|
|
229
|
+
requires 섹션이 없거나 비어있으면 이 단계를 건너뜁니다.
|
|
230
|
+
|
|
231
|
+
**출력 형식** (반드시 이 형식으로 사용자에게 보여줍니다):
|
|
232
|
+
\`\`\`
|
|
233
|
+
📋 Requirements 확인
|
|
234
|
+
|
|
235
|
+
[runtime]
|
|
236
|
+
✅ Node.js >=18 — v20.11.0 확인됨
|
|
237
|
+
❌ Python >=3.10 — v3.8.5 (업그레이드 필요)
|
|
238
|
+
|
|
239
|
+
[cli]
|
|
240
|
+
✅ playwright — 설치됨
|
|
241
|
+
❌ ffmpeg — 미설치 → 설치 명령: brew install ffmpeg
|
|
242
|
+
|
|
243
|
+
[npm]
|
|
244
|
+
✅ sharp — 설치됨
|
|
245
|
+
❌ puppeteer — 미설치 → 설치 중...
|
|
246
|
+
|
|
247
|
+
[env]
|
|
248
|
+
✅ OPENAI_API_KEY — 설정됨
|
|
249
|
+
❌ SLACK_WEBHOOK_URL (선택) — 미설정. 알림 전송에 필요
|
|
250
|
+
|
|
251
|
+
[mcp]
|
|
252
|
+
⚙️ supabase — MCP 서버 설정 필요 (아래 안내 참고)
|
|
253
|
+
|
|
254
|
+
[teams]
|
|
255
|
+
✅ @alice/doc-writer — 이미 설치됨
|
|
256
|
+
📦 @bob/utils — 미설치 → 설치 중...
|
|
257
|
+
\`\`\`
|
|
258
|
+
|
|
259
|
+
**처리 규칙 (각 카테고리별):**
|
|
260
|
+
|
|
261
|
+
1. **runtime**: \`node --version\`, \`python3 --version\`으로 확인. 버전 미달이면 ❌ 표시 후 업그레이드 안내.
|
|
262
|
+
2. **cli**: \`which <name>\`으로 확인.
|
|
263
|
+
- 설치됨 → ✅
|
|
264
|
+
- 미설치 + \`install\` 필드 있음 → 사용자에게 설치할지 물어본 후 실행
|
|
265
|
+
- 미설치 + \`install\` 필드 없음 → ❌ 표시 후 수동 설치 안내
|
|
266
|
+
3. **npm**: \`npm list <package> 2>/dev/null\`으로 확인.
|
|
267
|
+
- 설치됨 → ✅
|
|
268
|
+
- 미설치 + required → \`npm install <package>\` 실행
|
|
269
|
+
- 미설치 + optional → ❌ 표시 후 안내만
|
|
270
|
+
4. **env**: \`echo $<NAME>\`으로 확인.
|
|
271
|
+
- 설정됨 → ✅
|
|
272
|
+
- 미설정 + required → ❌ 표시 후 \`description\`과 함께 설정 방법 안내
|
|
273
|
+
- 미설정 + optional → ⚠️ 표시 후 용도 안내
|
|
274
|
+
5. **mcp**: MCP 서버 설정이 필요한 경우 ⚙️ 표시 후 설정 방법을 상세히 안내.
|
|
275
|
+
- \`config\` 필드가 있으면 settings.json에 추가할 JSON 블록을 보여줍니다.
|
|
276
|
+
- \`env\` 필드가 있으면 필요한 환경변수도 함께 안내합니다.
|
|
277
|
+
6. **teams**: \`relay list --json\`으로 설치 여부 확인.
|
|
278
|
+
- 설치됨 → ✅
|
|
279
|
+
- 미설치 → \`relay install <@author/team> --json\` 실행하여 재귀 설치
|
|
280
|
+
|
|
281
|
+
**중요**: 모든 required 항목이 ❌인 경우, 체크리스트 끝에 경고를 표시합니다:
|
|
282
|
+
\`\`\`
|
|
283
|
+
⚠️ 필수 요구사항이 충족되지 않았습니다. 팀 기능이 제한될 수 있습니다.
|
|
284
|
+
\`\`\`
|
|
234
285
|
${LOGIN_JIT_GUIDE}
|
|
235
286
|
|
|
236
287
|
### Step 3. 완료 & 팔로우 제안
|
|
@@ -43,7 +43,10 @@ async function checkTeamVersion(slug, force) {
|
|
|
43
43
|
const team = await (0, api_js_1.fetchTeamInfo)(slug);
|
|
44
44
|
(0, update_cache_js_1.updateCacheTimestamp)(slug);
|
|
45
45
|
// Fire-and-forget usage ping (only when cache expired = actual API call happened)
|
|
46
|
-
|
|
46
|
+
const teamId = entry.team_id ?? team.id;
|
|
47
|
+
if (teamId) {
|
|
48
|
+
(0, api_js_1.sendUsagePing)(teamId, slug, entry.version);
|
|
49
|
+
}
|
|
47
50
|
if (team.version !== entry.version) {
|
|
48
51
|
return {
|
|
49
52
|
type: 'team',
|
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface ContactItem {
|
|
|
4
4
|
value: string;
|
|
5
5
|
}
|
|
6
6
|
export interface InstalledTeam {
|
|
7
|
+
/** team UUID — 설치 카운트/핑 등 서버 통신에 사용 */
|
|
8
|
+
team_id?: string;
|
|
7
9
|
version: string;
|
|
8
10
|
installed_at: string;
|
|
9
11
|
files: string[];
|
|
@@ -20,6 +22,8 @@ export interface InstalledRegistry {
|
|
|
20
22
|
[scopedSlug: string]: InstalledTeam;
|
|
21
23
|
}
|
|
22
24
|
export interface TeamRegistryInfo {
|
|
25
|
+
/** team UUID */
|
|
26
|
+
id: string;
|
|
23
27
|
/** scoped slug 포맷: "@owner/name" */
|
|
24
28
|
slug: string;
|
|
25
29
|
name: string;
|