relayax-cli 0.4.24 → 0.4.26
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/publish.d.ts +2 -2
- package/dist/commands/publish.js +30 -72
- package/dist/commands/update.js +1 -7
- package/dist/index.js +0 -2
- package/dist/lib/api.js +3 -1
- package/dist/lib/command-adapter.js +2 -34
- package/dist/lib/git-operations.js +1 -1
- package/dist/lib/installer.js +2 -1
- package/dist/lib/preamble.js +9 -3
- package/dist/lib/storage.d.ts +0 -3
- package/dist/lib/storage.js +1 -30
- package/dist/mcp/server.js +7 -720
- package/dist/prompts/create.md +10 -6
- package/dist/prompts/explore.md +2 -0
- package/package.json +2 -4
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -106
- package/dist/commands/follow.d.ts +0 -2
- package/dist/commands/follow.js +0 -45
- package/dist/commands/invite.d.ts +0 -2
- package/dist/commands/invite.js +0 -135
- package/dist/commands/spaces.d.ts +0 -11
- package/dist/commands/spaces.js +0 -69
- package/dist/lib/config.js.bak +0 -75
- package/dist/lib/guide.d.ts +0 -12
- package/dist/lib/guide.js +0 -60
- package/dist/lib/manifest-generator.d.ts +0 -20
- package/dist/lib/manifest-generator.js +0 -144
- package/dist/lib/security-scan.d.ts +0 -19
- package/dist/lib/security-scan.js +0 -114
- package/dist/prompts/_business-card.md +0 -41
- package/dist/prompts/_guide-instruction.md +0 -2
- package/dist/prompts/_requirements-check.md +0 -59
- package/dist/prompts/_setup-cli.md +0 -36
- package/dist/prompts/_setup-environment.md +0 -75
- package/dist/prompts/_setup-login.md +0 -31
- package/dist/prompts/_setup-org.md +0 -25
- package/dist/prompts/business-card.md +0 -41
- package/dist/prompts/error-handling.md +0 -38
- package/dist/prompts/install.md +0 -178
- package/dist/prompts/publish.md +0 -505
- package/dist/prompts/requirements-check.md +0 -59
|
@@ -27,6 +27,7 @@ export interface RequiresEnv {
|
|
|
27
27
|
name: string;
|
|
28
28
|
required?: boolean;
|
|
29
29
|
description?: string;
|
|
30
|
+
setup_hint?: string;
|
|
30
31
|
}
|
|
31
32
|
export interface RequiresNpm {
|
|
32
33
|
name: string;
|
|
@@ -74,7 +75,6 @@ export interface PublishMetadata {
|
|
|
74
75
|
skill_details?: SkillDetail[];
|
|
75
76
|
org_slug?: string;
|
|
76
77
|
}
|
|
77
|
-
export declare function createTarball(agentDir: string): Promise<string>;
|
|
78
78
|
interface PublishResult {
|
|
79
79
|
status: string;
|
|
80
80
|
slug: string;
|
|
@@ -88,6 +88,6 @@ interface PublishResult {
|
|
|
88
88
|
default_welcome?: string;
|
|
89
89
|
} | null;
|
|
90
90
|
}
|
|
91
|
-
export declare function publishToApi(token: string,
|
|
91
|
+
export declare function publishToApi(token: string, metadata: PublishMetadata): Promise<PublishResult>;
|
|
92
92
|
export declare function registerPublish(program: Command): void;
|
|
93
93
|
export {};
|
package/dist/commands/publish.js
CHANGED
|
@@ -3,14 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createTarball = createTarball;
|
|
7
6
|
exports.publishToApi = publishToApi;
|
|
8
7
|
exports.registerPublish = registerPublish;
|
|
9
8
|
const fs_1 = __importDefault(require("fs"));
|
|
10
9
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
10
|
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
13
|
-
const tar_1 = require("tar");
|
|
14
11
|
const config_js_1 = require("../lib/config.js");
|
|
15
12
|
const preamble_js_1 = require("../lib/preamble.js");
|
|
16
13
|
const version_check_js_1 = require("../lib/version-check.js");
|
|
@@ -18,7 +15,6 @@ const paths_js_1 = require("../lib/paths.js");
|
|
|
18
15
|
const error_report_js_1 = require("../lib/error-report.js");
|
|
19
16
|
const step_tracker_js_1 = require("../lib/step-tracker.js");
|
|
20
17
|
const git_operations_js_1 = require("../lib/git-operations.js");
|
|
21
|
-
const manifest_generator_js_1 = require("../lib/manifest-generator.js");
|
|
22
18
|
// GUIDE_INSTRUCTION removed — share text now uses npx install command directly
|
|
23
19
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
24
20
|
const cliPkg = require('../../package.json');
|
|
@@ -52,7 +48,6 @@ function parseRelayYaml(content) {
|
|
|
52
48
|
type,
|
|
53
49
|
source: raw.source ? String(raw.source) : undefined,
|
|
54
50
|
org_slug: raw.org_slug ? String(raw.org_slug) : undefined,
|
|
55
|
-
platforms: Array.isArray(raw.platforms) ? raw.platforms.map((p) => String(p)) : undefined,
|
|
56
51
|
};
|
|
57
52
|
}
|
|
58
53
|
function detectCommands(agentDir) {
|
|
@@ -250,34 +245,14 @@ function resolveLongDescription(agentDir, yamlValue) {
|
|
|
250
245
|
}
|
|
251
246
|
return undefined;
|
|
252
247
|
}
|
|
253
|
-
async function
|
|
254
|
-
const tmpFile = path_1.default.join(os_1.default.tmpdir(), `relay-publish-${Date.now()}.tar.gz`);
|
|
255
|
-
const dirsToInclude = VALID_DIRS.filter((d) => fs_1.default.existsSync(path_1.default.join(agentDir, d)));
|
|
256
|
-
// Include root-level files if they exist
|
|
257
|
-
const entries = [...dirsToInclude];
|
|
258
|
-
const rootFiles = ['relay.yaml', 'SKILL.md', 'guide.md'];
|
|
259
|
-
for (const file of rootFiles) {
|
|
260
|
-
if (fs_1.default.existsSync(path_1.default.join(agentDir, file))) {
|
|
261
|
-
entries.push(file);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
await (0, tar_1.create)({
|
|
265
|
-
gzip: true,
|
|
266
|
-
file: tmpFile,
|
|
267
|
-
cwd: agentDir,
|
|
268
|
-
}, entries);
|
|
269
|
-
return tmpFile;
|
|
270
|
-
}
|
|
271
|
-
async function publishToApi(token, tarPath, metadata) {
|
|
272
|
-
const fileBuffer = fs_1.default.readFileSync(tarPath);
|
|
273
|
-
const blob = new Blob([fileBuffer], { type: 'application/gzip' });
|
|
274
|
-
const form = new FormData();
|
|
275
|
-
form.append('package', blob, `${metadata.slug}-${metadata.version}.tar.gz`);
|
|
276
|
-
form.append('metadata', JSON.stringify(metadata));
|
|
248
|
+
async function publishToApi(token, metadata) {
|
|
277
249
|
const res = await fetch(`${config_js_1.API_URL}/api/publish`, {
|
|
278
250
|
method: 'POST',
|
|
279
|
-
headers: {
|
|
280
|
-
|
|
251
|
+
headers: {
|
|
252
|
+
Authorization: `Bearer ${token}`,
|
|
253
|
+
'Content-Type': 'application/json',
|
|
254
|
+
},
|
|
255
|
+
body: JSON.stringify(metadata),
|
|
281
256
|
redirect: 'error',
|
|
282
257
|
});
|
|
283
258
|
const body = await res.json();
|
|
@@ -442,6 +417,27 @@ function registerPublish(program) {
|
|
|
442
417
|
console.error(` → relay.yaml에 version: ${newVersion} 저장됨\n`);
|
|
443
418
|
}
|
|
444
419
|
}
|
|
420
|
+
// Auto-sync: relay.yaml의 contents에 정의된 소스를 .relay/에 동기화
|
|
421
|
+
try {
|
|
422
|
+
const yamlContent = fs_1.default.readFileSync(relayYamlPath, 'utf-8');
|
|
423
|
+
const yamlConfig = js_yaml_1.default.load(yamlContent);
|
|
424
|
+
const contents = yamlConfig.contents ?? [];
|
|
425
|
+
if (contents.length > 0) {
|
|
426
|
+
const { computeContentsDiff, syncContentsToRelay } = await import('./package.js');
|
|
427
|
+
const { diff: contentsDiff } = computeContentsDiff(contents, relayDir, agentDir);
|
|
428
|
+
const hasChanges = contentsDiff.some((d) => d.status === 'modified');
|
|
429
|
+
if (hasChanges) {
|
|
430
|
+
syncContentsToRelay(contents, contentsDiff, relayDir, agentDir);
|
|
431
|
+
if (!json) {
|
|
432
|
+
const changedNames = contentsDiff.filter((d) => d.status === 'modified').map((d) => d.name);
|
|
433
|
+
console.error(`\x1b[36m⚙ 소스 동기화:\x1b[0m ${changedNames.join(', ')}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// sync 실패는 non-fatal — 기존 .relay/ 내용으로 publish 진행
|
|
440
|
+
}
|
|
445
441
|
// Validate structure (콘텐츠는 .relay/ 안에 있음)
|
|
446
442
|
const hasDirs = VALID_DIRS.some((d) => {
|
|
447
443
|
const dirPath = path_1.default.join(relayDir, d);
|
|
@@ -709,10 +705,7 @@ function registerPublish(program) {
|
|
|
709
705
|
console.error('\x1b[33m⚠ GUIDE.html은 더 이상 지원되지 않습니다. 상세페이지가 가이드 역할을 합니다.\x1b[0m');
|
|
710
706
|
console.error(' long_description을 활용하거나 relayax.com에서 에이전트 정보를 편집하세요.\n');
|
|
711
707
|
}
|
|
712
|
-
//
|
|
713
|
-
const { generateGuide } = await import('../lib/guide.js');
|
|
714
|
-
const guideContent = generateGuide(config, detectedCommands, config.requires);
|
|
715
|
-
fs_1.default.writeFileSync(path_1.default.join(relayDir, 'guide.md'), guideContent);
|
|
708
|
+
// guide.md는 웹 API route에서 동적 생성 (/api/registry/{owner}/{slug}/guide.md)
|
|
716
709
|
// Generate bin/relay-preamble.sh (self-contained tracking + update check)
|
|
717
710
|
(0, preamble_js_1.generatePreambleBin)(relayDir, config.slug, config_js_1.API_URL);
|
|
718
711
|
// Generate entry command (commands/{author}-{name}.md)
|
|
@@ -740,38 +733,11 @@ function registerPublish(program) {
|
|
|
740
733
|
}
|
|
741
734
|
process.exit(1);
|
|
742
735
|
}
|
|
743
|
-
// Generate platform manifests (after preamble/command, before git commit)
|
|
744
|
-
const manifestYaml = {
|
|
745
|
-
name: config.name,
|
|
746
|
-
slug: config.slug,
|
|
747
|
-
description: config.description,
|
|
748
|
-
version: config.version,
|
|
749
|
-
source: config.source,
|
|
750
|
-
org_slug: config.org_slug ?? selectedOrgSlug,
|
|
751
|
-
platforms: config.platforms,
|
|
752
|
-
};
|
|
753
|
-
const manifestFiles = (0, manifest_generator_js_1.generateManifests)(manifestYaml, relayDir);
|
|
754
|
-
for (const mf of manifestFiles) {
|
|
755
|
-
const mfPath = path_1.default.join(relayDir, mf.relativePath);
|
|
756
|
-
fs_1.default.mkdirSync(path_1.default.dirname(mfPath), { recursive: true });
|
|
757
|
-
fs_1.default.writeFileSync(mfPath, mf.content);
|
|
758
|
-
}
|
|
759
|
-
const generatedPlatforms = [...new Set(manifestFiles.map((f) => {
|
|
760
|
-
if (f.relativePath.startsWith('.claude-plugin/') || f.relativePath === 'marketplace.json')
|
|
761
|
-
return 'claude-code';
|
|
762
|
-
if (f.relativePath.startsWith('.codex-plugin/'))
|
|
763
|
-
return 'codex';
|
|
764
|
-
if (f.relativePath.startsWith('.agent/'))
|
|
765
|
-
return 'antigravity';
|
|
766
|
-
return 'unknown';
|
|
767
|
-
}))];
|
|
768
|
-
let tarPath = null;
|
|
769
736
|
try {
|
|
770
|
-
tarPath = await createTarball(relayDir);
|
|
771
737
|
if (!json) {
|
|
772
738
|
console.error(`업로드 중...`);
|
|
773
739
|
}
|
|
774
|
-
const result = await publishToApi(token,
|
|
740
|
+
const result = await publishToApi(token, metadata);
|
|
775
741
|
// Git push: commit and push to git server (required)
|
|
776
742
|
const gitUrlRaw = result.git_url;
|
|
777
743
|
if (gitUrlRaw) {
|
|
@@ -815,9 +781,7 @@ function registerPublish(program) {
|
|
|
815
781
|
// preamble update is best-effort — publish already succeeded
|
|
816
782
|
}
|
|
817
783
|
if (json) {
|
|
818
|
-
|
|
819
|
-
jsonResult.platforms = generatedPlatforms;
|
|
820
|
-
console.log(JSON.stringify(jsonResult));
|
|
784
|
+
console.log(JSON.stringify(result));
|
|
821
785
|
}
|
|
822
786
|
else {
|
|
823
787
|
console.log(`\n\x1b[32m✓ ${config.name} 배포 완료\x1b[0m v${result.version}`);
|
|
@@ -827,7 +791,6 @@ function registerPublish(program) {
|
|
|
827
791
|
{
|
|
828
792
|
const detailSlug = result.slug.startsWith('@') ? result.slug.slice(1) : result.slug;
|
|
829
793
|
const accessCode = result.access_code ?? null;
|
|
830
|
-
// const gitUrl = (result as unknown as Record<string, unknown>).git_url as string | undefined // plugin disabled
|
|
831
794
|
// npx turnkey install command (works everywhere, no pre-install needed)
|
|
832
795
|
const visibility = config.visibility ?? 'public';
|
|
833
796
|
let npxInstallCmd;
|
|
@@ -865,10 +828,5 @@ function registerPublish(program) {
|
|
|
865
828
|
console.error(JSON.stringify({ error: 'PUBLISH_FAILED', message, fix: message }));
|
|
866
829
|
process.exit(1);
|
|
867
830
|
}
|
|
868
|
-
finally {
|
|
869
|
-
if (tarPath && fs_1.default.existsSync(tarPath)) {
|
|
870
|
-
fs_1.default.unlinkSync(tarPath);
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
831
|
});
|
|
874
832
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -93,13 +93,7 @@ function registerUpdate(program) {
|
|
|
93
93
|
await (0, storage_js_1.clonePackage)(agent.git_url, agentDir);
|
|
94
94
|
}
|
|
95
95
|
else {
|
|
96
|
-
|
|
97
|
-
const tarPath = await (0, storage_js_1.downloadPackage)(agent.package_url, tempDir);
|
|
98
|
-
if (fs_1.default.existsSync(agentDir)) {
|
|
99
|
-
fs_1.default.rmSync(agentDir, { recursive: true, force: true });
|
|
100
|
-
}
|
|
101
|
-
fs_1.default.mkdirSync(agentDir, { recursive: true });
|
|
102
|
-
await (0, storage_js_1.extractPackage)(tarPath, agentDir);
|
|
96
|
+
throw new Error('이 에이전트는 재설치가 필요합니다. relay install로 다시 설치하세요.');
|
|
103
97
|
}
|
|
104
98
|
// Inject preamble
|
|
105
99
|
(0, preamble_js_1.injectPreambleToAgent)(agentDir, slug);
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,6 @@ const access_js_1 = require("./commands/access.js");
|
|
|
24
24
|
const grant_js_1 = require("./commands/grant.js");
|
|
25
25
|
const versions_js_1 = require("./commands/versions.js");
|
|
26
26
|
const diff_js_1 = require("./commands/diff.js");
|
|
27
|
-
const export_js_1 = require("./commands/export.js");
|
|
28
27
|
const feedback_js_1 = require("./commands/feedback.js");
|
|
29
28
|
const server_js_1 = require("./mcp/server.js");
|
|
30
29
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
@@ -57,7 +56,6 @@ program
|
|
|
57
56
|
(0, grant_js_1.registerGrant)(program);
|
|
58
57
|
(0, versions_js_1.registerVersions)(program);
|
|
59
58
|
(0, diff_js_1.registerDiff)(program);
|
|
60
|
-
(0, export_js_1.registerExport)(program);
|
|
61
59
|
(0, feedback_js_1.registerFeedback)(program);
|
|
62
60
|
program
|
|
63
61
|
.command('mcp')
|
package/dist/lib/api.js
CHANGED
|
@@ -110,10 +110,12 @@ async function sendUsagePing(agentId, slug, version) {
|
|
|
110
110
|
const deviceHash = createHash('sha256')
|
|
111
111
|
.update(`${hostname()}:${userInfo().username}`)
|
|
112
112
|
.digest('hex');
|
|
113
|
+
// CLI version
|
|
114
|
+
const pkg = require('../../package.json');
|
|
113
115
|
// agentId(UUID)가 있으면 UUID 경로, 없으면 slug name으로 fallback
|
|
114
116
|
const pathParam = agentId || slug.replace(/^@/, '').split('/').pop() || slug;
|
|
115
117
|
const url = `${config_js_1.API_URL}/api/agents/${pathParam}/ping`;
|
|
116
|
-
const payload = { device_hash: deviceHash, slug };
|
|
118
|
+
const payload = { device_hash: deviceHash, slug, cli_version: pkg.version };
|
|
117
119
|
if (version)
|
|
118
120
|
payload.installed_version = version;
|
|
119
121
|
const headers = { 'Content-Type': 'application/json' };
|
|
@@ -13,37 +13,6 @@ exports.formatCommandFile = formatCommandFile;
|
|
|
13
13
|
const os_1 = __importDefault(require("os"));
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const index_js_1 = require("../prompts/index.js");
|
|
16
|
-
/**
|
|
17
|
-
* 환경 감지 프리앰블.
|
|
18
|
-
* slash command 실행 시 MCP tool 사용 가능 여부를 먼저 판별하여,
|
|
19
|
-
* 이후 모든 CLI 명령어를 적절한 방식으로 실행하도록 안내.
|
|
20
|
-
*/
|
|
21
|
-
const ENV_PREAMBLE = `## 환경 감지
|
|
22
|
-
|
|
23
|
-
이 커맨드를 실행하기 전에 환경을 판별하세요:
|
|
24
|
-
|
|
25
|
-
1. **relay MCP tool 사용 가능 여부 확인**: relay_status 같은 relay MCP tool을 호출할 수 있는지 확인하세요.
|
|
26
|
-
- 사용 가능 → **MCP 모드**로 실행 (아래 표 참고)
|
|
27
|
-
- 사용 불가 → **CLI 모드**로 실행 (bash 명령어 그대로 사용)
|
|
28
|
-
|
|
29
|
-
2. MCP 모드에서의 명령어 변환:
|
|
30
|
-
|
|
31
|
-
| CLI 명령어 | MCP tool |
|
|
32
|
-
|---|---|
|
|
33
|
-
| \`relay status\` | \`relay_status\` tool 호출 |
|
|
34
|
-
| \`relay list --json\` | \`relay_list\` tool 호출 |
|
|
35
|
-
| \`relay search <keyword>\` | \`relay_search\` tool 호출 |
|
|
36
|
-
| \`relay install <slug>\` | \`relay_install\` tool 호출 |
|
|
37
|
-
| \`relay uninstall <slug>\` | \`relay_uninstall\` tool 호출 |
|
|
38
|
-
| \`relay package --init\` | \`relay_scan\` tool 호출 |
|
|
39
|
-
| \`relay publish\` | \`relay_publish\` tool 호출 |
|
|
40
|
-
| \`relay login\` | \`relay_login\` tool 호출 |
|
|
41
|
-
|
|
42
|
-
**중요**: 이후 지시에서 \`relay <명령어>\`로 표기된 것은 판별된 환경에 따라 변환하여 실행하세요.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
`;
|
|
47
16
|
/**
|
|
48
17
|
* 로컬 어댑터 — 프로젝트 디렉토리 기준.
|
|
49
18
|
* {projectPath}/{skillsDir}/commands/relay/{id}.md
|
|
@@ -101,7 +70,7 @@ exports.USER_COMMANDS = [
|
|
|
101
70
|
{
|
|
102
71
|
id: 'relay-status',
|
|
103
72
|
description: '설치된 에이전트와 Organization 현황을 확인합니다',
|
|
104
|
-
body:
|
|
73
|
+
body: `현재 설치된 에이전트와 소속 Organization 현황을 한눈에 보여줍니다.
|
|
105
74
|
|
|
106
75
|
## 실행 방법
|
|
107
76
|
|
|
@@ -154,7 +123,6 @@ exports.USER_COMMANDS = [
|
|
|
154
123
|
|
|
155
124
|
**표시:**
|
|
156
125
|
- \`role\`: owner → 오너, admin → 관리자, builder → 빌더, member → 멤버
|
|
157
|
-
${index_js_1.ERROR_HANDLING_GUIDE}
|
|
158
126
|
- Org 조회 실패해도 설치된 에이전트 목록은 정상 표시합니다 (로컬 데이터).
|
|
159
127
|
|
|
160
128
|
### 3. Org 에이전트 목록 (옵션)
|
|
@@ -190,7 +158,7 @@ ${index_js_1.ERROR_HANDLING_GUIDE}
|
|
|
190
158
|
{
|
|
191
159
|
id: 'relay-uninstall',
|
|
192
160
|
description: '설치된 에이전트를 삭제합니다',
|
|
193
|
-
body:
|
|
161
|
+
body: `설치된 에이전트를 제거합니다. CLI가 패키지와 배치된 파일을 모두 정리합니다.
|
|
194
162
|
|
|
195
163
|
## 실행 방법
|
|
196
164
|
|
|
@@ -148,7 +148,7 @@ async function gitPublishUpdate(sourceDir, remoteUrl, version) {
|
|
|
148
148
|
gitAdd(sourceDir);
|
|
149
149
|
gitCommit(sourceDir, `v${version}`);
|
|
150
150
|
gitTag(sourceDir, `v${version}`);
|
|
151
|
-
gitPush(sourceDir, 'origin');
|
|
151
|
+
gitPush(sourceDir, 'origin', 'HEAD:main');
|
|
152
152
|
}
|
|
153
153
|
finally {
|
|
154
154
|
fs_1.default.rmSync(tempCloneDir, { recursive: true, force: true });
|
package/dist/lib/installer.js
CHANGED
|
@@ -190,10 +190,11 @@ function checkRequires(agentDir) {
|
|
|
190
190
|
}
|
|
191
191
|
else {
|
|
192
192
|
const desc = env.description ? ` (${env.description})` : '';
|
|
193
|
+
const hint = env.setup_hint ? `\n 설정 방법:\n${env.setup_hint.split('\n').map((l) => ` ${l}`).join('\n')}` : '';
|
|
193
194
|
results.push({
|
|
194
195
|
label: 'env',
|
|
195
196
|
status: env.required !== false ? 'missing' : 'warn',
|
|
196
|
-
message: `${env.name} — 미설정${desc}`,
|
|
197
|
+
message: `${env.name} — 미설정${desc}${hint}`,
|
|
197
198
|
});
|
|
198
199
|
}
|
|
199
200
|
}
|
package/dist/lib/preamble.js
CHANGED
|
@@ -43,16 +43,24 @@ if [ -f "$HOME/.relay/token.json" ]; then
|
|
|
43
43
|
_RELAY_TOKEN=$(grep -o '"access_token":"[^"]*"' "$HOME/.relay/token.json" 2>/dev/null | head -1 | cut -d'"' -f4)
|
|
44
44
|
fi
|
|
45
45
|
|
|
46
|
+
# CLI version (for usage tracking)
|
|
47
|
+
_CLI_VERSION=""
|
|
48
|
+
if command -v relay &>/dev/null; then
|
|
49
|
+
_CLI_VERSION=$(relay --version 2>/dev/null | head -1 | grep -o '[0-9][0-9.]*' || true)
|
|
50
|
+
fi
|
|
51
|
+
|
|
46
52
|
# Usage ping (with user identity if logged in)
|
|
47
53
|
if command -v relay &>/dev/null; then
|
|
48
54
|
relay ping "${slug}" --quiet 2>/dev/null &
|
|
49
55
|
elif command -v curl &>/dev/null; then
|
|
50
56
|
_AUTH_HEADER=""
|
|
51
57
|
[ -n "$_RELAY_TOKEN" ] && _AUTH_HEADER="-H \\"Authorization: Bearer $_RELAY_TOKEN\\""
|
|
58
|
+
_CLI_VER_FIELD=""
|
|
59
|
+
[ -n "$_CLI_VERSION" ] && _CLI_VER_FIELD=",\\"cli_version\\":\\"$_CLI_VERSION\\""
|
|
52
60
|
eval curl -sf --max-time 5 -X POST "${apiUrl}/api/agents/${agentSlug}/ping" \\
|
|
53
61
|
-H "Content-Type: application/json" \\
|
|
54
62
|
$_AUTH_HEADER \\
|
|
55
|
-
-d "{\\"device_hash\\":\\"$DEVICE_HASH\\",\\"slug\\":\\"${slug}\\"}" \\
|
|
63
|
+
-d "{\\"device_hash\\":\\"$DEVICE_HASH\\",\\"slug\\":\\"${slug}\\"$_CLI_VER_FIELD}" \\
|
|
56
64
|
2>/dev/null &
|
|
57
65
|
fi
|
|
58
66
|
|
|
@@ -78,8 +86,6 @@ function generatePreamble(slug, agentDir) {
|
|
|
78
86
|
[ -f "${scriptPath}" ] && bash "${scriptPath}" 2>/dev/null || true
|
|
79
87
|
\`\`\`
|
|
80
88
|
|
|
81
|
-
If the bash command above fails or the file is not found (sandbox/MCP environment), use the \`relay_check_update\` MCP tool instead: \`relay_check_update(slug: "${slug}")\`
|
|
82
|
-
|
|
83
89
|
If output shows \`CLI_UPGRADE_AVAILABLE <old> <new>\`: tell user "relay v{new} available. Run: npm update -g relayax-cli"
|
|
84
90
|
If output shows \`AGENT_UPGRADE_AVAILABLE\`: tell user "${slug} v{new} available (by @{author}). Run: relay update ${slug}"
|
|
85
91
|
${PREAMBLE_END}`;
|
package/dist/lib/storage.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
export declare function downloadPackage(url: string, destDir: string): Promise<string>;
|
|
2
|
-
export declare function extractPackage(tarPath: string, destDir: string): Promise<void>;
|
|
3
1
|
export declare function makeTempDir(): string;
|
|
4
2
|
export declare function removeTempDir(dir: string): void;
|
|
5
3
|
/**
|
|
6
4
|
* Clone an agent from git URL to destination directory.
|
|
7
|
-
* Replaces downloadPackage() + extractPackage() for git-based agents.
|
|
8
5
|
*/
|
|
9
6
|
export declare function clonePackage(gitUrl: string, destDir: string, version?: string): Promise<void>;
|
package/dist/lib/storage.js
CHANGED
|
@@ -3,49 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.downloadPackage = downloadPackage;
|
|
7
|
-
exports.extractPackage = extractPackage;
|
|
8
6
|
exports.makeTempDir = makeTempDir;
|
|
9
7
|
exports.removeTempDir = removeTempDir;
|
|
10
8
|
exports.clonePackage = clonePackage;
|
|
11
9
|
const fs_1 = __importDefault(require("fs"));
|
|
12
|
-
const path_1 = __importDefault(require("path"));
|
|
13
10
|
const os_1 = __importDefault(require("os"));
|
|
14
|
-
const fs_2 = require("fs");
|
|
15
|
-
const promises_1 = require("stream/promises");
|
|
16
|
-
const stream_1 = require("stream");
|
|
17
|
-
const tar_1 = require("tar");
|
|
18
11
|
const git_operations_js_1 = require("./git-operations.js");
|
|
19
|
-
async function downloadPackage(url, destDir) {
|
|
20
|
-
const res = await fetch(url);
|
|
21
|
-
if (!res.ok) {
|
|
22
|
-
throw new Error(`패키지 다운로드 실패 (${res.status}): ${url}`);
|
|
23
|
-
}
|
|
24
|
-
const fileName = path_1.default.basename(new URL(url).pathname) || 'package.tar.gz';
|
|
25
|
-
const destPath = path_1.default.join(destDir, fileName);
|
|
26
|
-
const body = res.body;
|
|
27
|
-
if (!body) {
|
|
28
|
-
throw new Error('응답 본문이 비어 있습니다');
|
|
29
|
-
}
|
|
30
|
-
const nodeReadable = stream_1.Readable.fromWeb(body);
|
|
31
|
-
await (0, promises_1.pipeline)(nodeReadable, (0, fs_2.createWriteStream)(destPath));
|
|
32
|
-
return destPath;
|
|
33
|
-
}
|
|
34
|
-
async function extractPackage(tarPath, destDir) {
|
|
35
|
-
if (!fs_1.default.existsSync(destDir)) {
|
|
36
|
-
fs_1.default.mkdirSync(destDir, { recursive: true });
|
|
37
|
-
}
|
|
38
|
-
await (0, tar_1.extract)({ file: tarPath, cwd: destDir });
|
|
39
|
-
}
|
|
40
12
|
function makeTempDir() {
|
|
41
|
-
return fs_1.default.mkdtempSync(
|
|
13
|
+
return fs_1.default.mkdtempSync(os_1.default.tmpdir() + '/relay-');
|
|
42
14
|
}
|
|
43
15
|
function removeTempDir(dir) {
|
|
44
16
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
45
17
|
}
|
|
46
18
|
/**
|
|
47
19
|
* Clone an agent from git URL to destination directory.
|
|
48
|
-
* Replaces downloadPackage() + extractPackage() for git-based agents.
|
|
49
20
|
*/
|
|
50
21
|
async function clonePackage(gitUrl, destDir, version) {
|
|
51
22
|
await (0, git_operations_js_1.gitInstall)(gitUrl, destDir, version);
|