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.
Files changed (139) hide show
  1. package/README.md +174 -0
  2. package/dist/commands/access.d.ts +2 -0
  3. package/dist/commands/access.js +90 -0
  4. package/dist/commands/adopt.d.ts +2 -0
  5. package/dist/commands/adopt.js +177 -0
  6. package/dist/commands/changelog.d.ts +2 -0
  7. package/dist/commands/changelog.js +67 -0
  8. package/dist/commands/check-update.d.ts +2 -0
  9. package/dist/commands/check-update.js +76 -0
  10. package/dist/commands/config.d.ts +2 -0
  11. package/dist/commands/config.js +84 -0
  12. package/dist/commands/create.d.ts +2 -0
  13. package/dist/commands/create.js +227 -0
  14. package/dist/commands/deploy-record.d.ts +2 -0
  15. package/dist/commands/deploy-record.js +93 -0
  16. package/dist/commands/deploy.d.ts +2 -0
  17. package/dist/commands/deploy.js +284 -0
  18. package/dist/commands/diff.d.ts +2 -0
  19. package/dist/commands/diff.js +92 -0
  20. package/dist/commands/feedback.d.ts +2 -0
  21. package/dist/commands/feedback.js +71 -0
  22. package/dist/commands/grant.d.ts +33 -0
  23. package/dist/commands/grant.js +190 -0
  24. package/dist/commands/hub.d.ts +2 -0
  25. package/dist/commands/hub.js +171 -0
  26. package/dist/commands/init.d.ts +13 -0
  27. package/dist/commands/init.js +172 -0
  28. package/dist/commands/install.d.ts +2 -0
  29. package/dist/commands/install.js +626 -0
  30. package/dist/commands/join.d.ts +6 -0
  31. package/dist/commands/join.js +90 -0
  32. package/dist/commands/link.d.ts +2 -0
  33. package/dist/commands/link.js +112 -0
  34. package/dist/commands/list.d.ts +2 -0
  35. package/dist/commands/list.js +144 -0
  36. package/dist/commands/login.d.ts +7 -0
  37. package/dist/commands/login.js +235 -0
  38. package/dist/commands/orgs.d.ts +10 -0
  39. package/dist/commands/orgs.js +128 -0
  40. package/dist/commands/outdated.d.ts +2 -0
  41. package/dist/commands/outdated.js +70 -0
  42. package/dist/commands/package.d.ts +57 -0
  43. package/dist/commands/package.js +569 -0
  44. package/dist/commands/ping.d.ts +2 -0
  45. package/dist/commands/ping.js +40 -0
  46. package/dist/commands/publish.d.ts +98 -0
  47. package/dist/commands/publish.js +899 -0
  48. package/dist/commands/run.d.ts +2 -0
  49. package/dist/commands/run.js +249 -0
  50. package/dist/commands/search.d.ts +2 -0
  51. package/dist/commands/search.js +57 -0
  52. package/dist/commands/status.d.ts +2 -0
  53. package/dist/commands/status.js +159 -0
  54. package/dist/commands/uninstall.d.ts +2 -0
  55. package/dist/commands/uninstall.js +132 -0
  56. package/dist/commands/update.d.ts +2 -0
  57. package/dist/commands/update.js +171 -0
  58. package/dist/commands/versions.d.ts +2 -0
  59. package/dist/commands/versions.js +44 -0
  60. package/dist/index.d.ts +2 -0
  61. package/dist/index.js +91 -0
  62. package/dist/lib/agent-status.d.ts +23 -0
  63. package/dist/lib/agent-status.js +127 -0
  64. package/dist/lib/ai-tools.d.ts +34 -0
  65. package/dist/lib/ai-tools.js +104 -0
  66. package/dist/lib/anpm-config.d.ts +39 -0
  67. package/dist/lib/anpm-config.js +112 -0
  68. package/dist/lib/api.d.ts +24 -0
  69. package/dist/lib/api.js +151 -0
  70. package/dist/lib/auto-detect.d.ts +30 -0
  71. package/dist/lib/auto-detect.js +112 -0
  72. package/dist/lib/cloud-providers/anthropic.d.ts +19 -0
  73. package/dist/lib/cloud-providers/anthropic.js +200 -0
  74. package/dist/lib/cloud-providers/package-mapper.d.ts +9 -0
  75. package/dist/lib/cloud-providers/package-mapper.js +34 -0
  76. package/dist/lib/cloud-providers/provider.d.ts +60 -0
  77. package/dist/lib/cloud-providers/provider.js +7 -0
  78. package/dist/lib/command-adapter.d.ts +41 -0
  79. package/dist/lib/command-adapter.js +188 -0
  80. package/dist/lib/config.d.ts +50 -0
  81. package/dist/lib/config.js +274 -0
  82. package/dist/lib/contact-format.d.ts +7 -0
  83. package/dist/lib/contact-format.js +23 -0
  84. package/dist/lib/device-hash.d.ts +1 -0
  85. package/dist/lib/device-hash.js +16 -0
  86. package/dist/lib/error-report.d.ts +5 -0
  87. package/dist/lib/error-report.js +28 -0
  88. package/dist/lib/git-installer.d.ts +16 -0
  89. package/dist/lib/git-installer.js +97 -0
  90. package/dist/lib/git-operations.d.ts +38 -0
  91. package/dist/lib/git-operations.js +183 -0
  92. package/dist/lib/hub-notify.d.ts +9 -0
  93. package/dist/lib/hub-notify.js +66 -0
  94. package/dist/lib/install-source.d.ts +33 -0
  95. package/dist/lib/install-source.js +98 -0
  96. package/dist/lib/installer.d.ts +40 -0
  97. package/dist/lib/installer.js +358 -0
  98. package/dist/lib/local-installer.d.ts +15 -0
  99. package/dist/lib/local-installer.js +73 -0
  100. package/dist/lib/lockfile.d.ts +13 -0
  101. package/dist/lib/lockfile.js +42 -0
  102. package/dist/lib/manifest.d.ts +65 -0
  103. package/dist/lib/manifest.js +113 -0
  104. package/dist/lib/migration.d.ts +10 -0
  105. package/dist/lib/migration.js +91 -0
  106. package/dist/lib/paths.d.ts +10 -0
  107. package/dist/lib/paths.js +22 -0
  108. package/dist/lib/preamble.d.ts +22 -0
  109. package/dist/lib/preamble.js +133 -0
  110. package/dist/lib/relay-config.d.ts +13 -0
  111. package/dist/lib/relay-config.js +46 -0
  112. package/dist/lib/requires-suggest.d.ts +23 -0
  113. package/dist/lib/requires-suggest.js +295 -0
  114. package/dist/lib/setup-command.d.ts +6 -0
  115. package/dist/lib/setup-command.js +72 -0
  116. package/dist/lib/slug.d.ts +24 -0
  117. package/dist/lib/slug.js +100 -0
  118. package/dist/lib/step-tracker.d.ts +8 -0
  119. package/dist/lib/step-tracker.js +28 -0
  120. package/dist/lib/storage.d.ts +6 -0
  121. package/dist/lib/storage.js +23 -0
  122. package/dist/lib/update-cache.d.ts +2 -0
  123. package/dist/lib/update-cache.js +51 -0
  124. package/dist/lib/version-check.d.ts +10 -0
  125. package/dist/lib/version-check.js +75 -0
  126. package/dist/mcp/server.d.ts +3 -0
  127. package/dist/mcp/server.js +112 -0
  128. package/dist/postinstall.d.ts +8 -0
  129. package/dist/postinstall.js +41 -0
  130. package/dist/prompts/_error-handling.md +38 -0
  131. package/dist/prompts/create.md +170 -0
  132. package/dist/prompts/explore.md +30 -0
  133. package/dist/prompts/index.d.ts +3 -0
  134. package/dist/prompts/index.js +22 -0
  135. package/dist/relay-compat.d.ts +2 -0
  136. package/dist/relay-compat.js +7 -0
  137. package/dist/types.d.ts +118 -0
  138. package/dist/types.js +2 -0
  139. 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,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerCreate(program: Command): void;
@@ -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,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerDeployRecord(program: Command): void;
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerDeploy(program: Command): void;