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.
Files changed (39) hide show
  1. package/dist/commands/package.js +0 -12
  2. package/dist/commands/publish.js +1 -38
  3. package/dist/index.js +0 -2
  4. package/dist/lib/ai-tools.d.ts +0 -16
  5. package/dist/lib/ai-tools.js +0 -34
  6. package/dist/lib/command-adapter.js +2 -34
  7. package/dist/lib/preamble.d.ts +2 -2
  8. package/dist/lib/preamble.js +3 -43
  9. package/dist/mcp/server.js +7 -677
  10. package/dist/prompts/create.md +3 -6
  11. package/dist/prompts/explore.md +2 -0
  12. package/package.json +1 -1
  13. package/dist/commands/export.d.ts +0 -2
  14. package/dist/commands/export.js +0 -106
  15. package/dist/commands/follow.d.ts +0 -2
  16. package/dist/commands/follow.js +0 -45
  17. package/dist/commands/invite.d.ts +0 -2
  18. package/dist/commands/invite.js +0 -135
  19. package/dist/commands/spaces.d.ts +0 -11
  20. package/dist/commands/spaces.js +0 -69
  21. package/dist/lib/config.js.bak +0 -75
  22. package/dist/lib/guide.d.ts +0 -12
  23. package/dist/lib/guide.js +0 -60
  24. package/dist/lib/manifest-generator.d.ts +0 -20
  25. package/dist/lib/manifest-generator.js +0 -144
  26. package/dist/lib/security-scan.d.ts +0 -19
  27. package/dist/lib/security-scan.js +0 -114
  28. package/dist/prompts/_business-card.md +0 -41
  29. package/dist/prompts/_guide-instruction.md +0 -2
  30. package/dist/prompts/_requirements-check.md +0 -59
  31. package/dist/prompts/_setup-cli.md +0 -36
  32. package/dist/prompts/_setup-environment.md +0 -75
  33. package/dist/prompts/_setup-login.md +0 -31
  34. package/dist/prompts/_setup-org.md +0 -25
  35. package/dist/prompts/business-card.md +0 -41
  36. package/dist/prompts/error-handling.md +0 -38
  37. package/dist/prompts/install.md +0 -178
  38. package/dist/prompts/publish.md +0 -505
  39. package/dist/prompts/requirements-check.md +0 -59
@@ -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
 
@@ -26,3 +26,5 @@
26
26
  scope 결정 기준:
27
27
  - 범용 도구 (코드 리뷰, 문서 생성, 테스트) → `relay install <slug>` (글로벌 기본)
28
28
  - 프로젝트 특화 (특정 프레임워크, 팀 컨벤션) → `relay install <slug> --local`
29
+
30
+ {{ERROR_HANDLING_GUIDE}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relayax-cli",
3
- "version": "0.4.25",
3
+ "version": "0.4.27",
4
4
  "description": "RelayAX Agent Team Marketplace CLI - Install and manage agent teams",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerExport(program: Command): void;
@@ -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
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerFollow(program: Command): void;
@@ -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
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerInvite(program: Command): void;
@@ -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;
@@ -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
- }
@@ -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
- }
@@ -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[];