relayax-cli 0.1.3 → 0.1.4
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/init.js +92 -105
- package/dist/commands/install.js +1 -1
- package/dist/lib/ai-tools.d.ts +14 -0
- package/dist/lib/ai-tools.js +45 -0
- package/dist/lib/command-adapter.d.ts +21 -0
- package/dist/lib/command-adapter.js +89 -0
- package/dist/lib/config.d.ts +4 -2
- package/dist/lib/config.js +11 -3
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -6,130 +6,117 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.registerInit = registerInit;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
function slugify(str) {
|
|
20
|
-
return str
|
|
21
|
-
.toLowerCase()
|
|
22
|
-
.replace(/[^a-z0-9-]/g, '-')
|
|
23
|
-
.replace(/-+/g, '-')
|
|
24
|
-
.replace(/^-|-$/g, '');
|
|
25
|
-
}
|
|
26
|
-
function toYaml(data) {
|
|
27
|
-
const lines = [
|
|
28
|
-
`name: "${data.name}"`,
|
|
29
|
-
`slug: "${data.slug}"`,
|
|
30
|
-
`description: "${data.description}"`,
|
|
31
|
-
`version: "${data.version}"`,
|
|
32
|
-
];
|
|
33
|
-
if (data.tags.length > 0) {
|
|
34
|
-
lines.push('tags:');
|
|
35
|
-
for (const tag of data.tags) {
|
|
36
|
-
lines.push(` - "${tag}"`);
|
|
37
|
-
}
|
|
9
|
+
const ai_tools_js_1 = require("../lib/ai-tools.js");
|
|
10
|
+
const command_adapter_js_1 = require("../lib/command-adapter.js");
|
|
11
|
+
const VALID_TEAM_DIRS = ['skills', 'agents', 'rules', 'commands'];
|
|
12
|
+
function resolveTools(toolsArg) {
|
|
13
|
+
const raw = toolsArg.trim().toLowerCase();
|
|
14
|
+
if (raw === 'all') {
|
|
15
|
+
return ai_tools_js_1.AI_TOOLS.map((t) => t.value);
|
|
38
16
|
}
|
|
39
|
-
|
|
40
|
-
|
|
17
|
+
const tokens = raw.split(',').map((t) => t.trim()).filter(Boolean);
|
|
18
|
+
const valid = new Set(ai_tools_js_1.AI_TOOLS.map((t) => t.value));
|
|
19
|
+
const invalid = tokens.filter((t) => !valid.has(t));
|
|
20
|
+
if (invalid.length > 0) {
|
|
21
|
+
throw new Error(`알 수 없는 도구: ${invalid.join(', ')}\n사용 가능: ${[...valid].join(', ')}`);
|
|
41
22
|
}
|
|
42
|
-
return
|
|
23
|
+
return tokens;
|
|
43
24
|
}
|
|
44
25
|
function registerInit(program) {
|
|
45
26
|
program
|
|
46
27
|
.command('init')
|
|
47
|
-
.description('
|
|
48
|
-
.option('--
|
|
49
|
-
.option('--slug <slug>', 'URL 슬러그')
|
|
50
|
-
.option('--description <desc>', '한 줄 설명')
|
|
28
|
+
.description('에이전트 CLI를 감지하고 relay 슬래시 커맨드를 설치합니다')
|
|
29
|
+
.option('--tools <tools>', '설치할 에이전트 CLI 지정 (all 또는 쉼표 구분)')
|
|
51
30
|
.action(async (opts) => {
|
|
52
31
|
const pretty = program.opts().pretty ?? false;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
console.log('\x1b[33m이미 초기화되어 있습니다.\x1b[0m relay.yaml이 존재합니다.');
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
console.log(JSON.stringify({ status: 'already_initialized', path: relayYamlPath }));
|
|
62
|
-
}
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
// Detect existing directories
|
|
66
|
-
const existing = DIRS.filter((d) => fs_1.default.existsSync(path_1.default.join(cwd, d)));
|
|
67
|
-
const missing = DIRS.filter((d) => !fs_1.default.existsSync(path_1.default.join(cwd, d)));
|
|
68
|
-
const dirName = path_1.default.basename(cwd);
|
|
69
|
-
const autoSlug = slugify(dirName);
|
|
70
|
-
let name;
|
|
71
|
-
let slug;
|
|
72
|
-
let description;
|
|
73
|
-
let tags = [];
|
|
74
|
-
if (opts.name && opts.slug && opts.description) {
|
|
75
|
-
// Non-interactive
|
|
76
|
-
name = opts.name;
|
|
77
|
-
slug = opts.slug;
|
|
78
|
-
description = opts.description;
|
|
32
|
+
const projectPath = process.cwd();
|
|
33
|
+
// 1. 에이전트 CLI 감지 또는 --tools 지정
|
|
34
|
+
let targetToolIds;
|
|
35
|
+
if (opts.tools) {
|
|
36
|
+
targetToolIds = resolveTools(opts.tools);
|
|
79
37
|
}
|
|
80
38
|
else {
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
39
|
+
const detected = (0, ai_tools_js_1.detectAgentCLIs)(projectPath);
|
|
40
|
+
if (detected.length === 0) {
|
|
41
|
+
const msg = '에이전트 CLI 디렉토리를 찾을 수 없습니다.\n' +
|
|
42
|
+
'프로젝트에 .claude/, .gemini/, .cursor/ 등이 있는지 확인하세요.\n' +
|
|
43
|
+
'또는 --tools 옵션으로 직접 지정할 수 있습니다.';
|
|
44
|
+
if (pretty) {
|
|
45
|
+
console.error(`\n\x1b[31m✗ ${msg}\x1b[0m`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error(JSON.stringify({ error: 'NO_AGENT_CLI', message: msg }));
|
|
86
49
|
}
|
|
87
|
-
|
|
50
|
+
process.exit(1);
|
|
88
51
|
}
|
|
89
|
-
|
|
90
|
-
slug = opts.slug ?? await prompt(rl, '슬러그', autoSlug);
|
|
91
|
-
description = opts.description ?? await prompt(rl, '한 줄 설명');
|
|
92
|
-
const tagsInput = await prompt(rl, '태그 (쉼표 구분)', '');
|
|
93
|
-
tags = tagsInput ? tagsInput.split(',').map((t) => t.trim()).filter(Boolean) : [];
|
|
94
|
-
rl.close();
|
|
52
|
+
targetToolIds = detected.map((t) => t.value);
|
|
95
53
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
54
|
+
// 2. 각 에이전트 CLI에 슬래시 커맨드 설치
|
|
55
|
+
const results = [];
|
|
56
|
+
for (const toolId of targetToolIds) {
|
|
57
|
+
const tool = ai_tools_js_1.AI_TOOLS.find((t) => t.value === toolId);
|
|
58
|
+
if (!tool)
|
|
59
|
+
continue;
|
|
60
|
+
const adapter = (0, command_adapter_js_1.createAdapter)(tool);
|
|
61
|
+
const installedCommands = [];
|
|
62
|
+
for (const cmd of command_adapter_js_1.RELAY_COMMANDS) {
|
|
63
|
+
const filePath = path_1.default.join(projectPath, adapter.getFilePath(cmd.id));
|
|
64
|
+
const fileContent = adapter.formatFile(cmd);
|
|
65
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
66
|
+
fs_1.default.writeFileSync(filePath, fileContent);
|
|
67
|
+
installedCommands.push(cmd.id);
|
|
68
|
+
}
|
|
69
|
+
results.push({ tool: tool.name, commands: installedCommands });
|
|
70
|
+
}
|
|
71
|
+
// 3. relay.yaml 생성 (팀 패키지 구조가 있는 경우)
|
|
72
|
+
const relayYamlPath = path_1.default.join(projectPath, 'relay.yaml');
|
|
73
|
+
let relayYamlStatus = 'skipped';
|
|
74
|
+
if (fs_1.default.existsSync(relayYamlPath)) {
|
|
75
|
+
relayYamlStatus = 'exists';
|
|
99
76
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
77
|
+
else {
|
|
78
|
+
const hasTeamDirs = VALID_TEAM_DIRS.some((d) => {
|
|
79
|
+
const dirPath = path_1.default.join(projectPath, d);
|
|
80
|
+
if (!fs_1.default.existsSync(dirPath))
|
|
81
|
+
return false;
|
|
82
|
+
return fs_1.default.readdirSync(dirPath).filter((f) => !f.startsWith('.')).length > 0;
|
|
83
|
+
});
|
|
84
|
+
if (hasTeamDirs) {
|
|
85
|
+
const dirName = path_1.default.basename(projectPath);
|
|
86
|
+
const yaml = [
|
|
87
|
+
`name: "${dirName}"`,
|
|
88
|
+
`slug: "${dirName}"`,
|
|
89
|
+
`description: ""`,
|
|
90
|
+
`version: "1.0.0"`,
|
|
91
|
+
`tags: []`,
|
|
92
|
+
].join('\n') + '\n';
|
|
93
|
+
fs_1.default.writeFileSync(relayYamlPath, yaml);
|
|
94
|
+
relayYamlStatus = 'created';
|
|
95
|
+
}
|
|
107
96
|
}
|
|
108
|
-
//
|
|
109
|
-
const yamlData = { name, slug, description, version: '1.0.0', tags };
|
|
110
|
-
fs_1.default.writeFileSync(relayYamlPath, toYaml(yamlData));
|
|
111
|
-
const result = {
|
|
112
|
-
status: 'ok',
|
|
113
|
-
slug,
|
|
114
|
-
name,
|
|
115
|
-
description,
|
|
116
|
-
existing_dirs: existing,
|
|
117
|
-
created_dirs: created,
|
|
118
|
-
};
|
|
97
|
+
// 4. 출력
|
|
119
98
|
if (pretty) {
|
|
120
|
-
console.log(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
99
|
+
console.log('\n\x1b[32m✓ relay 초기화 완료\x1b[0m\n');
|
|
100
|
+
for (const r of results) {
|
|
101
|
+
console.log(` \x1b[36m${r.tool}\x1b[0m`);
|
|
102
|
+
for (const cmd of r.commands) {
|
|
103
|
+
console.log(` /${cmd}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (relayYamlStatus === 'created') {
|
|
107
|
+
console.log(`\n relay.yaml 생성됨 (팀 패키지 구조 감지)`);
|
|
108
|
+
}
|
|
109
|
+
else if (relayYamlStatus === 'exists') {
|
|
110
|
+
console.log(`\n relay.yaml 이미 존재`);
|
|
125
111
|
}
|
|
126
|
-
console.log(
|
|
127
|
-
console.log('\n 다음 단계:');
|
|
128
|
-
console.log(' 1. skills/, commands/ 등에 파일 추가');
|
|
129
|
-
console.log(' 2. \x1b[36mrelay publish\x1b[0m 로 마켓에 배포');
|
|
112
|
+
console.log('\n IDE를 재시작하면 슬래시 커맨드가 활성화됩니다.');
|
|
130
113
|
}
|
|
131
114
|
else {
|
|
132
|
-
console.log(JSON.stringify(
|
|
115
|
+
console.log(JSON.stringify({
|
|
116
|
+
status: 'ok',
|
|
117
|
+
tools: results,
|
|
118
|
+
relay_yaml: relayYamlStatus,
|
|
119
|
+
}));
|
|
133
120
|
}
|
|
134
121
|
});
|
|
135
122
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -8,7 +8,7 @@ const config_js_1 = require("../lib/config.js");
|
|
|
8
8
|
function registerInstall(program) {
|
|
9
9
|
program
|
|
10
10
|
.command('install <slug>')
|
|
11
|
-
.description('에이전트 팀 설치 (
|
|
11
|
+
.description('에이전트 팀 설치 (감지된 에이전트 CLI에 설치)')
|
|
12
12
|
.option('--path <install_path>', '설치 경로 지정 (기본: ./.claude)')
|
|
13
13
|
.action(async (slug, opts) => {
|
|
14
14
|
const pretty = program.opts().pretty ?? false;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AITool {
|
|
2
|
+
name: string;
|
|
3
|
+
value: string;
|
|
4
|
+
skillsDir: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Agent Skills 표준을 지원하는 에이전트 CLI 목록.
|
|
8
|
+
* @fission-ai/openspec의 AI_TOOLS에서 차용.
|
|
9
|
+
*/
|
|
10
|
+
export declare const AI_TOOLS: AITool[];
|
|
11
|
+
/**
|
|
12
|
+
* 프로젝트 디렉토리에서 에이전트 CLI 디렉토리를 감지한다.
|
|
13
|
+
*/
|
|
14
|
+
export declare function detectAgentCLIs(projectPath: string): AITool[];
|
|
@@ -0,0 +1,45 @@
|
|
|
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.AI_TOOLS = void 0;
|
|
7
|
+
exports.detectAgentCLIs = detectAgentCLIs;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* Agent Skills 표준을 지원하는 에이전트 CLI 목록.
|
|
12
|
+
* @fission-ai/openspec의 AI_TOOLS에서 차용.
|
|
13
|
+
*/
|
|
14
|
+
exports.AI_TOOLS = [
|
|
15
|
+
{ name: 'Amazon Q Developer', value: 'amazon-q', skillsDir: '.amazonq' },
|
|
16
|
+
{ name: 'Antigravity', value: 'antigravity', skillsDir: '.agent' },
|
|
17
|
+
{ name: 'Auggie', value: 'auggie', skillsDir: '.augment' },
|
|
18
|
+
{ name: 'Claude Code', value: 'claude', skillsDir: '.claude' },
|
|
19
|
+
{ name: 'Cline', value: 'cline', skillsDir: '.cline' },
|
|
20
|
+
{ name: 'Codex', value: 'codex', skillsDir: '.codex' },
|
|
21
|
+
{ name: 'CodeBuddy', value: 'codebuddy', skillsDir: '.codebuddy' },
|
|
22
|
+
{ name: 'Continue', value: 'continue', skillsDir: '.continue' },
|
|
23
|
+
{ name: 'CoStrict', value: 'costrict', skillsDir: '.cospec' },
|
|
24
|
+
{ name: 'Crush', value: 'crush', skillsDir: '.crush' },
|
|
25
|
+
{ name: 'Cursor', value: 'cursor', skillsDir: '.cursor' },
|
|
26
|
+
{ name: 'Factory Droid', value: 'factory', skillsDir: '.factory' },
|
|
27
|
+
{ name: 'Gemini CLI', value: 'gemini', skillsDir: '.gemini' },
|
|
28
|
+
{ name: 'GitHub Copilot', value: 'github-copilot', skillsDir: '.github' },
|
|
29
|
+
{ name: 'iFlow', value: 'iflow', skillsDir: '.iflow' },
|
|
30
|
+
{ name: 'Kilo Code', value: 'kilocode', skillsDir: '.kilocode' },
|
|
31
|
+
{ name: 'Kiro', value: 'kiro', skillsDir: '.kiro' },
|
|
32
|
+
{ name: 'OpenCode', value: 'opencode', skillsDir: '.opencode' },
|
|
33
|
+
{ name: 'Pi', value: 'pi', skillsDir: '.pi' },
|
|
34
|
+
{ name: 'Qoder', value: 'qoder', skillsDir: '.qoder' },
|
|
35
|
+
{ name: 'Qwen Code', value: 'qwen', skillsDir: '.qwen' },
|
|
36
|
+
{ name: 'RooCode', value: 'roocode', skillsDir: '.roo' },
|
|
37
|
+
{ name: 'Trae', value: 'trae', skillsDir: '.trae' },
|
|
38
|
+
{ name: 'Windsurf', value: 'windsurf', skillsDir: '.windsurf' },
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* 프로젝트 디렉토리에서 에이전트 CLI 디렉토리를 감지한다.
|
|
42
|
+
*/
|
|
43
|
+
function detectAgentCLIs(projectPath) {
|
|
44
|
+
return exports.AI_TOOLS.filter((tool) => fs_1.default.existsSync(path_1.default.join(projectPath, tool.skillsDir)));
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AITool } from './ai-tools.js';
|
|
2
|
+
export interface CommandContent {
|
|
3
|
+
id: string;
|
|
4
|
+
description: string;
|
|
5
|
+
body: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ToolCommandAdapter {
|
|
8
|
+
toolId: string;
|
|
9
|
+
getFilePath(commandId: string): string;
|
|
10
|
+
formatFile(content: CommandContent): string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 기본 어댑터 — 대부분의 에이전트 CLI가 동일한 패턴 사용.
|
|
14
|
+
* {skillsDir}/commands/relay/{id}.md
|
|
15
|
+
*/
|
|
16
|
+
export declare function createAdapter(tool: AITool): ToolCommandAdapter;
|
|
17
|
+
/**
|
|
18
|
+
* relay 슬래시 커맨드 템플릿.
|
|
19
|
+
* CLI 명령어(원자적 API)를 조합하는 에이전트 워크플로우.
|
|
20
|
+
*/
|
|
21
|
+
export declare const RELAY_COMMANDS: CommandContent[];
|
|
@@ -0,0 +1,89 @@
|
|
|
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.RELAY_COMMANDS = void 0;
|
|
7
|
+
exports.createAdapter = createAdapter;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* 기본 어댑터 — 대부분의 에이전트 CLI가 동일한 패턴 사용.
|
|
11
|
+
* {skillsDir}/commands/relay/{id}.md
|
|
12
|
+
*/
|
|
13
|
+
function createAdapter(tool) {
|
|
14
|
+
return {
|
|
15
|
+
toolId: tool.value,
|
|
16
|
+
getFilePath(commandId) {
|
|
17
|
+
return path_1.default.join(tool.skillsDir, 'commands', 'relay', `${commandId}.md`);
|
|
18
|
+
},
|
|
19
|
+
formatFile(content) {
|
|
20
|
+
return `---\ndescription: ${content.description}\n---\n\n${content.body}\n`;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* relay 슬래시 커맨드 템플릿.
|
|
26
|
+
* CLI 명령어(원자적 API)를 조합하는 에이전트 워크플로우.
|
|
27
|
+
*/
|
|
28
|
+
exports.RELAY_COMMANDS = [
|
|
29
|
+
{
|
|
30
|
+
id: 'relay-explore',
|
|
31
|
+
description: 'relay 마켓플레이스를 탐색하고 프로젝트에 맞는 팀을 찾습니다',
|
|
32
|
+
body: `사용자의 요청이나 현재 프로젝트 맥락에 맞는 에이전트 팀을 relay 마켓플레이스에서 탐색합니다.
|
|
33
|
+
|
|
34
|
+
## 실행 방법
|
|
35
|
+
|
|
36
|
+
1. 사용자의 요청에서 키워드를 추출합니다. 명시적 키워드가 없으면 현재 프로젝트를 분석하여 적절한 검색어를 판단합니다.
|
|
37
|
+
2. \`relay search <keyword>\` 명령어를 실행합니다 (필요하면 여러 키워드로 반복).
|
|
38
|
+
3. 결과를 현재 프로젝트 맥락과 대조하여 가장 도움될 팀을 추천합니다:
|
|
39
|
+
- 팀 이름과 설명
|
|
40
|
+
- 제공하는 커맨드 목록
|
|
41
|
+
- 왜 이 팀이 지금 프로젝트에 맞는지 설명
|
|
42
|
+
4. 관심 있는 팀이 있다면 \`/relay-install <slug>\`로 바로 설치할 수 있다고 안내합니다.
|
|
43
|
+
|
|
44
|
+
## 예시
|
|
45
|
+
|
|
46
|
+
사용자: /relay-explore 콘텐츠 만들 수 있는 팀 있어?
|
|
47
|
+
→ relay search 콘텐츠 실행
|
|
48
|
+
→ 결과 해석: "contents-team이 카드뉴스, PDF, PPT를 만들 수 있어요"
|
|
49
|
+
→ 프로젝트 맥락 기반 추천
|
|
50
|
+
→ "/relay-install contents-team으로 설치할 수 있어요"`,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'relay-install',
|
|
54
|
+
description: 'relay 마켓플레이스에서 에이전트 팀을 설치합니다',
|
|
55
|
+
body: `요청된 에이전트 팀을 relay 마켓플레이스에서 다운로드하여 현재 프로젝트에 설치합니다.
|
|
56
|
+
|
|
57
|
+
## 실행 방법
|
|
58
|
+
|
|
59
|
+
1. \`relay install <slug> --pretty\` 명령어를 실행합니다.
|
|
60
|
+
2. 설치 결과를 확인합니다:
|
|
61
|
+
- 설치된 파일 수
|
|
62
|
+
- 사용 가능해진 커맨드 목록
|
|
63
|
+
3. 각 커맨드의 사용법을 간단히 안내합니다.
|
|
64
|
+
4. "바로 사용해볼까요?"라고 제안합니다.
|
|
65
|
+
5. 사용자가 원하면 첫 번째 커맨드를 실행해봅니다.
|
|
66
|
+
|
|
67
|
+
## 예시
|
|
68
|
+
|
|
69
|
+
사용자: /relay-install contents-team
|
|
70
|
+
→ relay install contents-team --pretty 실행
|
|
71
|
+
→ "설치 완료! 다음 커맨드를 사용할 수 있습니다:"
|
|
72
|
+
→ /cardnews - 카드뉴스 제작
|
|
73
|
+
→ /detailpage - 상세페이지 제작
|
|
74
|
+
→ "바로 /cardnews를 사용해볼까요?"`,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'relay-publish',
|
|
78
|
+
description: '현재 팀 패키지를 relay 마켓플레이스에 배포합니다',
|
|
79
|
+
body: `현재 디렉토리의 에이전트 팀을 relay 마켓플레이스에 배포합니다.
|
|
80
|
+
|
|
81
|
+
## 실행 방법
|
|
82
|
+
|
|
83
|
+
1. relay.yaml이 있는지 확인합니다. 없으면 사용자에게 팀 정보를 물어보고 생성합니다.
|
|
84
|
+
2. skills/, agents/, rules/, commands/ 디렉토리 구조를 확인합니다.
|
|
85
|
+
3. \`relay login\`으로 인증 상태를 확인합니다. 미인증이면 로그인을 안내합니다.
|
|
86
|
+
4. \`relay publish --pretty\` 명령어를 실행합니다.
|
|
87
|
+
5. 배포 결과와 마켓플레이스 URL을 보여줍니다.`,
|
|
88
|
+
},
|
|
89
|
+
];
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { InstalledRegistry } from '../types.js';
|
|
2
2
|
export declare const API_URL = "https://relayax.com";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* --path
|
|
4
|
+
* 설치 경로를 결정한다.
|
|
5
|
+
* 1. --path 옵션이 있으면 그대로 사용
|
|
6
|
+
* 2. 에이전트 CLI 자동 감지 → 감지된 경로 사용
|
|
7
|
+
* 3. 감지 안 되면 현재 디렉토리에 직접 설치
|
|
6
8
|
*/
|
|
7
9
|
export declare function getInstallPath(override?: string): string;
|
|
8
10
|
export declare function ensureRelayDir(): void;
|
package/dist/lib/config.js
CHANGED
|
@@ -13,12 +13,15 @@ exports.saveInstalled = saveInstalled;
|
|
|
13
13
|
const fs_1 = __importDefault(require("fs"));
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const os_1 = __importDefault(require("os"));
|
|
16
|
+
const ai_tools_js_1 = require("./ai-tools.js");
|
|
16
17
|
exports.API_URL = 'https://relayax.com';
|
|
17
18
|
const RELAY_DIR = path_1.default.join(os_1.default.homedir(), '.relay');
|
|
18
19
|
const INSTALLED_FILE = path_1.default.join(RELAY_DIR, 'installed.json');
|
|
19
20
|
/**
|
|
20
|
-
*
|
|
21
|
-
* --path
|
|
21
|
+
* 설치 경로를 결정한다.
|
|
22
|
+
* 1. --path 옵션이 있으면 그대로 사용
|
|
23
|
+
* 2. 에이전트 CLI 자동 감지 → 감지된 경로 사용
|
|
24
|
+
* 3. 감지 안 되면 현재 디렉토리에 직접 설치
|
|
22
25
|
*/
|
|
23
26
|
function getInstallPath(override) {
|
|
24
27
|
if (override) {
|
|
@@ -27,7 +30,12 @@ function getInstallPath(override) {
|
|
|
27
30
|
: path_1.default.resolve(override);
|
|
28
31
|
return resolved;
|
|
29
32
|
}
|
|
30
|
-
|
|
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;
|
|
31
39
|
}
|
|
32
40
|
function ensureRelayDir() {
|
|
33
41
|
if (!fs_1.default.existsSync(RELAY_DIR)) {
|