anpm-io 1.0.0
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/README.md +174 -0
- package/dist/commands/access.d.ts +2 -0
- package/dist/commands/access.js +90 -0
- package/dist/commands/adopt.d.ts +2 -0
- package/dist/commands/adopt.js +177 -0
- package/dist/commands/changelog.d.ts +2 -0
- package/dist/commands/changelog.js +67 -0
- package/dist/commands/check-update.d.ts +2 -0
- package/dist/commands/check-update.js +76 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +84 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +227 -0
- package/dist/commands/deploy-record.d.ts +2 -0
- package/dist/commands/deploy-record.js +93 -0
- package/dist/commands/deploy.d.ts +2 -0
- package/dist/commands/deploy.js +284 -0
- package/dist/commands/diff.d.ts +2 -0
- package/dist/commands/diff.js +92 -0
- package/dist/commands/feedback.d.ts +2 -0
- package/dist/commands/feedback.js +71 -0
- package/dist/commands/grant.d.ts +33 -0
- package/dist/commands/grant.js +190 -0
- package/dist/commands/hub.d.ts +2 -0
- package/dist/commands/hub.js +171 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +172 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +626 -0
- package/dist/commands/join.d.ts +6 -0
- package/dist/commands/join.js +90 -0
- package/dist/commands/link.d.ts +2 -0
- package/dist/commands/link.js +112 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +144 -0
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.js +235 -0
- package/dist/commands/orgs.d.ts +10 -0
- package/dist/commands/orgs.js +128 -0
- package/dist/commands/outdated.d.ts +2 -0
- package/dist/commands/outdated.js +70 -0
- package/dist/commands/package.d.ts +57 -0
- package/dist/commands/package.js +569 -0
- package/dist/commands/ping.d.ts +2 -0
- package/dist/commands/ping.js +40 -0
- package/dist/commands/publish.d.ts +98 -0
- package/dist/commands/publish.js +899 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +249 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +57 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +159 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.js +132 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +171 -0
- package/dist/commands/versions.d.ts +2 -0
- package/dist/commands/versions.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +91 -0
- package/dist/lib/agent-status.d.ts +23 -0
- package/dist/lib/agent-status.js +127 -0
- package/dist/lib/ai-tools.d.ts +34 -0
- package/dist/lib/ai-tools.js +104 -0
- package/dist/lib/anpm-config.d.ts +39 -0
- package/dist/lib/anpm-config.js +112 -0
- package/dist/lib/api.d.ts +24 -0
- package/dist/lib/api.js +151 -0
- package/dist/lib/auto-detect.d.ts +30 -0
- package/dist/lib/auto-detect.js +112 -0
- package/dist/lib/cloud-providers/anthropic.d.ts +19 -0
- package/dist/lib/cloud-providers/anthropic.js +200 -0
- package/dist/lib/cloud-providers/package-mapper.d.ts +9 -0
- package/dist/lib/cloud-providers/package-mapper.js +34 -0
- package/dist/lib/cloud-providers/provider.d.ts +60 -0
- package/dist/lib/cloud-providers/provider.js +7 -0
- package/dist/lib/command-adapter.d.ts +41 -0
- package/dist/lib/command-adapter.js +188 -0
- package/dist/lib/config.d.ts +50 -0
- package/dist/lib/config.js +274 -0
- package/dist/lib/contact-format.d.ts +7 -0
- package/dist/lib/contact-format.js +23 -0
- package/dist/lib/device-hash.d.ts +1 -0
- package/dist/lib/device-hash.js +16 -0
- package/dist/lib/error-report.d.ts +5 -0
- package/dist/lib/error-report.js +28 -0
- package/dist/lib/git-installer.d.ts +16 -0
- package/dist/lib/git-installer.js +97 -0
- package/dist/lib/git-operations.d.ts +38 -0
- package/dist/lib/git-operations.js +183 -0
- package/dist/lib/hub-notify.d.ts +9 -0
- package/dist/lib/hub-notify.js +66 -0
- package/dist/lib/install-source.d.ts +33 -0
- package/dist/lib/install-source.js +98 -0
- package/dist/lib/installer.d.ts +40 -0
- package/dist/lib/installer.js +358 -0
- package/dist/lib/local-installer.d.ts +15 -0
- package/dist/lib/local-installer.js +73 -0
- package/dist/lib/lockfile.d.ts +13 -0
- package/dist/lib/lockfile.js +42 -0
- package/dist/lib/manifest.d.ts +65 -0
- package/dist/lib/manifest.js +113 -0
- package/dist/lib/migration.d.ts +10 -0
- package/dist/lib/migration.js +91 -0
- package/dist/lib/paths.d.ts +10 -0
- package/dist/lib/paths.js +22 -0
- package/dist/lib/preamble.d.ts +22 -0
- package/dist/lib/preamble.js +133 -0
- package/dist/lib/relay-config.d.ts +13 -0
- package/dist/lib/relay-config.js +46 -0
- package/dist/lib/requires-suggest.d.ts +23 -0
- package/dist/lib/requires-suggest.js +295 -0
- package/dist/lib/setup-command.d.ts +6 -0
- package/dist/lib/setup-command.js +72 -0
- package/dist/lib/slug.d.ts +24 -0
- package/dist/lib/slug.js +100 -0
- package/dist/lib/step-tracker.d.ts +8 -0
- package/dist/lib/step-tracker.js +28 -0
- package/dist/lib/storage.d.ts +6 -0
- package/dist/lib/storage.js +23 -0
- package/dist/lib/update-cache.d.ts +2 -0
- package/dist/lib/update-cache.js +51 -0
- package/dist/lib/version-check.d.ts +10 -0
- package/dist/lib/version-check.js +75 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +112 -0
- package/dist/postinstall.d.ts +8 -0
- package/dist/postinstall.js +41 -0
- package/dist/prompts/_error-handling.md +38 -0
- package/dist/prompts/create.md +170 -0
- package/dist/prompts/explore.md +30 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.js +22 -0
- package/dist/relay-compat.d.ts +2 -0
- package/dist/relay-compat.js +7 -0
- package/dist/types.d.ts +118 -0
- package/dist/types.js +2 -0
- package/package.json +51 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerConfig = registerConfig;
|
|
4
|
+
const anpm_config_js_1 = require("../lib/anpm-config.js");
|
|
5
|
+
function registerConfig(program) {
|
|
6
|
+
const configCmd = program
|
|
7
|
+
.command('config')
|
|
8
|
+
.description('Manage anpm CLI configuration');
|
|
9
|
+
configCmd
|
|
10
|
+
.command('get <key>')
|
|
11
|
+
.description('Get a config value')
|
|
12
|
+
.action((key) => {
|
|
13
|
+
const json = program.opts().json ?? false;
|
|
14
|
+
const config = (0, anpm_config_js_1.loadConfig)();
|
|
15
|
+
const value = config[key] ?? anpm_config_js_1.CONFIG_DEFAULTS[key];
|
|
16
|
+
if (json) {
|
|
17
|
+
console.log(JSON.stringify({ key, value: value ?? null }));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.log(value ?? `(not set, default: ${anpm_config_js_1.CONFIG_DEFAULTS[key] ?? 'none'})`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
configCmd
|
|
24
|
+
.command('set <key> <value>')
|
|
25
|
+
.description('Set a config value (supports dot notation: provider.anthropic.api-key)')
|
|
26
|
+
.action((key, value) => {
|
|
27
|
+
const json = program.opts().json ?? false;
|
|
28
|
+
// Support dot-notation for nested keys
|
|
29
|
+
if (key.startsWith('provider.')) {
|
|
30
|
+
(0, anpm_config_js_1.setNestedConfigKey)(key, value);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const config = (0, anpm_config_js_1.loadConfig)();
|
|
34
|
+
config[key] = value;
|
|
35
|
+
(0, anpm_config_js_1.saveConfig)(config);
|
|
36
|
+
}
|
|
37
|
+
if (json) {
|
|
38
|
+
console.log(JSON.stringify({ status: 'ok', key, value }));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log(`\x1b[32m✓\x1b[0m ${key} = ${value}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
configCmd
|
|
45
|
+
.command('delete <key>')
|
|
46
|
+
.description('Delete a config value (restore default)')
|
|
47
|
+
.action((key) => {
|
|
48
|
+
const json = program.opts().json ?? false;
|
|
49
|
+
(0, anpm_config_js_1.deleteConfigKey)(key);
|
|
50
|
+
if (json) {
|
|
51
|
+
console.log(JSON.stringify({ status: 'ok', key, deleted: true }));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log(`\x1b[32m✓\x1b[0m ${key} deleted (restored to default)`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
configCmd
|
|
58
|
+
.command('list')
|
|
59
|
+
.description('Show all config values')
|
|
60
|
+
.action(() => {
|
|
61
|
+
const json = program.opts().json ?? false;
|
|
62
|
+
const config = (0, anpm_config_js_1.loadConfig)();
|
|
63
|
+
const merged = { ...anpm_config_js_1.CONFIG_DEFAULTS, ...config };
|
|
64
|
+
if (json) {
|
|
65
|
+
console.log(JSON.stringify(merged));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
69
|
+
if (key === 'providers' && typeof value === 'object' && value) {
|
|
70
|
+
for (const [prov, pConfig] of Object.entries(value)) {
|
|
71
|
+
for (const [pk, pv] of Object.entries(pConfig ?? {})) {
|
|
72
|
+
const display = pk.includes('key') ? (0, anpm_config_js_1.maskApiKey)(String(pv)) : pv;
|
|
73
|
+
console.log(` provider.${prov}.${pk} = ${display}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const isDefault = !(key in config);
|
|
79
|
+
const suffix = isDefault ? ' \x1b[90m(default)\x1b[0m' : '';
|
|
80
|
+
console.log(` ${key} = ${value}${suffix}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
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.registerCreate = registerCreate;
|
|
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 ai_tools_js_1 = require("../lib/ai-tools.js");
|
|
11
|
+
const step_tracker_js_1 = require("../lib/step-tracker.js");
|
|
12
|
+
const command_adapter_js_1 = require("../lib/command-adapter.js");
|
|
13
|
+
const init_js_1 = require("./init.js");
|
|
14
|
+
const slug_js_1 = require("../lib/slug.js");
|
|
15
|
+
const paths_js_1 = require("../lib/paths.js");
|
|
16
|
+
const DEFAULT_DIRS = ['.anpm/skills', '.anpm/commands'];
|
|
17
|
+
/**
|
|
18
|
+
* 글로벌 User 커맨드가 없으면 설치한다.
|
|
19
|
+
*/
|
|
20
|
+
function ensureGlobalUserCommands() {
|
|
21
|
+
if ((0, init_js_1.hasGlobalUserCommands)())
|
|
22
|
+
return false;
|
|
23
|
+
(0, init_js_1.installGlobalUserCommands)();
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
function registerCreate(program) {
|
|
27
|
+
program
|
|
28
|
+
.command('create <name>')
|
|
29
|
+
.description('새 에이전트 프로젝트를 생성합니다')
|
|
30
|
+
.option('--description <desc>', '에이전트 설명')
|
|
31
|
+
.option('--slug <slug>', 'URL용 식별자 (영문 소문자, 숫자, 하이픈)')
|
|
32
|
+
.option('--tags <tags>', '태그 (쉼표 구분)')
|
|
33
|
+
.option('--visibility <visibility>', '공개 범위 (public, private, internal)')
|
|
34
|
+
.option('--project <dir>', '프로젝트 루트 경로 (기본: cwd, 환경변수: RELAY_PROJECT_PATH)')
|
|
35
|
+
.action(async (name, opts) => {
|
|
36
|
+
const json = program.opts().json ?? false;
|
|
37
|
+
(0, step_tracker_js_1.trackCommand)('create');
|
|
38
|
+
const projectPath = (0, paths_js_1.resolveProjectPath)(opts.project);
|
|
39
|
+
const relayDir = path_1.default.join(projectPath, '.anpm');
|
|
40
|
+
const relayYamlPath = path_1.default.join(relayDir, 'anpm.yaml');
|
|
41
|
+
const isTTY = Boolean(process.stdin.isTTY) && !json;
|
|
42
|
+
// 1. .anpm/anpm.yaml 이미 존재하면 에러
|
|
43
|
+
if (fs_1.default.existsSync(relayYamlPath)) {
|
|
44
|
+
if (json) {
|
|
45
|
+
console.error(JSON.stringify({ error: 'ALREADY_EXISTS', message: '.anpm/anpm.yaml이 이미 존재합니다.', fix: '기존 .anpm/anpm.yaml을 확인하세요. 새로 시작하려면 삭제 후 재시도.' }));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error('.anpm/anpm.yaml이 이미 존재합니다. 기존 에이전트 프로젝트에서는 `anpm init`을 사용하세요.');
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
// 2. 메타데이터 수집
|
|
53
|
+
let slug = opts.slug ?? (0, slug_js_1.slugify)(name);
|
|
54
|
+
let description = opts.description ?? '';
|
|
55
|
+
let tags = opts.tags ? opts.tags.split(',').map((t) => t.trim()).filter(Boolean) : [];
|
|
56
|
+
let visibility = opts.visibility ?? 'public';
|
|
57
|
+
if (json) {
|
|
58
|
+
// --json 모드: slug가 비어있으면 에러
|
|
59
|
+
if (!slug) {
|
|
60
|
+
console.error(JSON.stringify({
|
|
61
|
+
error: 'INVALID_SLUG',
|
|
62
|
+
message: '이름에서 유효한 slug를 생성할 수 없습니다. 영문 이름을 사용하거나 --slug 옵션을 지정하세요.',
|
|
63
|
+
fix: `anpm create "${name}" --slug <영문-slug> --description <설명> --json`,
|
|
64
|
+
}));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
// --json 모드: 필수 값 부족 시 에러 반환 (프롬프트 없음)
|
|
68
|
+
if (!opts.description) {
|
|
69
|
+
console.error(JSON.stringify({
|
|
70
|
+
error: 'MISSING_FIELD',
|
|
71
|
+
message: '에이전트 설명이 필요합니다.',
|
|
72
|
+
fix: `relay create ${name} --description <설명> --json`,
|
|
73
|
+
field: 'description',
|
|
74
|
+
}));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
if (!opts.visibility) {
|
|
78
|
+
console.error(JSON.stringify({
|
|
79
|
+
error: 'MISSING_VISIBILITY',
|
|
80
|
+
message: '공개 범위를 선택하세요.',
|
|
81
|
+
fix: `relay create ${name} --description "${description}" --visibility <visibility> --json`,
|
|
82
|
+
options: [
|
|
83
|
+
{ value: 'public', label: '공개 — 누구나 검색 및 설치 가능' },
|
|
84
|
+
{ value: 'private', label: '비공개 — 허가 코드 등록자만 사용 가능' },
|
|
85
|
+
{ value: 'internal', label: '내부 — 조직 내의 누구나 사용 가능' },
|
|
86
|
+
],
|
|
87
|
+
}));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
if (!['public', 'private', 'internal'].includes(opts.visibility)) {
|
|
91
|
+
console.error(JSON.stringify({
|
|
92
|
+
error: 'INVALID_FIELD',
|
|
93
|
+
message: `유효하지 않은 visibility 값: ${opts.visibility}`,
|
|
94
|
+
fix: `visibility는 public, private, internal 중 하나여야 합니다.`,
|
|
95
|
+
options: [
|
|
96
|
+
{ value: 'public', label: '공개' },
|
|
97
|
+
{ value: 'private', label: '비공개' },
|
|
98
|
+
{ value: 'internal', label: '내부' },
|
|
99
|
+
],
|
|
100
|
+
}));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (isTTY) {
|
|
105
|
+
const { input: promptInput, select: promptSelect } = await import('@inquirer/prompts');
|
|
106
|
+
console.log(`\n \x1b[33m⚡\x1b[0m \x1b[1mrelay create\x1b[0m — 새 에이전트 프로젝트\n`);
|
|
107
|
+
// slug가 비어있으면 (한국어 등 비ASCII 이름) slug를 직접 입력받음
|
|
108
|
+
if (!slug) {
|
|
109
|
+
slug = await promptInput({
|
|
110
|
+
message: 'Slug (URL/설치에 사용되는 영문 식별자):',
|
|
111
|
+
validate: (v) => {
|
|
112
|
+
const trimmed = v.trim();
|
|
113
|
+
if (!trimmed)
|
|
114
|
+
return 'slug를 입력해주세요.';
|
|
115
|
+
if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(trimmed))
|
|
116
|
+
return '소문자, 숫자, 하이픈만 사용 가능합니다.';
|
|
117
|
+
return true;
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
slug = slug.trim();
|
|
121
|
+
}
|
|
122
|
+
if (!description) {
|
|
123
|
+
description = await promptInput({
|
|
124
|
+
message: '에이전트 설명:',
|
|
125
|
+
validate: (v) => v.trim().length > 0 ? true : '설명을 입력해주세요.',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (!opts.tags) {
|
|
129
|
+
const tagsRaw = await promptInput({
|
|
130
|
+
message: '태그 (쉼표로 구분, 선택):',
|
|
131
|
+
default: '',
|
|
132
|
+
});
|
|
133
|
+
tags = tagsRaw.split(',').map((t) => t.trim()).filter(Boolean);
|
|
134
|
+
}
|
|
135
|
+
if (!opts.visibility) {
|
|
136
|
+
visibility = await promptSelect({
|
|
137
|
+
message: '공개 범위:',
|
|
138
|
+
choices: [
|
|
139
|
+
{ name: '공개 — 누구나 검색 및 설치 가능', value: 'public' },
|
|
140
|
+
{ name: '비공개 — 허가 코드 등록자만 사용 가능', value: 'private' },
|
|
141
|
+
{ name: '내부 — 조직 내의 누구나 사용 가능', value: 'internal' },
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// 3. recommended_scope 자동 추천
|
|
147
|
+
// rules/ 존재 or 프레임워크 태그 → local, 그 외 → global
|
|
148
|
+
const frameworkTags = ['nextjs', 'react', 'vue', 'angular', 'svelte', 'nuxt', 'remix', 'astro', 'django', 'rails', 'laravel', 'spring', 'express', 'fastapi', 'flask'];
|
|
149
|
+
const hasRules = fs_1.default.existsSync(path_1.default.join(projectPath, '.relay', 'rules'))
|
|
150
|
+
|| fs_1.default.existsSync(path_1.default.join(projectPath, 'rules'));
|
|
151
|
+
const hasFrameworkTag = tags.some((t) => frameworkTags.includes(t.toLowerCase()));
|
|
152
|
+
const recommendedScope = (hasRules || hasFrameworkTag) ? 'local' : 'global';
|
|
153
|
+
// 4. .relay/relay.yaml 생성
|
|
154
|
+
fs_1.default.mkdirSync(relayDir, { recursive: true });
|
|
155
|
+
const yamlData = {
|
|
156
|
+
name,
|
|
157
|
+
slug: slug,
|
|
158
|
+
description,
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
type: 'hybrid',
|
|
161
|
+
recommended_scope: recommendedScope,
|
|
162
|
+
tags,
|
|
163
|
+
visibility,
|
|
164
|
+
contents: [],
|
|
165
|
+
};
|
|
166
|
+
fs_1.default.writeFileSync(relayYamlPath, js_yaml_1.default.dump(yamlData, { lineWidth: 120 }), 'utf-8');
|
|
167
|
+
// 4. 디렉토리 구조 생성
|
|
168
|
+
const createdDirs = [];
|
|
169
|
+
for (const dir of DEFAULT_DIRS) {
|
|
170
|
+
const dirPath = path_1.default.join(projectPath, dir);
|
|
171
|
+
if (!fs_1.default.existsSync(dirPath)) {
|
|
172
|
+
fs_1.default.mkdirSync(dirPath, { recursive: true });
|
|
173
|
+
createdDirs.push(dir);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 5. 로컬 Builder 슬래시 커맨드 설치
|
|
177
|
+
const detected = (0, ai_tools_js_1.detectAgentCLIs)(projectPath);
|
|
178
|
+
const localResults = [];
|
|
179
|
+
for (const tool of detected) {
|
|
180
|
+
const adapter = (0, command_adapter_js_1.createAdapter)(tool);
|
|
181
|
+
const installed = [];
|
|
182
|
+
for (const cmd of command_adapter_js_1.BUILDER_COMMANDS) {
|
|
183
|
+
const filePath = path_1.default.join(projectPath, adapter.getFilePath(cmd.id));
|
|
184
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
185
|
+
fs_1.default.writeFileSync(filePath, adapter.formatFile(cmd));
|
|
186
|
+
installed.push(cmd.id);
|
|
187
|
+
}
|
|
188
|
+
localResults.push({ tool: tool.name, commands: installed });
|
|
189
|
+
}
|
|
190
|
+
// 6. 글로벌 User 커맨드 (없으면 설치)
|
|
191
|
+
const globalInstalled = ensureGlobalUserCommands();
|
|
192
|
+
// 7. 출력
|
|
193
|
+
if (json) {
|
|
194
|
+
console.log(JSON.stringify({
|
|
195
|
+
status: 'ok',
|
|
196
|
+
name,
|
|
197
|
+
slug: slug,
|
|
198
|
+
recommended_scope: recommendedScope,
|
|
199
|
+
relay_yaml: 'created',
|
|
200
|
+
directories: createdDirs,
|
|
201
|
+
local_commands: localResults,
|
|
202
|
+
global_commands: globalInstalled ? 'installed' : 'already',
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const scopeLabel = recommendedScope === 'global' ? '\x1b[32m글로벌\x1b[0m' : '\x1b[33m로컬\x1b[0m';
|
|
207
|
+
const scopeReason = hasRules ? 'rules/ 감지' : hasFrameworkTag ? '프레임워크 태그 감지' : '범용 에이전트';
|
|
208
|
+
console.log(`\n\x1b[32m✓ ${name} 에이전트 프로젝트 생성 완료\x1b[0m\n`);
|
|
209
|
+
console.log(` .relay/relay.yaml 생성됨`);
|
|
210
|
+
console.log(` recommended_scope: ${scopeLabel} (${scopeReason})`);
|
|
211
|
+
if (createdDirs.length > 0) {
|
|
212
|
+
console.log(` 디렉토리 생성: ${createdDirs.join(', ')}`);
|
|
213
|
+
}
|
|
214
|
+
if (localResults.length > 0) {
|
|
215
|
+
console.log(`\n \x1b[36mBuilder 커맨드 (로컬)\x1b[0m`);
|
|
216
|
+
for (const r of localResults) {
|
|
217
|
+
console.log(` ${r.tool}: ${r.commands.map((c) => `/${c}`).join(', ')}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (globalInstalled) {
|
|
221
|
+
console.log(`\n \x1b[36mUser 커맨드 (글로벌)\x1b[0m — 설치됨`);
|
|
222
|
+
}
|
|
223
|
+
console.log(`\n 다음 단계: \x1b[33m/relay-publish\x1b[0m로 Space에 배포`);
|
|
224
|
+
console.log(' IDE를 재시작하면 슬래시 커맨드가 활성화됩니다.\n');
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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.registerDeployRecord = registerDeployRecord;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const config_js_1 = require("../lib/config.js");
|
|
9
|
+
const slug_js_1 = require("../lib/slug.js");
|
|
10
|
+
function registerDeployRecord(program) {
|
|
11
|
+
program
|
|
12
|
+
.command('deploy-record <slug>')
|
|
13
|
+
.description('에이전트가 배치한 파일 정보를 installed.json에 기록합니다')
|
|
14
|
+
.requiredOption('--scope <scope>', '배치 범위 (global 또는 local)')
|
|
15
|
+
.option('--files <paths...>', '배치된 파일 경로 목록')
|
|
16
|
+
.action((slugInput, opts) => {
|
|
17
|
+
const json = program.opts().json ?? false;
|
|
18
|
+
const scope = opts.scope;
|
|
19
|
+
if (scope !== 'global' && scope !== 'local') {
|
|
20
|
+
const msg = { error: 'INVALID_SCOPE', message: '--scope는 global 또는 local이어야 합니다.' };
|
|
21
|
+
if (json) {
|
|
22
|
+
console.error(JSON.stringify(msg));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.error(`\x1b[31m오류:\x1b[0m ${msg.message}`);
|
|
26
|
+
}
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const files = opts.files ?? [];
|
|
30
|
+
// Resolve absolute paths
|
|
31
|
+
const resolvedFiles = files.map((f) => f.startsWith('/') || f.startsWith('~')
|
|
32
|
+
? f
|
|
33
|
+
: path_1.default.resolve(f));
|
|
34
|
+
// Find the agent in the appropriate registry
|
|
35
|
+
const localRegistry = (0, config_js_1.loadInstalled)();
|
|
36
|
+
const globalRegistry = (0, config_js_1.loadGlobalInstalled)();
|
|
37
|
+
// Resolve slug — check both registries for short name match
|
|
38
|
+
let slug;
|
|
39
|
+
if ((0, slug_js_1.isScopedSlug)(slugInput)) {
|
|
40
|
+
slug = slugInput;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const allKeys = [...Object.keys(localRegistry), ...Object.keys(globalRegistry)];
|
|
44
|
+
const match = allKeys.find((key) => {
|
|
45
|
+
const parsed = (0, slug_js_1.parseSlug)(key);
|
|
46
|
+
return parsed && parsed.name === slugInput;
|
|
47
|
+
});
|
|
48
|
+
slug = match ?? slugInput;
|
|
49
|
+
}
|
|
50
|
+
// Check if agent exists in either registry
|
|
51
|
+
const entry = localRegistry[slug] ?? globalRegistry[slug];
|
|
52
|
+
if (!entry) {
|
|
53
|
+
const msg = { error: 'NOT_INSTALLED', message: `'${slugInput}'는 설치되어 있지 않습니다.` };
|
|
54
|
+
if (json) {
|
|
55
|
+
console.error(JSON.stringify(msg));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.error(`\x1b[31m오류:\x1b[0m ${msg.message}`);
|
|
59
|
+
}
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
// Update deploy info
|
|
63
|
+
entry.deploy_scope = scope;
|
|
64
|
+
entry.deployed_files = resolvedFiles;
|
|
65
|
+
// Save to the correct registry based on scope
|
|
66
|
+
if (scope === 'global') {
|
|
67
|
+
globalRegistry[slug] = entry;
|
|
68
|
+
(0, config_js_1.saveGlobalInstalled)(globalRegistry);
|
|
69
|
+
// Also update local registry if entry exists there
|
|
70
|
+
if (localRegistry[slug]) {
|
|
71
|
+
localRegistry[slug] = entry;
|
|
72
|
+
(0, config_js_1.saveInstalled)(localRegistry);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
localRegistry[slug] = entry;
|
|
77
|
+
(0, config_js_1.saveInstalled)(localRegistry);
|
|
78
|
+
}
|
|
79
|
+
const result = {
|
|
80
|
+
status: 'ok',
|
|
81
|
+
slug,
|
|
82
|
+
deploy_scope: scope,
|
|
83
|
+
deployed_files: resolvedFiles.length,
|
|
84
|
+
};
|
|
85
|
+
if (json) {
|
|
86
|
+
console.log(JSON.stringify(result));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const scopeLabel = scope === 'global' ? '글로벌' : '로컬';
|
|
90
|
+
console.log(`\x1b[32m✓ ${slug} 배치 정보 기록 완료\x1b[0m (${scopeLabel}, ${resolvedFiles.length}개 파일)`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|