relayax-cli 0.3.65 → 0.3.67
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.d.ts +1 -5
- package/dist/commands/init.js +28 -6
- package/dist/commands/install.js +146 -41
- package/dist/commands/publish.js +103 -74
- package/dist/commands/uninstall.js +20 -4
- package/dist/commands/update.js +67 -31
- package/dist/lib/command-adapter.js +8 -9
- package/dist/lib/guide.d.ts +0 -1
- package/dist/lib/guide.js +27 -77
- package/dist/lib/installer.d.ts +32 -0
- package/dist/lib/installer.js +265 -0
- package/dist/prompts/create.md +108 -0
- package/dist/prompts/explore.md +28 -0
- package/dist/prompts/index.d.ts +2 -7
- package/dist/prompts/index.js +4 -11
- package/dist/types.d.ts +3 -1
- package/package.json +1 -1
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
/**
|
|
3
|
-
* 글로벌 User 커맨드를 감지된 모든 에이전트 CLI에 설치한다.
|
|
4
|
-
* ~/{skillsDir}/commands/relay/ 에 설치.
|
|
5
|
-
* 기존 파일 중 현재 커맨드 목록에 없는 것은 제거한다.
|
|
6
|
-
*/
|
|
7
2
|
export declare function installGlobalUserCommands(): {
|
|
8
3
|
installed: boolean;
|
|
9
4
|
commands: string[];
|
|
10
5
|
tools: string[];
|
|
6
|
+
removed: string[];
|
|
11
7
|
};
|
|
12
8
|
/**
|
|
13
9
|
* 글로벌 User 커맨드가 이미 설치되어 있는지 확인한다.
|
package/dist/commands/init.js
CHANGED
|
@@ -36,10 +36,15 @@ function showWelcome() {
|
|
|
36
36
|
' 에이전트 CLI에 relay 커맨드를 연결합니다.',
|
|
37
37
|
'',
|
|
38
38
|
' \x1b[2mUser 커맨드 (글로벌)\x1b[0m',
|
|
39
|
-
' /relay-
|
|
40
|
-
' /relay-
|
|
39
|
+
' /relay-explore 에이전트 탐색 & 추천',
|
|
40
|
+
' /relay-create 에이전트 생성 & 배포',
|
|
41
|
+
' /relay-status 설치 현황 & Organization',
|
|
41
42
|
' /relay-uninstall 에이전트 삭제',
|
|
42
43
|
'',
|
|
44
|
+
' \x1b[2mCLI 명령어\x1b[0m',
|
|
45
|
+
' relay install 에이전트 설치 (CLI 한 줄 완결)',
|
|
46
|
+
' relay publish 재배포 (--patch/--minor/--major)',
|
|
47
|
+
'',
|
|
43
48
|
];
|
|
44
49
|
console.log(lines.join('\n'));
|
|
45
50
|
}
|
|
@@ -65,20 +70,28 @@ async function selectToolsInteractively(detectedIds) {
|
|
|
65
70
|
* ~/{skillsDir}/commands/relay/ 에 설치.
|
|
66
71
|
* 기존 파일 중 현재 커맨드 목록에 없는 것은 제거한다.
|
|
67
72
|
*/
|
|
73
|
+
/** 제거된 레거시 커맨드 → 대체 안내 매핑 */
|
|
74
|
+
const LEGACY_COMMANDS = {
|
|
75
|
+
'relay-install': 'relay install (CLI) 또는 /relay-explore',
|
|
76
|
+
'relay-publish': 'relay publish --patch (CLI) 또는 /relay-create',
|
|
77
|
+
};
|
|
68
78
|
function installGlobalUserCommands() {
|
|
69
79
|
const globalCLIs = (0, ai_tools_js_1.detectGlobalCLIs)();
|
|
70
80
|
const currentIds = new Set(command_adapter_js_1.USER_COMMANDS.map((c) => c.id));
|
|
71
81
|
const commands = [];
|
|
72
82
|
const tools = [];
|
|
73
|
-
|
|
83
|
+
const removed = [];
|
|
74
84
|
const targetDirs = globalCLIs.map((t) => ({ name: t.name, dir: (0, command_adapter_js_1.getGlobalCommandDirForTool)(t.skillsDir), getPath: (id) => (0, command_adapter_js_1.getGlobalCommandPathForTool)(t.skillsDir, id) }));
|
|
75
85
|
for (const target of targetDirs) {
|
|
76
86
|
fs_1.default.mkdirSync(target.dir, { recursive: true });
|
|
77
|
-
// 기존 파일 중 현재 목록에 없는 것 제거
|
|
87
|
+
// 기존 파일 중 현재 목록에 없는 것 제거 + 레거시 안내
|
|
78
88
|
for (const file of fs_1.default.readdirSync(target.dir)) {
|
|
79
89
|
const id = file.replace(/\.md$/, '');
|
|
80
90
|
if (!currentIds.has(id)) {
|
|
81
91
|
fs_1.default.unlinkSync(path_1.default.join(target.dir, file));
|
|
92
|
+
if (LEGACY_COMMANDS[id] && !removed.includes(id)) {
|
|
93
|
+
removed.push(id);
|
|
94
|
+
}
|
|
82
95
|
}
|
|
83
96
|
}
|
|
84
97
|
// 현재 커맨드 설치 (덮어쓰기)
|
|
@@ -87,11 +100,10 @@ function installGlobalUserCommands() {
|
|
|
87
100
|
}
|
|
88
101
|
tools.push(target.name);
|
|
89
102
|
}
|
|
90
|
-
// commands 목록은 한 번만
|
|
91
103
|
for (const cmd of command_adapter_js_1.USER_COMMANDS) {
|
|
92
104
|
commands.push(cmd.id);
|
|
93
105
|
}
|
|
94
|
-
return { installed: true, commands, tools };
|
|
106
|
+
return { installed: true, commands, tools, removed };
|
|
95
107
|
}
|
|
96
108
|
/**
|
|
97
109
|
* 글로벌 User 커맨드가 이미 설치되어 있는지 확인한다.
|
|
@@ -149,10 +161,12 @@ function registerInit(program) {
|
|
|
149
161
|
// ── 1. 글로벌 User 커맨드 설치 ──
|
|
150
162
|
let globalStatus = 'already';
|
|
151
163
|
let globalTools = [];
|
|
164
|
+
let removedCommands = [];
|
|
152
165
|
{
|
|
153
166
|
const result = installGlobalUserCommands();
|
|
154
167
|
globalStatus = hasGlobalUserCommands() ? 'updated' : 'installed';
|
|
155
168
|
globalTools = result.tools;
|
|
169
|
+
removedCommands = result.removed;
|
|
156
170
|
// Register relay-core in installed.json
|
|
157
171
|
const installed = (0, config_js_1.loadInstalled)();
|
|
158
172
|
installed['relay-core'] = {
|
|
@@ -245,6 +259,14 @@ function registerInit(program) {
|
|
|
245
259
|
}
|
|
246
260
|
else {
|
|
247
261
|
console.log(`\n\x1b[32m✓ relay 초기화 완료\x1b[0m\n`);
|
|
262
|
+
// 레거시 커맨드 마이그레이션 안내
|
|
263
|
+
if (removedCommands.length > 0) {
|
|
264
|
+
console.log(` \x1b[33m⚠ 변경된 커맨드:\x1b[0m`);
|
|
265
|
+
for (const id of removedCommands) {
|
|
266
|
+
console.log(` \x1b[31m✗ /${id}\x1b[0m → ${LEGACY_COMMANDS[id]}`);
|
|
267
|
+
}
|
|
268
|
+
console.log();
|
|
269
|
+
}
|
|
248
270
|
// 글로벌
|
|
249
271
|
{
|
|
250
272
|
const toolNames = globalTools.length > 0 ? globalTools.join(', ') : '(감지된 CLI 없음)';
|
package/dist/commands/install.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.registerInstall = registerInstall;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
8
9
|
const path_1 = __importDefault(require("path"));
|
|
9
10
|
const api_js_1 = require("../lib/api.js");
|
|
10
11
|
const storage_js_1 = require("../lib/storage.js");
|
|
@@ -15,11 +16,15 @@ const init_js_1 = require("./init.js");
|
|
|
15
16
|
const paths_js_1 = require("../lib/paths.js");
|
|
16
17
|
const error_report_js_1 = require("../lib/error-report.js");
|
|
17
18
|
const step_tracker_js_1 = require("../lib/step-tracker.js");
|
|
19
|
+
const installer_js_1 = require("../lib/installer.js");
|
|
18
20
|
function registerInstall(program) {
|
|
19
21
|
program
|
|
20
22
|
.command('install <slug>')
|
|
21
23
|
.description('에이전트 패키지를 .relay/agents/에 다운로드합니다')
|
|
22
24
|
.option('--join-code <code>', '초대 코드 (Organization 에이전트 설치 시 자동 가입)')
|
|
25
|
+
.option('--code <code>', '접근 코드 (private 에이전트 설치 시)')
|
|
26
|
+
.option('--global', '글로벌 설치 (홈 디렉토리)')
|
|
27
|
+
.option('--local', '로컬 설치 (프로젝트 디렉토리)')
|
|
23
28
|
.option('--project <dir>', '프로젝트 루트 경로 (기본: cwd, 환경변수: RELAY_PROJECT_PATH)')
|
|
24
29
|
.action(async (slugInput, _opts) => {
|
|
25
30
|
const json = program.opts().json ?? false;
|
|
@@ -45,6 +50,39 @@ function registerInstall(program) {
|
|
|
45
50
|
const actualSlugInput = versionMatch ? versionMatch[1] : slugInput;
|
|
46
51
|
parsed = await (0, slug_js_1.resolveSlug)(actualSlugInput);
|
|
47
52
|
slug = parsed.full;
|
|
53
|
+
// Helper: ensure a valid token exists, triggering auto-login in TTY if needed.
|
|
54
|
+
// Returns the token string or null if login failed / not available.
|
|
55
|
+
async function ensureToken() {
|
|
56
|
+
let token = await (0, config_js_1.getValidToken)();
|
|
57
|
+
if (!token) {
|
|
58
|
+
const isTTY = Boolean(process.stdin.isTTY);
|
|
59
|
+
if (isTTY && !json) {
|
|
60
|
+
console.error('\x1b[33m⚙ 이 에이전트는 로그인이 필요합니다. 로그인을 시작합니다...\x1b[0m');
|
|
61
|
+
const { runLogin } = await import('./login.js');
|
|
62
|
+
await runLogin();
|
|
63
|
+
token = await (0, config_js_1.getValidToken)();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return token ?? null;
|
|
67
|
+
}
|
|
68
|
+
// Pre-fetch auto-login: --join-code and --code always require auth.
|
|
69
|
+
if (_opts.joinCode || _opts.code) {
|
|
70
|
+
const token = await ensureToken();
|
|
71
|
+
if (!token) {
|
|
72
|
+
if (json) {
|
|
73
|
+
console.error(JSON.stringify({
|
|
74
|
+
error: 'LOGIN_REQUIRED',
|
|
75
|
+
slug,
|
|
76
|
+
message: '이 에이전트는 로그인이 필요합니다. relay login을 먼저 실행하세요.',
|
|
77
|
+
fix: 'relay login 실행 후 재시도하세요.',
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.error('\x1b[31m이 에이전트는 로그인이 필요합니다. relay login 을 먼저 실행하세요.\x1b[0m');
|
|
82
|
+
}
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
48
86
|
try {
|
|
49
87
|
agent = await (0, api_js_1.fetchAgentInfo)(slug);
|
|
50
88
|
}
|
|
@@ -64,15 +102,63 @@ function registerInstall(program) {
|
|
|
64
102
|
}
|
|
65
103
|
}
|
|
66
104
|
catch { /* ignore parse errors */ }
|
|
67
|
-
//
|
|
68
|
-
if (
|
|
105
|
+
// Task 2.1: --join-code provided and not yet a member → join org then retry
|
|
106
|
+
if (_opts.joinCode && membershipStatus !== 'member') {
|
|
107
|
+
if (!json) {
|
|
108
|
+
console.error('\x1b[33m⚙ 초대 코드로 Organization에 가입합니다...\x1b[0m');
|
|
109
|
+
}
|
|
110
|
+
const { joinOrg } = await import('./join.js');
|
|
111
|
+
await joinOrg(parsed.owner, _opts.joinCode);
|
|
112
|
+
agent = await (0, api_js_1.fetchAgentInfo)(slug);
|
|
113
|
+
}
|
|
114
|
+
// Task 2.2: --code provided and agent is private → claim access then retry
|
|
115
|
+
else if (_opts.code && (errorVisibility === 'private' || purchaseInfo)) {
|
|
116
|
+
if (!json) {
|
|
117
|
+
console.error('\x1b[33m⚙ 접근 코드로 에이전트 접근 권한을 요청합니다...\x1b[0m');
|
|
118
|
+
}
|
|
119
|
+
const token = await (0, config_js_1.getValidToken)();
|
|
120
|
+
if (!token) {
|
|
121
|
+
if (json) {
|
|
122
|
+
console.error(JSON.stringify({
|
|
123
|
+
error: 'LOGIN_REQUIRED',
|
|
124
|
+
slug,
|
|
125
|
+
message: '이 에이전트는 로그인이 필요합니다. relay login을 먼저 실행하세요.',
|
|
126
|
+
fix: 'relay login 실행 후 재시도하세요.',
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.error('\x1b[31m이 에이전트는 로그인이 필요합니다. relay login 을 먼저 실행하세요.\x1b[0m');
|
|
131
|
+
}
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
const claimRes = await fetch(`${config_js_1.API_URL}/api/agents/${slug}/claim-access`, {
|
|
135
|
+
method: 'POST',
|
|
136
|
+
headers: {
|
|
137
|
+
'Content-Type': 'application/json',
|
|
138
|
+
Authorization: `Bearer ${token}`,
|
|
139
|
+
},
|
|
140
|
+
body: JSON.stringify({ code: _opts.code }),
|
|
141
|
+
signal: AbortSignal.timeout(10000),
|
|
142
|
+
});
|
|
143
|
+
if (!claimRes.ok) {
|
|
144
|
+
const claimBody = (await claimRes.json().catch(() => ({})));
|
|
145
|
+
const claimErrCode = claimBody.error ?? String(claimRes.status);
|
|
146
|
+
if (claimErrCode === 'INVALID_LINK')
|
|
147
|
+
throw new Error('초대 링크가 유효하지 않거나 만료되었습니다.');
|
|
148
|
+
throw new Error(claimBody.message ?? `접근 권한 요청 실패 (${claimRes.status})`);
|
|
149
|
+
}
|
|
150
|
+
agent = await (0, api_js_1.fetchAgentInfo)(slug);
|
|
151
|
+
}
|
|
152
|
+
// No code provided: show appropriate error messages
|
|
153
|
+
else if (errorVisibility === 'private' || purchaseInfo) {
|
|
154
|
+
// Private agent: show purchase info + relay access hint
|
|
69
155
|
if (json) {
|
|
70
156
|
console.error(JSON.stringify({
|
|
71
157
|
error: 'ACCESS_REQUIRED',
|
|
72
158
|
message: '이 에이전트는 접근 권한이 필요합니다.',
|
|
73
159
|
slug,
|
|
74
160
|
purchase_info: purchaseInfo ?? null,
|
|
75
|
-
fix: '접근 링크 코드가 있으면: relay
|
|
161
|
+
fix: '접근 링크 코드가 있으면: relay install ' + slugInput + ' --code <코드>',
|
|
76
162
|
}));
|
|
77
163
|
}
|
|
78
164
|
else {
|
|
@@ -83,18 +169,18 @@ function registerInstall(program) {
|
|
|
83
169
|
if (purchaseInfo?.url) {
|
|
84
170
|
console.error(` \x1b[36m${purchaseInfo.url}\x1b[0m`);
|
|
85
171
|
}
|
|
86
|
-
console.error(`\n\x1b[33m접근 링크 코드가 있으면: relay
|
|
172
|
+
console.error(`\n\x1b[33m접근 링크 코드가 있으면: relay install ${slugInput} --code <코드>\x1b[0m`);
|
|
87
173
|
}
|
|
88
174
|
process.exit(1);
|
|
89
175
|
}
|
|
90
|
-
if (membershipStatus === 'member') {
|
|
176
|
+
else if (membershipStatus === 'member') {
|
|
91
177
|
// Member but no access to this specific agent
|
|
92
178
|
if (json) {
|
|
93
179
|
console.error(JSON.stringify({
|
|
94
180
|
error: 'NO_ACCESS',
|
|
95
181
|
message: '이 에이전트에 대한 접근 권한이 없습니다.',
|
|
96
182
|
slug,
|
|
97
|
-
fix: '이 에이전트의 접근 링크 코드가 있으면 `relay
|
|
183
|
+
fix: '이 에이전트의 접근 링크 코드가 있으면 `relay install ' + slugInput + ' --code <코드>`로 접근 권한을 얻으세요. 없으면 에이전트 제작자에게 문의하세요.',
|
|
98
184
|
}));
|
|
99
185
|
}
|
|
100
186
|
else {
|
|
@@ -108,12 +194,12 @@ function registerInstall(program) {
|
|
|
108
194
|
error: 'ACCESS_REQUIRED',
|
|
109
195
|
message: '이 에이전트는 접근 권한이 필요합니다.',
|
|
110
196
|
slug,
|
|
111
|
-
fix: '초대 코드가 있으면 `relay
|
|
197
|
+
fix: '초대 코드가 있으면 `relay install ' + slugInput + ' --join-code <코드>`로 가입하세요.',
|
|
112
198
|
}));
|
|
113
199
|
}
|
|
114
200
|
else {
|
|
115
201
|
console.error('\x1b[31m이 에이전트는 접근 권한이 필요합니다.\x1b[0m');
|
|
116
|
-
console.error('\x1b[33m초대 코드가 있으면 `relay
|
|
202
|
+
console.error('\x1b[33m초대 코드가 있으면 `relay install ' + slugInput + ' --join-code <코드>`로 가입하세요.\x1b[0m');
|
|
117
203
|
}
|
|
118
204
|
process.exit(1);
|
|
119
205
|
}
|
|
@@ -126,35 +212,32 @@ function registerInstall(program) {
|
|
|
126
212
|
throw new Error('에이전트 정보를 가져오지 못했습니다.');
|
|
127
213
|
// Re-bind as non-optional so TypeScript tracks the narrowing through nested scopes
|
|
128
214
|
let resolvedAgent = agent;
|
|
129
|
-
|
|
130
|
-
|
|
215
|
+
// Scope 자동결정: --global/--local 플래그 > agent_type 기반
|
|
216
|
+
const scope = _opts.global ? 'global'
|
|
217
|
+
: _opts.local ? 'local'
|
|
218
|
+
: resolvedAgent.type === 'passive' ? 'local'
|
|
219
|
+
: 'global';
|
|
220
|
+
const agentDir = scope === 'global'
|
|
221
|
+
? path_1.default.join(os_1.default.homedir(), '.relay', 'agents', parsed.owner, parsed.name)
|
|
222
|
+
: path_1.default.join(projectPath, '.relay', 'agents', parsed.owner, parsed.name);
|
|
223
|
+
// 2. Visibility check + auto-login (internal agents always require a token)
|
|
131
224
|
const visibility = resolvedAgent.visibility ?? 'public';
|
|
132
225
|
if (visibility === 'internal') {
|
|
133
|
-
|
|
226
|
+
const token = await ensureToken();
|
|
134
227
|
if (!token) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
228
|
+
if (json) {
|
|
229
|
+
console.error(JSON.stringify({
|
|
230
|
+
error: 'LOGIN_REQUIRED',
|
|
231
|
+
visibility,
|
|
232
|
+
slug,
|
|
233
|
+
message: '이 에이전트는 로그인이 필요합니다. relay login을 먼저 실행하세요.',
|
|
234
|
+
fix: 'relay login 실행 후 재시도하세요.',
|
|
235
|
+
}));
|
|
142
236
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
console.error(JSON.stringify({
|
|
146
|
-
error: 'LOGIN_REQUIRED',
|
|
147
|
-
visibility,
|
|
148
|
-
slug,
|
|
149
|
-
message: '이 에이전트는 로그인이 필요합니다. relay login을 먼저 실행하세요.',
|
|
150
|
-
fix: 'relay login 실행 후 재시도하세요.',
|
|
151
|
-
}));
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
console.error('\x1b[31m이 에이전트는 로그인이 필요합니다. relay login 을 먼저 실행하세요.\x1b[0m');
|
|
155
|
-
}
|
|
156
|
-
process.exit(1);
|
|
237
|
+
else {
|
|
238
|
+
console.error('\x1b[31m이 에이전트는 로그인이 필요합니다. relay login 을 먼저 실행하세요.\x1b[0m');
|
|
157
239
|
}
|
|
240
|
+
process.exit(1);
|
|
158
241
|
}
|
|
159
242
|
}
|
|
160
243
|
// 3. Download package (retry once if signed URL expired)
|
|
@@ -184,7 +267,13 @@ function registerInstall(program) {
|
|
|
184
267
|
await (0, storage_js_1.extractPackage)(tarPath, agentDir);
|
|
185
268
|
// 4.5. Inject preamble (update check) into SKILL.md and commands
|
|
186
269
|
(0, preamble_js_1.injectPreambleToAgent)(agentDir, slug);
|
|
187
|
-
// 5.
|
|
270
|
+
// 5. Deploy symlinks to detected AI tool directories
|
|
271
|
+
const deploy = (0, installer_js_1.deploySymlinks)(agentDir, scope, projectPath);
|
|
272
|
+
for (const w of deploy.warnings) {
|
|
273
|
+
if (!json)
|
|
274
|
+
console.error(`\x1b[33m${w}\x1b[0m`);
|
|
275
|
+
}
|
|
276
|
+
// 6. Count extracted files
|
|
188
277
|
function countFiles(dir) {
|
|
189
278
|
let count = 0;
|
|
190
279
|
if (!fs_1.default.existsSync(dir))
|
|
@@ -200,16 +289,26 @@ function registerInstall(program) {
|
|
|
200
289
|
return count;
|
|
201
290
|
}
|
|
202
291
|
const fileCount = countFiles(agentDir);
|
|
203
|
-
//
|
|
204
|
-
const
|
|
205
|
-
installed[slug] = {
|
|
292
|
+
// 7. Record in installed.json (scope-aware)
|
|
293
|
+
const installRecord = {
|
|
206
294
|
agent_id: resolvedAgent.id,
|
|
207
295
|
version: resolvedAgent.version,
|
|
208
296
|
installed_at: new Date().toISOString(),
|
|
209
297
|
files: [agentDir],
|
|
298
|
+
deploy_scope: scope,
|
|
299
|
+
deployed_symlinks: deploy.symlinks,
|
|
210
300
|
};
|
|
211
|
-
(
|
|
212
|
-
|
|
301
|
+
if (scope === 'global') {
|
|
302
|
+
const globalInstalled = (0, config_js_1.loadGlobalInstalled)();
|
|
303
|
+
globalInstalled[slug] = installRecord;
|
|
304
|
+
(0, config_js_1.saveGlobalInstalled)(globalInstalled);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
const installed = (0, config_js_1.loadInstalled)();
|
|
308
|
+
installed[slug] = installRecord;
|
|
309
|
+
(0, config_js_1.saveInstalled)(installed);
|
|
310
|
+
}
|
|
311
|
+
// 8. Report install + usage ping (non-blocking, agent_id 기반)
|
|
213
312
|
await (0, api_js_1.reportInstall)(resolvedAgent.id, slug, resolvedAgent.version);
|
|
214
313
|
(0, api_js_1.sendUsagePing)(resolvedAgent.id, slug, resolvedAgent.version);
|
|
215
314
|
const result = {
|
|
@@ -220,6 +319,8 @@ function registerInstall(program) {
|
|
|
220
319
|
commands: resolvedAgent.commands,
|
|
221
320
|
files: fileCount,
|
|
222
321
|
install_path: agentDir,
|
|
322
|
+
scope,
|
|
323
|
+
symlinks: deploy.symlinks,
|
|
223
324
|
author: resolvedAgent.author ? {
|
|
224
325
|
username: resolvedAgent.author.username,
|
|
225
326
|
display_name: resolvedAgent.author.display_name ?? null,
|
|
@@ -233,9 +334,11 @@ function registerInstall(program) {
|
|
|
233
334
|
else {
|
|
234
335
|
const authorUsername = resolvedAgent.author?.username;
|
|
235
336
|
const authorSuffix = authorUsername ? ` \x1b[90mby @${authorUsername}\x1b[0m` : '';
|
|
236
|
-
|
|
337
|
+
const scopeLabel = scope === 'global' ? '글로벌' : '로컬';
|
|
338
|
+
console.log(`\n\x1b[32m✓ ${resolvedAgent.name} 설치 완료\x1b[0m v${resolvedAgent.version}${authorSuffix}`);
|
|
237
339
|
console.log(` 위치: \x1b[36m${agentDir}\x1b[0m`);
|
|
238
|
-
console.log(`
|
|
340
|
+
console.log(` 범위: ${scopeLabel}`);
|
|
341
|
+
console.log(` 파일: ${fileCount}개, symlink: ${deploy.symlinks.length}개`);
|
|
239
342
|
if (resolvedAgent.commands.length > 0) {
|
|
240
343
|
console.log('\n 포함된 커맨드:');
|
|
241
344
|
for (const cmd of resolvedAgent.commands) {
|
|
@@ -256,7 +359,9 @@ function registerInstall(program) {
|
|
|
256
359
|
else {
|
|
257
360
|
console.log(`\n\x1b[33m💡 설치 완료! AI 에이전트에서 사용할 수 있습니다.\x1b[0m`);
|
|
258
361
|
}
|
|
259
|
-
|
|
362
|
+
// Requires check
|
|
363
|
+
const requiresResults = (0, installer_js_1.checkRequires)(agentDir);
|
|
364
|
+
(0, installer_js_1.printRequiresCheck)(requiresResults);
|
|
260
365
|
}
|
|
261
366
|
}
|
|
262
367
|
catch (err) {
|