relayax-cli 0.4.25 → 0.4.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.
- package/dist/commands/package.js +0 -12
- package/dist/commands/publish.js +1 -38
- package/dist/index.js +0 -2
- package/dist/lib/ai-tools.d.ts +0 -16
- package/dist/lib/ai-tools.js +0 -34
- package/dist/lib/command-adapter.js +2 -34
- package/dist/lib/preamble.d.ts +2 -2
- package/dist/lib/preamble.js +3 -43
- package/dist/mcp/server.js +7 -677
- package/dist/prompts/create.md +3 -6
- package/dist/prompts/explore.md +2 -0
- package/package.json +1 -1
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -106
- package/dist/commands/follow.d.ts +0 -2
- package/dist/commands/follow.js +0 -45
- package/dist/commands/invite.d.ts +0 -2
- package/dist/commands/invite.js +0 -135
- package/dist/commands/spaces.d.ts +0 -11
- package/dist/commands/spaces.js +0 -69
- package/dist/lib/config.js.bak +0 -75
- package/dist/lib/guide.d.ts +0 -12
- package/dist/lib/guide.js +0 -60
- package/dist/lib/manifest-generator.d.ts +0 -20
- package/dist/lib/manifest-generator.js +0 -144
- package/dist/lib/security-scan.d.ts +0 -19
- package/dist/lib/security-scan.js +0 -114
- package/dist/prompts/_business-card.md +0 -41
- package/dist/prompts/_guide-instruction.md +0 -2
- package/dist/prompts/_requirements-check.md +0 -59
- package/dist/prompts/_setup-cli.md +0 -36
- package/dist/prompts/_setup-environment.md +0 -75
- package/dist/prompts/_setup-login.md +0 -31
- package/dist/prompts/_setup-org.md +0 -25
- package/dist/prompts/business-card.md +0 -41
- package/dist/prompts/error-handling.md +0 -38
- package/dist/prompts/install.md +0 -178
- package/dist/prompts/publish.md +0 -505
- package/dist/prompts/requirements-check.md +0 -59
package/dist/prompts/create.md
CHANGED
|
@@ -29,7 +29,9 @@ relay.yaml이 없으면 새로 만들고, 있으면 변경사항을 반영합니
|
|
|
29
29
|
`.relay/relay.yaml`이 있는지 확인합니다.
|
|
30
30
|
|
|
31
31
|
- **없음** → 아래 "최초 생성" 플로우
|
|
32
|
-
- **있음** →
|
|
32
|
+
- **있음** → `relay package --json`으로 상태 확인
|
|
33
|
+
- `no_contents` 에러 → relay.yaml에 sources/contents가 없는 레거시 상태. `relay package --init --json`으로 소스를 스캔하고 relay.yaml에 sources를 추가한 뒤 "업데이트" 플로우 진행
|
|
34
|
+
- 정상 응답 → 아래 "업데이트" 플로우
|
|
33
35
|
|
|
34
36
|
---
|
|
35
37
|
|
|
@@ -150,11 +152,6 @@ relay.yaml이 없으면 새로 만들고, 있으면 변경사항을 반영합니
|
|
|
150
152
|
1. **배포 결과 요약** — slug, 버전, 공개 범위, URL
|
|
151
153
|
2. **설치 방법** — CLI 출력에 코드블록 형태로 이미 포함되어 있으므로, 그 내용을 사용자에게 안내합니다:
|
|
152
154
|
- CLI: `npx relayax-cli install {slug}`
|
|
153
|
-
- 출력에 `plugin_url`이 있으면 Claude Code Plugin (**두 명령을 순서대로 각각 실행**):
|
|
154
|
-
```
|
|
155
|
-
① /plugin marketplace add {pluginUrl}
|
|
156
|
-
② /plugin install {slug}
|
|
157
|
-
```
|
|
158
155
|
- 에이전트 소개 페이지 URL
|
|
159
156
|
3. **공유 텍스트** — CLI 출력의 공유 블록(┌─ ... ─┘)을 그대로 안내합니다. 팀에 바로 복붙할 수 있는 코드블록 형태입니다.
|
|
160
157
|
|
package/dist/prompts/explore.md
CHANGED
package/package.json
CHANGED
package/dist/commands/export.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerExport = registerExport;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
10
|
-
const manifest_generator_js_1 = require("../lib/manifest-generator.js");
|
|
11
|
-
const paths_js_1 = require("../lib/paths.js");
|
|
12
|
-
function registerExport(program) {
|
|
13
|
-
program
|
|
14
|
-
.command('export <platform>')
|
|
15
|
-
.description('로컬에서 플랫폼 네이티브 매니페스트를 생성합니다')
|
|
16
|
-
.option('--out <dir>', '출력 디렉토리 (기본: .relay/export/<platform>/)')
|
|
17
|
-
.option('--project <dir>', '프로젝트 루트 경로')
|
|
18
|
-
.action(async (platform, opts) => {
|
|
19
|
-
const json = program.opts().json ?? false;
|
|
20
|
-
const projectPath = (0, paths_js_1.resolveProjectPath)(opts.project);
|
|
21
|
-
const relayDir = path_1.default.join(projectPath, '.relay');
|
|
22
|
-
const relayYamlPath = path_1.default.join(relayDir, 'relay.yaml');
|
|
23
|
-
// Check relay.yaml exists
|
|
24
|
-
if (!fs_1.default.existsSync(relayYamlPath)) {
|
|
25
|
-
const msg = 'relay.yaml not found';
|
|
26
|
-
if (json) {
|
|
27
|
-
console.error(JSON.stringify({ error: 'NOT_FOUND', message: msg }));
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
console.error(`\x1b[31m${msg}\x1b[0m`);
|
|
31
|
-
console.error(' relay.yaml이 있는 에이전트 디렉토리에서 실행하세요.');
|
|
32
|
-
}
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
35
|
-
// Validate platform
|
|
36
|
-
const validPlatforms = [...manifest_generator_js_1.SUPPORTED_PLATFORMS, 'all'];
|
|
37
|
-
if (!validPlatforms.includes(platform)) {
|
|
38
|
-
const msg = `지원하지 않는 플랫폼: ${platform}`;
|
|
39
|
-
if (json) {
|
|
40
|
-
console.error(JSON.stringify({ error: 'INVALID_PLATFORM', message: msg, supported: manifest_generator_js_1.SUPPORTED_PLATFORMS }));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
console.error(`\x1b[31m${msg}\x1b[0m`);
|
|
44
|
-
console.error(` 지원 플랫폼: ${manifest_generator_js_1.SUPPORTED_PLATFORMS.join(', ')}, all`);
|
|
45
|
-
}
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
// Parse relay.yaml
|
|
49
|
-
const yamlContent = fs_1.default.readFileSync(relayYamlPath, 'utf-8');
|
|
50
|
-
const raw = js_yaml_1.default.load(yamlContent) ?? {};
|
|
51
|
-
const manifestYaml = {
|
|
52
|
-
name: String(raw.name ?? ''),
|
|
53
|
-
slug: String(raw.slug ?? ''),
|
|
54
|
-
description: String(raw.description ?? ''),
|
|
55
|
-
version: String(raw.version ?? '1.0.0'),
|
|
56
|
-
source: raw.source ? String(raw.source) : undefined,
|
|
57
|
-
org_slug: raw.org_slug ? String(raw.org_slug) : undefined,
|
|
58
|
-
platforms: platform === 'all' ? undefined : [platform],
|
|
59
|
-
};
|
|
60
|
-
// Generate manifests
|
|
61
|
-
const files = (0, manifest_generator_js_1.generateManifests)(manifestYaml, relayDir);
|
|
62
|
-
if (files.length === 0) {
|
|
63
|
-
if (json) {
|
|
64
|
-
console.log(JSON.stringify({ status: 'empty', message: '생성할 매니페스트가 없습니다.' }));
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
console.log('생성할 매니페스트가 없습니다.');
|
|
68
|
-
}
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
// Determine output directory
|
|
72
|
-
const outDir = opts.out
|
|
73
|
-
? path_1.default.resolve(opts.out)
|
|
74
|
-
: path_1.default.join(relayDir, 'export', platform);
|
|
75
|
-
fs_1.default.mkdirSync(outDir, { recursive: true });
|
|
76
|
-
// Write files
|
|
77
|
-
const written = [];
|
|
78
|
-
for (const file of files) {
|
|
79
|
-
const filePath = path_1.default.join(outDir, file.relativePath);
|
|
80
|
-
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
81
|
-
fs_1.default.writeFileSync(filePath, file.content);
|
|
82
|
-
written.push(file.relativePath);
|
|
83
|
-
}
|
|
84
|
-
if (json) {
|
|
85
|
-
console.log(JSON.stringify({ status: 'ok', platform, output_dir: outDir, files: written }));
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
console.log(`\n\x1b[32m✓ 매니페스트 생성 완료\x1b[0m (${platform})`);
|
|
89
|
-
console.log(` 출력: \x1b[36m${outDir}\x1b[0m\n`);
|
|
90
|
-
for (const f of written) {
|
|
91
|
-
console.log(` \x1b[90m•\x1b[0m ${f}`);
|
|
92
|
-
}
|
|
93
|
-
// Platform-specific usage hints
|
|
94
|
-
console.log('');
|
|
95
|
-
if (platform === 'claude-code' || platform === 'all') {
|
|
96
|
-
console.log(' \x1b[90mClaude Code:\x1b[0m /plugin marketplace add <marketplace.json URL>');
|
|
97
|
-
}
|
|
98
|
-
if (platform === 'codex' || platform === 'all') {
|
|
99
|
-
console.log(' \x1b[90mCodex:\x1b[0m .codex-plugin/plugin.json을 Codex에 등록하세요');
|
|
100
|
-
}
|
|
101
|
-
if (platform === 'antigravity' || platform === 'all') {
|
|
102
|
-
console.log(' \x1b[90mAntigravity:\x1b[0m .agent/skills/를 프로젝트에 복사하세요');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
package/dist/commands/follow.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerFollow = registerFollow;
|
|
4
|
-
const api_js_1 = require("../lib/api.js");
|
|
5
|
-
const config_js_1 = require("../lib/config.js");
|
|
6
|
-
function registerFollow(program) {
|
|
7
|
-
program
|
|
8
|
-
.command('follow <username>')
|
|
9
|
-
.description('빌더를 팔로우합니다 (새 버전 알림)')
|
|
10
|
-
.action(async (username) => {
|
|
11
|
-
const json = program.opts().json ?? false;
|
|
12
|
-
// Strip @ prefix if present
|
|
13
|
-
const cleanUsername = username.startsWith('@') ? username.slice(1) : username;
|
|
14
|
-
const token = await (0, config_js_1.getValidToken)();
|
|
15
|
-
if (!token) {
|
|
16
|
-
const msg = '로그인이 필요합니다. `relay login`을 먼저 실행하세요.';
|
|
17
|
-
if (json) {
|
|
18
|
-
console.log(JSON.stringify({ error: 'NO_TOKEN', message: msg, fix: 'relay login 실행 후 재시도하세요.' }));
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
console.error(msg);
|
|
22
|
-
}
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
await (0, api_js_1.followBuilder)(cleanUsername);
|
|
27
|
-
if (json) {
|
|
28
|
-
console.log(JSON.stringify({ ok: true, following: cleanUsername }));
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
console.log(`\x1b[32m✓ @${cleanUsername} 팔로우 완료\x1b[0m — 새 버전 알림을 받습니다.`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
36
|
-
if (json) {
|
|
37
|
-
console.log(JSON.stringify({ error: 'FOLLOW_FAILED', message, fix: 'username을 확인하거나 잠시 후 재시도하세요.' }));
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.error(`팔로우 실패: ${message}`);
|
|
41
|
-
}
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
package/dist/commands/invite.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerInvite = registerInvite;
|
|
4
|
-
const config_js_1 = require("../lib/config.js");
|
|
5
|
-
function registerInvite(program) {
|
|
6
|
-
const inviteCmd = program
|
|
7
|
-
.command('invite <slug>')
|
|
8
|
-
.description('invite-only 팀에 사용자를 초대합니다');
|
|
9
|
-
inviteCmd
|
|
10
|
-
.command('add <username>')
|
|
11
|
-
.description('사용자 초대')
|
|
12
|
-
.action(async (username) => {
|
|
13
|
-
const json = program.opts().json ?? false;
|
|
14
|
-
const slug = inviteCmd.args[0];
|
|
15
|
-
const token = (0, config_js_1.loadToken)();
|
|
16
|
-
if (!token) {
|
|
17
|
-
console.error(JSON.stringify({ error: 'NO_TOKEN', message: '인증이 필요합니다. `relay login`을 먼저 실행하세요.' }));
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const res = await fetch(`${config_js_1.API_URL}/api/teams/${slug}/invites`, {
|
|
22
|
-
method: 'POST',
|
|
23
|
-
headers: {
|
|
24
|
-
'Authorization': `Bearer ${token}`,
|
|
25
|
-
'Content-Type': 'application/json',
|
|
26
|
-
},
|
|
27
|
-
body: JSON.stringify({ username }),
|
|
28
|
-
});
|
|
29
|
-
const body = await res.json();
|
|
30
|
-
if (!res.ok) {
|
|
31
|
-
if (json) {
|
|
32
|
-
console.error(JSON.stringify(body));
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
console.error(`오류: ${body.message ?? '초대에 실패했습니다'}`);
|
|
36
|
-
}
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
if (json) {
|
|
40
|
-
console.log(JSON.stringify(body));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
console.log(`✓ @${username}을(를) ${slug}에 초대했습니다.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
48
|
-
console.error(JSON.stringify({ error: 'INVITE_FAILED', message }));
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
inviteCmd
|
|
53
|
-
.command('remove <username>')
|
|
54
|
-
.description('초대 취소')
|
|
55
|
-
.action(async (username) => {
|
|
56
|
-
const json = program.opts().json ?? false;
|
|
57
|
-
const slug = inviteCmd.args[0];
|
|
58
|
-
const token = (0, config_js_1.loadToken)();
|
|
59
|
-
if (!token) {
|
|
60
|
-
console.error(JSON.stringify({ error: 'NO_TOKEN', message: '인증이 필요합니다.' }));
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
try {
|
|
64
|
-
const res = await fetch(`${config_js_1.API_URL}/api/teams/${slug}/invites`, {
|
|
65
|
-
method: 'DELETE',
|
|
66
|
-
headers: {
|
|
67
|
-
'Authorization': `Bearer ${token}`,
|
|
68
|
-
'Content-Type': 'application/json',
|
|
69
|
-
},
|
|
70
|
-
body: JSON.stringify({ username }),
|
|
71
|
-
});
|
|
72
|
-
const body = await res.json();
|
|
73
|
-
if (!res.ok) {
|
|
74
|
-
if (json) {
|
|
75
|
-
console.error(JSON.stringify(body));
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
console.error(`오류: ${body.message ?? '초대 취소에 실패했습니다'}`);
|
|
79
|
-
}
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
if (json) {
|
|
83
|
-
console.log(JSON.stringify(body));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
console.log(`✓ @${username}의 초대를 취소했습니다.`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
91
|
-
console.error(JSON.stringify({ error: 'REVOKE_FAILED', message }));
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
inviteCmd
|
|
96
|
-
.command('list')
|
|
97
|
-
.description('초대 목록 조회')
|
|
98
|
-
.action(async () => {
|
|
99
|
-
const json = program.opts().json ?? false;
|
|
100
|
-
const slug = inviteCmd.args[0];
|
|
101
|
-
const token = (0, config_js_1.loadToken)();
|
|
102
|
-
if (!token) {
|
|
103
|
-
console.error(JSON.stringify({ error: 'NO_TOKEN', message: '인증이 필요합니다.' }));
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
106
|
-
try {
|
|
107
|
-
const res = await fetch(`${config_js_1.API_URL}/api/teams/${slug}/invites`, {
|
|
108
|
-
headers: { 'Authorization': `Bearer ${token}` },
|
|
109
|
-
});
|
|
110
|
-
const body = await res.json();
|
|
111
|
-
if (!res.ok) {
|
|
112
|
-
console.error(JSON.stringify(body));
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
const invites = body.invites ?? [];
|
|
116
|
-
if (json) {
|
|
117
|
-
console.log(JSON.stringify(body));
|
|
118
|
-
}
|
|
119
|
-
else if (invites.length === 0) {
|
|
120
|
-
console.log('초대된 사용자가 없습니다.');
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
console.log(`초대된 사용자 (${invites.length}명):`);
|
|
124
|
-
for (const inv of invites) {
|
|
125
|
-
console.log(` @${inv.profiles?.username ?? '(알 수 없음)'}`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
131
|
-
console.error(JSON.stringify({ error: 'LIST_FAILED', message }));
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
export interface SpaceInfo {
|
|
3
|
-
id: string;
|
|
4
|
-
slug: string;
|
|
5
|
-
name: string;
|
|
6
|
-
description: string | null;
|
|
7
|
-
join_policy?: string;
|
|
8
|
-
role: string;
|
|
9
|
-
}
|
|
10
|
-
export declare function fetchMySpaces(token: string): Promise<SpaceInfo[]>;
|
|
11
|
-
export declare function registerSpaces(program: Command): void;
|
package/dist/commands/spaces.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fetchMySpaces = fetchMySpaces;
|
|
4
|
-
exports.registerSpaces = registerSpaces;
|
|
5
|
-
const config_js_1 = require("../lib/config.js");
|
|
6
|
-
async function fetchMySpaces(token) {
|
|
7
|
-
const res = await fetch(`${config_js_1.API_URL}/api/spaces`, {
|
|
8
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
9
|
-
signal: AbortSignal.timeout(8000),
|
|
10
|
-
});
|
|
11
|
-
if (!res.ok) {
|
|
12
|
-
throw new Error(`Space 목록 조회 실패 (${res.status})`);
|
|
13
|
-
}
|
|
14
|
-
return (await res.json());
|
|
15
|
-
}
|
|
16
|
-
function registerSpaces(program) {
|
|
17
|
-
program
|
|
18
|
-
.command('spaces')
|
|
19
|
-
.description('내 Space 목록을 확인합니다')
|
|
20
|
-
.action(async () => {
|
|
21
|
-
const json = program.opts().json ?? false;
|
|
22
|
-
const token = await (0, config_js_1.getValidToken)();
|
|
23
|
-
if (!token) {
|
|
24
|
-
if (json) {
|
|
25
|
-
console.error(JSON.stringify({ error: 'LOGIN_REQUIRED', message: '로그인이 필요합니다. relay login을 먼저 실행하세요.', fix: 'relay login 실행 후 재시도하세요.' }));
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
console.error('\x1b[31m오류: 로그인이 필요합니다.\x1b[0m');
|
|
29
|
-
console.error(' relay login을 먼저 실행하세요.');
|
|
30
|
-
}
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
const spaces = await fetchMySpaces(token);
|
|
35
|
-
if (json) {
|
|
36
|
-
console.log(JSON.stringify({ spaces }));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
if (spaces.length === 0) {
|
|
40
|
-
console.log('\nSpace가 없습니다.');
|
|
41
|
-
console.log('\x1b[33m💡 Space를 만들려면: www.relayax.com/spaces/new\x1b[0m');
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.log(`\n\x1b[1m내 Space\x1b[0m (${spaces.length}개):\n`);
|
|
45
|
-
for (const s of spaces) {
|
|
46
|
-
const role = s.role === 'owner' ? '\x1b[33m소유자\x1b[0m'
|
|
47
|
-
: s.role === 'builder' ? '\x1b[36m빌더\x1b[0m'
|
|
48
|
-
: '\x1b[90m멤버\x1b[0m';
|
|
49
|
-
const desc = s.description
|
|
50
|
-
? ` \x1b[90m${s.description.length > 40 ? s.description.slice(0, 40) + '...' : s.description}\x1b[0m`
|
|
51
|
-
: '';
|
|
52
|
-
console.log(` \x1b[36m${s.slug}\x1b[0m \x1b[1m${s.name}\x1b[0m ${role}${desc}`);
|
|
53
|
-
}
|
|
54
|
-
console.log(`\n\x1b[33m💡 Space 팀 목록: relay list --space <slug>\x1b[0m`);
|
|
55
|
-
console.log(`\x1b[33m💡 비공개 배포: relay.yaml에 visibility: private 설정 후 relay publish\x1b[0m`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
60
|
-
if (json) {
|
|
61
|
-
console.error(JSON.stringify({ error: 'FETCH_FAILED', message, fix: '네트워크 연결을 확인하거나 잠시 후 재시도하세요.' }));
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
console.error(`\x1b[31m오류: ${message}\x1b[0m`);
|
|
65
|
-
}
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
package/dist/lib/config.js.bak
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.API_URL = void 0;
|
|
7
|
-
exports.getInstallPath = getInstallPath;
|
|
8
|
-
exports.ensureRelayDir = ensureRelayDir;
|
|
9
|
-
exports.loadToken = loadToken;
|
|
10
|
-
exports.saveToken = saveToken;
|
|
11
|
-
exports.loadInstalled = loadInstalled;
|
|
12
|
-
exports.saveInstalled = saveInstalled;
|
|
13
|
-
const fs_1 = __importDefault(require("fs"));
|
|
14
|
-
const path_1 = __importDefault(require("path"));
|
|
15
|
-
const os_1 = __importDefault(require("os"));
|
|
16
|
-
const ai_tools_js_1 = require("./ai-tools.js");
|
|
17
|
-
exports.API_URL = 'https://relayax.com';
|
|
18
|
-
const RELAY_DIR = path_1.default.join(os_1.default.homedir(), '.relay');
|
|
19
|
-
const INSTALLED_FILE = path_1.default.join(RELAY_DIR, 'installed.json');
|
|
20
|
-
/**
|
|
21
|
-
* 설치 경로를 결정한다.
|
|
22
|
-
* 1. --path 옵션이 있으면 그대로 사용
|
|
23
|
-
* 2. 에이전트 CLI 자동 감지 → 감지된 경로 사용
|
|
24
|
-
* 3. 감지 안 되면 현재 디렉토리에 직접 설치
|
|
25
|
-
*/
|
|
26
|
-
function getInstallPath(override) {
|
|
27
|
-
if (override) {
|
|
28
|
-
const resolved = override.startsWith('~')
|
|
29
|
-
? path_1.default.join(os_1.default.homedir(), override.slice(1))
|
|
30
|
-
: path_1.default.resolve(override);
|
|
31
|
-
return resolved;
|
|
32
|
-
}
|
|
33
|
-
const cwd = process.cwd();
|
|
34
|
-
const detected = (0, ai_tools_js_1.detectAgentCLIs)(cwd);
|
|
35
|
-
if (detected.length >= 1) {
|
|
36
|
-
return path_1.default.join(cwd, detected[0].skillsDir);
|
|
37
|
-
}
|
|
38
|
-
return cwd;
|
|
39
|
-
}
|
|
40
|
-
function ensureRelayDir() {
|
|
41
|
-
if (!fs_1.default.existsSync(RELAY_DIR)) {
|
|
42
|
-
fs_1.default.mkdirSync(RELAY_DIR, { recursive: true });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function loadToken() {
|
|
46
|
-
const tokenFile = path_1.default.join(RELAY_DIR, 'token');
|
|
47
|
-
if (!fs_1.default.existsSync(tokenFile))
|
|
48
|
-
return undefined;
|
|
49
|
-
try {
|
|
50
|
-
return fs_1.default.readFileSync(tokenFile, 'utf-8').trim() || undefined;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function saveToken(token) {
|
|
57
|
-
ensureRelayDir();
|
|
58
|
-
fs_1.default.writeFileSync(path_1.default.join(RELAY_DIR, 'token'), token);
|
|
59
|
-
}
|
|
60
|
-
function loadInstalled() {
|
|
61
|
-
if (!fs_1.default.existsSync(INSTALLED_FILE)) {
|
|
62
|
-
return {};
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const raw = fs_1.default.readFileSync(INSTALLED_FILE, 'utf-8');
|
|
66
|
-
return JSON.parse(raw);
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return {};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function saveInstalled(registry) {
|
|
73
|
-
ensureRelayDir();
|
|
74
|
-
fs_1.default.writeFileSync(INSTALLED_FILE, JSON.stringify(registry, null, 2));
|
|
75
|
-
}
|
package/dist/lib/guide.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Requires } from '../commands/publish.js';
|
|
2
|
-
interface CommandEntry {
|
|
3
|
-
name: string;
|
|
4
|
-
description: string;
|
|
5
|
-
}
|
|
6
|
-
export declare function generateGuide(config: {
|
|
7
|
-
slug: string;
|
|
8
|
-
name: string;
|
|
9
|
-
description: string;
|
|
10
|
-
version: string;
|
|
11
|
-
}, commands: CommandEntry[], requires?: Requires): string;
|
|
12
|
-
export {};
|
package/dist/lib/guide.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateGuide = generateGuide;
|
|
4
|
-
function buildRequiresSummary(requires) {
|
|
5
|
-
const lines = [];
|
|
6
|
-
for (const cli of requires.cli ?? []) {
|
|
7
|
-
const label = cli.required === false ? '선택' : '필수';
|
|
8
|
-
lines.push(`- cli: **${cli.name}** (${label})${cli.install ? ` — \`${cli.install}\`` : ''}`);
|
|
9
|
-
}
|
|
10
|
-
if (requires.npm && requires.npm.length > 0) {
|
|
11
|
-
const names = requires.npm.map((p) => typeof p === 'string' ? p : p.name);
|
|
12
|
-
lines.push(`- npm: ${names.map((n) => `**${n}**`).join(', ')}`);
|
|
13
|
-
}
|
|
14
|
-
for (const env of requires.env ?? []) {
|
|
15
|
-
const label = env.required === false ? '선택' : '필수';
|
|
16
|
-
const desc = env.description ? ` — ${env.description}` : '';
|
|
17
|
-
lines.push(`- env: **${env.name}** (${label})${desc}`);
|
|
18
|
-
}
|
|
19
|
-
for (const mcp of requires.mcp ?? []) {
|
|
20
|
-
const pkg = mcp.package ? ` — \`${mcp.package}\`` : '';
|
|
21
|
-
lines.push(`- mcp: **${mcp.name}**${pkg}`);
|
|
22
|
-
}
|
|
23
|
-
for (const agent of requires.agents ?? []) {
|
|
24
|
-
lines.push(`- agent: **${agent}**`);
|
|
25
|
-
}
|
|
26
|
-
return lines.join('\n');
|
|
27
|
-
}
|
|
28
|
-
function generateGuide(config, commands, requires) {
|
|
29
|
-
const scopedSlug = config.slug.startsWith('@') ? config.slug : `@${config.slug}`;
|
|
30
|
-
const installCmd = `npx relayax-cli install ${scopedSlug}`;
|
|
31
|
-
const requiresSummary = requires ? buildRequiresSummary(requires) : '';
|
|
32
|
-
const slugPart = scopedSlug.startsWith('@') ? scopedSlug.slice(1) : scopedSlug;
|
|
33
|
-
const pluginUrl = `https://www.relayax.com/api/registry/${slugPart}/plugin`;
|
|
34
|
-
return `# ${config.name}
|
|
35
|
-
|
|
36
|
-
> ${config.description}
|
|
37
|
-
|
|
38
|
-
## 설치
|
|
39
|
-
|
|
40
|
-
### CLI
|
|
41
|
-
\`\`\`bash
|
|
42
|
-
${installCmd}
|
|
43
|
-
\`\`\`
|
|
44
|
-
|
|
45
|
-
### Claude Code Plugin
|
|
46
|
-
\`\`\`
|
|
47
|
-
/plugin marketplace add ${pluginUrl}
|
|
48
|
-
/plugin install ${config.slug.split('/').pop() ?? config.slug}
|
|
49
|
-
\`\`\`
|
|
50
|
-
|
|
51
|
-
${commands.length > 0 ? `## 포함된 커맨드
|
|
52
|
-
|
|
53
|
-
${commands.map((cmd) => `- \`/${cmd.name}\`: ${cmd.description}`).join('\n')}
|
|
54
|
-
` : ''}${requiresSummary ? `## 요구사항
|
|
55
|
-
|
|
56
|
-
${requiresSummary}
|
|
57
|
-
` : ''}---
|
|
58
|
-
*https://relayax.com — Agent Marketplace*
|
|
59
|
-
`;
|
|
60
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface GeneratedFile {
|
|
2
|
-
relativePath: string;
|
|
3
|
-
content: string;
|
|
4
|
-
}
|
|
5
|
-
export interface ManifestRelayYaml {
|
|
6
|
-
name: string;
|
|
7
|
-
slug: string;
|
|
8
|
-
description: string;
|
|
9
|
-
version: string;
|
|
10
|
-
source?: string;
|
|
11
|
-
org_slug?: string;
|
|
12
|
-
platforms?: string[];
|
|
13
|
-
}
|
|
14
|
-
export declare const SUPPORTED_PLATFORMS: readonly ["claude-code", "codex", "antigravity"];
|
|
15
|
-
export type Platform = typeof SUPPORTED_PLATFORMS[number];
|
|
16
|
-
/**
|
|
17
|
-
* Generate platform-native manifests from relay.yaml metadata.
|
|
18
|
-
* Used by both `relay publish` and `relay export`.
|
|
19
|
-
*/
|
|
20
|
-
export declare function generateManifests(yaml: ManifestRelayYaml, agentDir: string): GeneratedFile[];
|