relayax-cli 0.4.30 → 0.4.32
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 +18 -12
- package/dist/commands/publish.js +14 -0
- package/dist/lib/setup-command.d.ts +6 -0
- package/dist/lib/setup-command.js +72 -0
- package/package.json +1 -1
package/dist/commands/install.js
CHANGED
|
@@ -209,7 +209,7 @@ function registerInstall(program) {
|
|
|
209
209
|
const detectedValues = new Set(detected.map((t) => t.value));
|
|
210
210
|
const { checkbox } = await import('@inquirer/prompts');
|
|
211
211
|
selectedTools = await checkbox({
|
|
212
|
-
message: '설치할 AI 도구를
|
|
212
|
+
message: '설치할 AI 도구를 선택하세요 (감지된 도구는 자동 선택됨)',
|
|
213
213
|
choices: ai_tools_js_1.AI_TOOLS.map((t) => ({
|
|
214
214
|
name: t.name,
|
|
215
215
|
value: t,
|
|
@@ -237,12 +237,12 @@ function registerInstall(program) {
|
|
|
237
237
|
}
|
|
238
238
|
else if (interactive) {
|
|
239
239
|
const { select } = await import('@inquirer/prompts');
|
|
240
|
-
const recommendLabel = defaultScope === 'global' ? '글로벌' : '
|
|
240
|
+
const recommendLabel = defaultScope === 'global' ? '글로벌' : '로컬';
|
|
241
241
|
scope = await select({
|
|
242
242
|
message: `설치 범위를 선택하세요 (제작자 권장: ${recommendLabel})`,
|
|
243
243
|
choices: [
|
|
244
|
-
{ name: '글로벌 (~/.relay/agents/) — 모든
|
|
245
|
-
{ name: '로컬 (./.relay/agents/) — 이 프로젝트에서만
|
|
244
|
+
{ name: '글로벌 (~/.relay/agents/) — 모든 프로젝트에서 사용', value: 'global' },
|
|
245
|
+
{ name: '로컬 (./.relay/agents/) — 이 프로젝트에서만 사용', value: 'local' },
|
|
246
246
|
],
|
|
247
247
|
default: defaultScope,
|
|
248
248
|
});
|
|
@@ -371,29 +371,35 @@ function registerInstall(program) {
|
|
|
371
371
|
console.log(` 위치: \x1b[36m${agentDir}\x1b[0m`);
|
|
372
372
|
console.log(` 범위: ${scopeLabel}`);
|
|
373
373
|
console.log(` 파일: ${fileCount}개, symlink: ${deploy.symlinks.length}개`);
|
|
374
|
-
|
|
374
|
+
const userCommands = resolvedAgent.commands.filter((c) => !c.name.startsWith('setup-'));
|
|
375
|
+
if (userCommands.length > 0) {
|
|
375
376
|
console.log('\n 포함된 커맨드:');
|
|
376
|
-
for (const cmd of
|
|
377
|
+
for (const cmd of userCommands) {
|
|
377
378
|
console.log(` \x1b[33m/${cmd.name}\x1b[0m - ${cmd.description}`);
|
|
378
379
|
}
|
|
379
380
|
}
|
|
380
|
-
// Usage hint (type-aware)
|
|
381
|
+
// Usage hint (type-aware, setup command 제외)
|
|
381
382
|
const agentType = resolvedAgent.type;
|
|
383
|
+
const mainCommand = userCommands[0];
|
|
382
384
|
if (agentType === 'passive') {
|
|
383
385
|
console.log(`\n\x1b[33m💡 자동 적용됩니다. 별도 실행 없이 동작합니다.\x1b[0m`);
|
|
384
386
|
}
|
|
385
|
-
else if (agentType === 'hybrid' &&
|
|
386
|
-
console.log(`\n\x1b[33m💡 자동 적용 + \x1b[1m/${
|
|
387
|
+
else if (agentType === 'hybrid' && mainCommand) {
|
|
388
|
+
console.log(`\n\x1b[33m💡 자동 적용 + \x1b[1m/${mainCommand.name}\x1b[0m\x1b[33m 으로 추가 기능을 사용할 수 있습니다.\x1b[0m`);
|
|
387
389
|
}
|
|
388
|
-
else if (
|
|
389
|
-
console.log(`\n\x1b[33m💡 사용법: \x1b[1m/${
|
|
390
|
+
else if (mainCommand) {
|
|
391
|
+
console.log(`\n\x1b[33m💡 사용법: \x1b[1m/${mainCommand.name}\x1b[0m`);
|
|
390
392
|
}
|
|
391
393
|
else {
|
|
392
394
|
console.log(`\n\x1b[33m💡 설치 완료! AI 에이전트에서 사용할 수 있습니다.\x1b[0m`);
|
|
393
395
|
}
|
|
394
|
-
// Requires check
|
|
396
|
+
// Requires check + setup CTA
|
|
395
397
|
const requiresResults = (0, installer_js_1.checkRequires)(agentDir);
|
|
396
398
|
(0, installer_js_1.printRequiresCheck)(requiresResults);
|
|
399
|
+
const setupCmd = resolvedAgent.commands.find((c) => c.name.startsWith('setup-'));
|
|
400
|
+
if (setupCmd && requiresResults.some((r) => r.status === 'missing' || r.status === 'warn')) {
|
|
401
|
+
console.log(`\n \x1b[36m👉 설정이 필요합니다: \x1b[1m/${setupCmd.name}\x1b[0m\x1b[36m 을 실행하세요\x1b[0m`);
|
|
402
|
+
}
|
|
397
403
|
}
|
|
398
404
|
}
|
|
399
405
|
catch (err) {
|
package/dist/commands/publish.js
CHANGED
|
@@ -15,6 +15,7 @@ const paths_js_1 = require("../lib/paths.js");
|
|
|
15
15
|
const error_report_js_1 = require("../lib/error-report.js");
|
|
16
16
|
const step_tracker_js_1 = require("../lib/step-tracker.js");
|
|
17
17
|
const git_operations_js_1 = require("../lib/git-operations.js");
|
|
18
|
+
const setup_command_js_1 = require("../lib/setup-command.js");
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
20
|
const cliPkg = require('../../package.json');
|
|
20
21
|
const VALID_DIRS = ['skills', 'agents', 'rules', 'commands', 'bin'];
|
|
@@ -680,6 +681,19 @@ function registerPublish(program) {
|
|
|
680
681
|
console.error(` → relay.yaml에 visibility: ${config.visibility} 저장됨 (${visLabelMap[config.visibility]})\n`);
|
|
681
682
|
}
|
|
682
683
|
}
|
|
684
|
+
// Generate setup command BEFORE detectCommands so it's included in metadata
|
|
685
|
+
{
|
|
686
|
+
const commandsDir = path_1.default.join(relayDir, 'commands');
|
|
687
|
+
if (!fs_1.default.existsSync(commandsDir)) {
|
|
688
|
+
fs_1.default.mkdirSync(commandsDir, { recursive: true });
|
|
689
|
+
}
|
|
690
|
+
const slugName = config.slug.split('/').pop() ?? config.name;
|
|
691
|
+
const setupContent = (0, setup_command_js_1.generateSetupCommand)(config.name, config.requires, slugName);
|
|
692
|
+
if (setupContent) {
|
|
693
|
+
const setupFileName = `setup-${slugName}.md`;
|
|
694
|
+
fs_1.default.writeFileSync(path_1.default.join(commandsDir, setupFileName), setupContent);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
683
697
|
const detectedCommands = detectCommands(relayDir);
|
|
684
698
|
const components = {
|
|
685
699
|
agents: countDir(relayDir, 'agents'),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Requires } from '../commands/publish.js';
|
|
2
|
+
/**
|
|
3
|
+
* relay.yaml의 requires를 기반으로 setup slash command .md 내용을 생성한다.
|
|
4
|
+
* requires가 없거나 빈 객체이면 null을 반환한다.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateSetupCommand(agentName: string, requires: Requires | undefined, mainCommandName?: string): string | null;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSetupCommand = generateSetupCommand;
|
|
4
|
+
/**
|
|
5
|
+
* relay.yaml의 requires를 기반으로 setup slash command .md 내용을 생성한다.
|
|
6
|
+
* requires가 없거나 빈 객체이면 null을 반환한다.
|
|
7
|
+
*/
|
|
8
|
+
function generateSetupCommand(agentName, requires, mainCommandName) {
|
|
9
|
+
if (!requires)
|
|
10
|
+
return null;
|
|
11
|
+
const sections = [];
|
|
12
|
+
// runtime
|
|
13
|
+
if (requires.runtime) {
|
|
14
|
+
const items = [];
|
|
15
|
+
if (requires.runtime.node)
|
|
16
|
+
items.push(`- Node.js \`>=${requires.runtime.node}\``);
|
|
17
|
+
if (requires.runtime.python)
|
|
18
|
+
items.push(`- Python \`>=${requires.runtime.python}\``);
|
|
19
|
+
if (items.length > 0) {
|
|
20
|
+
sections.push(`### 런타임\n${items.join('\n')}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// cli
|
|
24
|
+
if (requires.cli && requires.cli.length > 0) {
|
|
25
|
+
const items = requires.cli.map((c) => {
|
|
26
|
+
const req = c.required !== false ? '필수' : '선택';
|
|
27
|
+
const install = c.install ? ` — 설치: \`${c.install}\`` : '';
|
|
28
|
+
return `- \`${c.name}\` (${req})${install}`;
|
|
29
|
+
});
|
|
30
|
+
sections.push(`### CLI 도구\n${items.join('\n')}`);
|
|
31
|
+
}
|
|
32
|
+
// env
|
|
33
|
+
if (requires.env && requires.env.length > 0) {
|
|
34
|
+
const items = requires.env.map((e) => {
|
|
35
|
+
const req = e.required !== false ? '필수' : '선택';
|
|
36
|
+
const desc = e.description ? ` — ${e.description}` : '';
|
|
37
|
+
const hint = e.setup_hint ? `\n 설정 방법:\n${e.setup_hint.split('\n').map((l) => ` ${l}`).join('\n')}` : '';
|
|
38
|
+
return `- \`${e.name}\` (${req})${desc}${hint}`;
|
|
39
|
+
});
|
|
40
|
+
sections.push(`### 환경변수\n${items.join('\n')}`);
|
|
41
|
+
}
|
|
42
|
+
// npm
|
|
43
|
+
if (requires.npm && requires.npm.length > 0) {
|
|
44
|
+
const items = requires.npm.map((n) => {
|
|
45
|
+
const name = typeof n === 'string' ? n : n.name;
|
|
46
|
+
const req = typeof n === 'string' ? '필수' : (n.required !== false ? '필수' : '선택');
|
|
47
|
+
return `- \`${name}\` (${req})`;
|
|
48
|
+
});
|
|
49
|
+
sections.push(`### npm 패키지\n${items.join('\n')}`);
|
|
50
|
+
}
|
|
51
|
+
// mcp
|
|
52
|
+
if (requires.mcp && requires.mcp.length > 0) {
|
|
53
|
+
const items = requires.mcp.map((m) => {
|
|
54
|
+
const req = m.required !== false ? '필수' : '선택';
|
|
55
|
+
const pkg = m.package ? ` — 패키지: \`${m.package}\`` : '';
|
|
56
|
+
const envList = m.env && m.env.length > 0 ? `\n 필요한 환경변수: ${m.env.map((e) => `\`${e}\``).join(', ')}` : '';
|
|
57
|
+
const config = m.config ? `\n 설정: \`${JSON.stringify(m.config)}\`` : '';
|
|
58
|
+
return `- \`${m.name}\` MCP 서버 (${req})${pkg}${envList}${config}`;
|
|
59
|
+
});
|
|
60
|
+
sections.push(`### MCP 서버\n${items.join('\n')}`);
|
|
61
|
+
}
|
|
62
|
+
if (sections.length === 0)
|
|
63
|
+
return null;
|
|
64
|
+
const body = `# ${agentName} 설정 가이드
|
|
65
|
+
|
|
66
|
+
아래 요구사항을 각각 체크하고, 미충족 항목이 있으면 사용자가 설정할 수 있도록 안내하세요.
|
|
67
|
+
모든 항목이 충족될 때까지 멈추지 말고 끝까지 진행하세요.
|
|
68
|
+
${mainCommandName ? `\n모든 설정이 완료되면 \`/${mainCommandName}\`으로 에이전트를 사용할 수 있다고 안내하세요.` : ''}
|
|
69
|
+
|
|
70
|
+
${sections.join('\n\n')}`;
|
|
71
|
+
return `---\ndescription: ${agentName} 설정 가이드 — 필수 요구사항을 확인하고 설정합니다\n---\n\n${body}\n`;
|
|
72
|
+
}
|