relayax-cli 0.2.41 → 0.3.41

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.
@@ -2,30 +2,27 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerList = registerList;
4
4
  const config_js_1 = require("../lib/config.js");
5
- async function fetchSpaceTeamList(spaceSlug, token) {
6
- const res = await fetch(`${config_js_1.API_URL}/api/spaces/${spaceSlug}/teams`, {
5
+ async function fetchOrgTeamList(orgSlug, token) {
6
+ const res = await fetch(`${config_js_1.API_URL}/api/orgs/${orgSlug}/teams`, {
7
7
  headers: { Authorization: `Bearer ${token}` },
8
8
  signal: AbortSignal.timeout(8000),
9
9
  });
10
10
  if (!res.ok) {
11
11
  const body = await res.text();
12
- throw new Error(`Space 팀 목록 조회 실패 (${res.status}): ${body}`);
12
+ throw new Error(`Org 팀 목록 조회 실패 (${res.status}): ${body}`);
13
13
  }
14
- const data = (await res.json());
15
- if (Array.isArray(data))
16
- return data;
17
- return data.teams ?? [];
14
+ return (await res.json());
18
15
  }
19
16
  function registerList(program) {
20
17
  program
21
18
  .command('list')
22
19
  .description('설치된 에이전트 팀 목록')
23
- .option('--space <slug>', 'Space 팀 목록 조회')
20
+ .option('--org <slug>', 'Organization 팀 목록 조회')
24
21
  .action(async (opts) => {
25
22
  const json = program.opts().json ?? false;
26
- // --space 옵션: Space 팀 목록
27
- if (opts.space) {
28
- const spaceSlug = opts.space;
23
+ // --org 옵션: Org 팀 목록
24
+ if (opts.org) {
25
+ const orgSlug = opts.org;
29
26
  const token = await (0, config_js_1.getValidToken)();
30
27
  if (!token) {
31
28
  if (json) {
@@ -38,23 +35,23 @@ function registerList(program) {
38
35
  process.exit(1);
39
36
  }
40
37
  try {
41
- const teams = await fetchSpaceTeamList(spaceSlug, token);
38
+ const teams = await fetchOrgTeamList(orgSlug, token);
42
39
  if (json) {
43
- console.log(JSON.stringify({ space: spaceSlug, teams }));
40
+ console.log(JSON.stringify({ org: orgSlug, teams }));
44
41
  return;
45
42
  }
46
43
  if (teams.length === 0) {
47
- console.log(`\n${spaceSlug} Space추가된 팀이 없습니다.`);
44
+ console.log(`\n@${orgSlug} Organization에 팀이 없습니다.`);
48
45
  return;
49
46
  }
50
- console.log(`\n\x1b[1m${spaceSlug} Space 팀 목록\x1b[0m (${teams.length}개):\n`);
47
+ console.log(`\n\x1b[1m@${orgSlug} 팀 목록\x1b[0m (${teams.length}개):\n`);
51
48
  for (const t of teams) {
52
49
  const desc = t.description
53
50
  ? ` \x1b[90m${t.description.length > 50 ? t.description.slice(0, 50) + '...' : t.description}\x1b[0m`
54
51
  : '';
55
- console.log(` \x1b[36m${t.slug}\x1b[0m \x1b[1m${t.name}\x1b[0m${desc}`);
52
+ console.log(` \x1b[36m@${t.owner}/${t.slug}\x1b[0m \x1b[1m${t.name}\x1b[0m${desc}`);
56
53
  }
57
- console.log(`\n\x1b[33m💡 설치: relay install @spaces/${spaceSlug}/<팀슬러그>\x1b[0m`);
54
+ console.log(`\n\x1b[33m 설치: relay install @${orgSlug}/<팀슬러그>\x1b[0m`);
58
55
  }
59
56
  catch (err) {
60
57
  const message = err instanceof Error ? err.message : String(err);
@@ -80,7 +77,7 @@ function registerList(program) {
80
77
  installed_at: info.installed_at,
81
78
  scope: 'global',
82
79
  deploy_scope: info.deploy_scope,
83
- space_slug: info.space_slug,
80
+ org_slug: info.org_slug,
84
81
  });
85
82
  seen.add(slug);
86
83
  }
@@ -94,7 +91,7 @@ function registerList(program) {
94
91
  installed_at: info.installed_at,
95
92
  scope: 'local',
96
93
  deploy_scope: info.deploy_scope,
97
- space_slug: info.space_slug,
94
+ org_slug: info.org_slug,
98
95
  });
99
96
  }
100
97
  if (json) {
@@ -113,8 +110,8 @@ function registerList(program) {
113
110
  : item.deploy_scope === 'local'
114
111
  ? '\x1b[33m로컬\x1b[0m'
115
112
  : '\x1b[90m미배치\x1b[0m';
116
- const spaceLabel = item.space_slug ? ` \x1b[90m[Space: ${item.space_slug}]\x1b[0m` : '';
117
- console.log(` \x1b[36m${item.slug}\x1b[0m v${item.version} ${scopeLabel} (${date})${spaceLabel}`);
113
+ const orgLabel = item.org_slug ? ` \x1b[90m[Org: ${item.org_slug}]\x1b[0m` : '';
114
+ console.log(` \x1b[36m${item.slug}\x1b[0m v${item.version} ${scopeLabel} (${date})${orgLabel}`);
118
115
  }
119
116
  }
120
117
  });
@@ -0,0 +1,10 @@
1
+ import { Command } from 'commander';
2
+ export interface OrgInfo {
3
+ id: string;
4
+ slug: string;
5
+ name: string;
6
+ description: string | null;
7
+ role: string;
8
+ }
9
+ export declare function fetchMyOrgs(token: string): Promise<OrgInfo[]>;
10
+ export declare function registerOrgs(program: Command): void;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchMyOrgs = fetchMyOrgs;
4
+ exports.registerOrgs = registerOrgs;
5
+ const config_js_1 = require("../lib/config.js");
6
+ async function fetchMyOrgs(token) {
7
+ const res = await fetch(`${config_js_1.API_URL}/api/orgs`, {
8
+ headers: { Authorization: `Bearer ${token}` },
9
+ signal: AbortSignal.timeout(8000),
10
+ });
11
+ if (!res.ok) {
12
+ throw new Error(`Organization 목록 조회 실패 (${res.status})`);
13
+ }
14
+ return (await res.json());
15
+ }
16
+ function registerOrgs(program) {
17
+ const orgsCmd = program
18
+ .command('orgs')
19
+ .description('Organization 관련 명령어');
20
+ orgsCmd
21
+ .command('list')
22
+ .description('내 Organization 목록을 확인합니다')
23
+ .action(async () => {
24
+ const json = program.opts().json ?? false;
25
+ const token = await (0, config_js_1.getValidToken)();
26
+ if (!token) {
27
+ if (json) {
28
+ console.error(JSON.stringify({ error: 'LOGIN_REQUIRED', message: '로그인이 필요합니다.', fix: 'relay login 실행 후 재시도하세요.' }));
29
+ }
30
+ else {
31
+ console.error('\x1b[31m오류: 로그인이 필요합니다.\x1b[0m');
32
+ console.error(' relay login을 먼저 실행하세요.');
33
+ }
34
+ process.exit(1);
35
+ }
36
+ try {
37
+ const orgs = await fetchMyOrgs(token);
38
+ if (json) {
39
+ console.log(JSON.stringify({ orgs }));
40
+ return;
41
+ }
42
+ if (orgs.length === 0) {
43
+ console.log('\nOrganization이 없습니다.');
44
+ console.log('\x1b[33m Organization을 만들려면: relay orgs create "이름"\x1b[0m');
45
+ }
46
+ else {
47
+ console.log(`\n\x1b[1m내 Organization\x1b[0m (${orgs.length}개):\n`);
48
+ for (const o of orgs) {
49
+ const role = o.role === 'owner' ? '\x1b[33m오너\x1b[0m'
50
+ : o.role === 'admin' ? '\x1b[36m관리자\x1b[0m'
51
+ : o.role === 'builder' ? '\x1b[36m빌더\x1b[0m'
52
+ : '\x1b[90m멤버\x1b[0m';
53
+ const desc = o.description
54
+ ? ` \x1b[90m${o.description.length > 40 ? o.description.slice(0, 40) + '...' : o.description}\x1b[0m`
55
+ : '';
56
+ console.log(` \x1b[36m@${o.slug}\x1b[0m \x1b[1m${o.name}\x1b[0m ${role}${desc}`);
57
+ }
58
+ }
59
+ }
60
+ catch (err) {
61
+ const message = err instanceof Error ? err.message : String(err);
62
+ if (json) {
63
+ console.error(JSON.stringify({ error: 'FETCH_FAILED', message, fix: '네트워크 연결을 확인하거나 잠시 후 재시도하세요.' }));
64
+ }
65
+ else {
66
+ console.error(`\x1b[31m오류: ${message}\x1b[0m`);
67
+ }
68
+ process.exit(1);
69
+ }
70
+ });
71
+ orgsCmd
72
+ .command('create <name>')
73
+ .description('새 Organization을 생성합니다')
74
+ .option('--slug <slug>', 'URL slug (미지정 시 이름에서 자동 생성)')
75
+ .action(async (name, opts) => {
76
+ const json = program.opts().json ?? false;
77
+ const token = await (0, config_js_1.getValidToken)();
78
+ if (!token) {
79
+ if (json) {
80
+ console.error(JSON.stringify({ error: 'LOGIN_REQUIRED', message: '로그인이 필요합니다.', fix: 'relay login 실행 후 재시도하세요.' }));
81
+ }
82
+ else {
83
+ console.error('\x1b[31m오류: 로그인이 필요합니다.\x1b[0m');
84
+ }
85
+ process.exit(1);
86
+ }
87
+ const slug = opts.slug ?? name
88
+ .toLowerCase()
89
+ .replace(/[^a-z0-9\s-]/g, '')
90
+ .replace(/[\s]+/g, '-')
91
+ .replace(/-+/g, '-')
92
+ .replace(/^-|-$/g, '')
93
+ .slice(0, 50);
94
+ try {
95
+ const res = await fetch(`${config_js_1.API_URL}/api/orgs`, {
96
+ method: 'POST',
97
+ headers: {
98
+ 'Content-Type': 'application/json',
99
+ Authorization: `Bearer ${token}`,
100
+ },
101
+ body: JSON.stringify({ name, slug }),
102
+ });
103
+ if (!res.ok) {
104
+ const body = await res.json().catch(() => ({ message: `${res.status}` }));
105
+ throw new Error(body.message ?? `Organization 생성 실패 (${res.status})`);
106
+ }
107
+ const org = await res.json();
108
+ if (json) {
109
+ console.log(JSON.stringify({ status: 'created', org }));
110
+ }
111
+ else {
112
+ console.log(`\x1b[32m✅ Organization "${org.name}" (@${org.slug}) 생성 완료\x1b[0m`);
113
+ console.log(`\n\x1b[33m 팀 배포: relay publish --org ${org.slug}\x1b[0m`);
114
+ console.log(`\x1b[33m 멤버 초대: www.relayax.com/orgs/${org.slug}/members\x1b[0m`);
115
+ }
116
+ }
117
+ catch (err) {
118
+ const message = err instanceof Error ? err.message : String(err);
119
+ if (json) {
120
+ console.error(JSON.stringify({ error: 'CREATE_FAILED', message }));
121
+ }
122
+ else {
123
+ console.error(`\x1b[31m오류: ${message}\x1b[0m`);
124
+ }
125
+ process.exit(1);
126
+ }
127
+ });
128
+ }
@@ -445,90 +445,84 @@ function registerPublish(program) {
445
445
  }));
446
446
  process.exit(1);
447
447
  }
448
- // Fetch user's Spaces and select publish target
449
- let selectedSpaceId;
450
- let selectedSpaceSlug;
451
- let selectedJoinPolicy;
448
+ // Fetch user's Orgs and select publish target
449
+ let selectedOrgId;
450
+ let selectedOrgSlug;
452
451
  try {
453
- const { fetchMySpaces } = await import('./spaces.js');
454
- const spaces = await fetchMySpaces(token);
455
- // --space flag: resolve Space by slug
452
+ const { fetchMyOrgs } = await import('./orgs.js');
453
+ const orgs = await fetchMyOrgs(token);
454
+ // --space flag (legacy alias for --org): resolve Org by slug
456
455
  if (opts.space) {
457
- const matched = spaces.find((s) => s.slug === opts.space);
456
+ const matched = orgs.find((o) => o.slug === opts.space);
458
457
  if (matched) {
459
- selectedSpaceId = matched.id;
460
- selectedSpaceSlug = matched.slug;
461
- selectedJoinPolicy = matched.join_policy;
458
+ selectedOrgId = matched.id;
459
+ selectedOrgSlug = matched.slug;
462
460
  }
463
461
  else {
464
462
  if (json) {
465
463
  console.error(JSON.stringify({
466
- error: 'INVALID_SPACE',
467
- message: `Space '${opts.space}'를 찾을 수 없습니다.`,
468
- fix: `사용 가능한 Space: ${spaces.map((s) => s.slug).join(', ')}`,
469
- options: spaces.map((s) => ({ value: s.slug, label: `${s.name} (${s.slug})` })),
464
+ error: 'INVALID_ORG',
465
+ message: `Organization '${opts.space}'를 찾을 수 없습니다.`,
466
+ fix: `사용 가능한 Org: ${orgs.map((o) => o.slug).join(', ')}`,
467
+ options: orgs.map((o) => ({ value: o.slug, label: `${o.name} (${o.slug})` })),
470
468
  }));
471
469
  }
472
470
  else {
473
- console.error(`Space '${opts.space}'를 찾을 수 없습니다.`);
471
+ console.error(`Organization '${opts.space}'를 찾을 수 없습니다.`);
474
472
  }
475
473
  process.exit(1);
476
474
  }
477
475
  }
478
476
  else if (isTTY) {
479
- if (spaces.length === 0) {
480
- // No spaces at all — publish without space_id
481
- console.error('\x1b[33m⚠ 소속 Space가 없습니다. 개인 계정으로 배포합니다.\x1b[0m\n');
477
+ if (orgs.length === 0) {
478
+ // No orgs — publish without org_id
479
+ console.error('\x1b[33m⚠ 소속 Organization이 없습니다. 개인 계정으로 배포합니다.\x1b[0m\n');
482
480
  }
483
- else if (spaces.length === 1) {
484
- // Only one Space — auto-select regardless of type
485
- selectedSpaceId = spaces[0].id;
486
- selectedSpaceSlug = spaces[0].slug;
487
- selectedJoinPolicy = spaces[0].join_policy;
488
- console.error(`\x1b[2m Space: ${spaces[0].name} (${spaces[0].slug})\x1b[0m\n`);
481
+ else if (orgs.length === 1) {
482
+ // Only one Org — auto-select
483
+ selectedOrgId = orgs[0].id;
484
+ selectedOrgSlug = orgs[0].slug;
485
+ console.error(`\x1b[2m Organization: ${orgs[0].name} (${orgs[0].slug})\x1b[0m\n`);
489
486
  }
490
487
  else {
491
- // Multiple spaces — prompt user
492
- const { select: selectSpace } = await import('@inquirer/prompts');
493
- const spaceChoices = spaces.map((s) => ({
494
- name: `${s.name} (${s.slug})`,
495
- value: s.id,
496
- slug: s.slug,
497
- join_policy: s.join_policy,
488
+ // Multiple orgs — prompt user
489
+ const { select: selectOrg } = await import('@inquirer/prompts');
490
+ const orgChoices = orgs.map((o) => ({
491
+ name: `${o.name} (${o.slug})`,
492
+ value: o.id,
493
+ slug: o.slug,
498
494
  }));
499
- const chosenId = await selectSpace({
500
- message: '어떤 Space에 배포할까요?',
501
- choices: spaceChoices.map((c) => ({ name: c.name, value: c.value })),
495
+ const chosenId = await selectOrg({
496
+ message: '어떤 Organization에 배포할까요?',
497
+ choices: orgChoices.map((c) => ({ name: c.name, value: c.value })),
502
498
  });
503
- const chosen = spaceChoices.find((c) => c.value === chosenId);
504
- selectedSpaceId = chosenId;
505
- selectedSpaceSlug = chosen?.slug;
506
- selectedJoinPolicy = chosen?.join_policy;
499
+ const chosen = orgChoices.find((c) => c.value === chosenId);
500
+ selectedOrgId = chosenId;
501
+ selectedOrgSlug = chosen?.slug;
507
502
  const chosenLabel = chosen?.name ?? chosenId;
508
- console.error(` → Space: ${chosenLabel}\n`);
503
+ console.error(` → Organization: ${chosenLabel}\n`);
509
504
  }
510
505
  }
511
- else if (spaces.length > 1 && json) {
512
- // --json 모드 + 여러 Space: 에이전트가 선택할 수 있도록 에러 반환
506
+ else if (orgs.length > 1 && json) {
507
+ // --json 모드 + 여러 Org: 에이전트가 선택할 수 있도록 에러 반환
513
508
  console.error(JSON.stringify({
514
- error: 'MISSING_SPACE',
515
- message: '배포할 Space를 선택하세요.',
516
- fix: `relay publish --space <slug> --json`,
517
- options: spaces.map((s) => ({ value: s.slug, label: `${s.name} (${s.slug})` })),
509
+ error: 'MISSING_ORG',
510
+ message: '배포할 Organization을 선택하세요.',
511
+ fix: `relay publish --org <slug> --json`,
512
+ options: orgs.map((o) => ({ value: o.slug, label: `${o.name} (${o.slug})` })),
518
513
  }));
519
514
  process.exit(1);
520
515
  }
521
- else if (spaces.length > 0) {
522
- selectedSpaceId = spaces[0].id;
523
- selectedSpaceSlug = spaces[0].slug;
524
- selectedJoinPolicy = spaces[0].join_policy;
516
+ else if (orgs.length > 0) {
517
+ selectedOrgId = orgs[0].id;
518
+ selectedOrgSlug = orgs[0].slug;
525
519
  }
526
520
  }
527
521
  catch {
528
- // Space 조회 실패 시 무시하고 계속 진행
522
+ // Org 조회 실패 시 무시하고 계속 진행
529
523
  }
530
- // Visibility default based on join_policy: approval → private, otherwise → public
531
- const defaultVisibility = selectedJoinPolicy === 'approval' ? 'private' : 'public';
524
+ // Visibility default
525
+ const defaultVisibility = 'public';
532
526
  // Visibility validation: must be explicitly set
533
527
  if (!config.visibility) {
534
528
  if (isTTY) {
@@ -546,7 +540,7 @@ function registerPublish(program) {
546
540
  value: 'gated',
547
541
  },
548
542
  {
549
- name: `비공개 — Space 멤버만 접근${defaultVisibility === 'private' ? ' ✓ 추천' : ''}`,
543
+ name: `비공개 — Space 멤버만 접근`,
550
544
  value: 'private',
551
545
  },
552
546
  ],
@@ -593,7 +587,7 @@ function registerPublish(program) {
593
587
  value: 'gated',
594
588
  },
595
589
  {
596
- name: `비공개 — Space 멤버만 접근${defaultVisibility === 'private' ? ' ✓ 추천' : ''}`,
590
+ name: `비공개 — Space 멤버만 접근`,
597
591
  value: 'private',
598
592
  },
599
593
  ],
@@ -638,8 +632,8 @@ function registerPublish(program) {
638
632
  type: config.type ?? 'hybrid',
639
633
  agent_details: detectedAgents,
640
634
  skill_details: detectedSkills,
641
- ...(selectedSpaceId ? { space_id: selectedSpaceId } : {}),
642
- ...(selectedSpaceSlug ? { space_slug: selectedSpaceSlug } : {}),
635
+ ...(selectedOrgId ? { org_id: selectedOrgId } : {}),
636
+ ...(selectedOrgSlug ? { org_slug: selectedOrgSlug } : {}),
643
637
  };
644
638
  if (!json) {
645
639
  console.error(`패키지 생성 중... (${config.name} v${config.version})`);
@@ -32,7 +32,7 @@ function registerSearch(program) {
32
32
  .action(async (keyword, opts) => {
33
33
  const json = program.opts().json ?? false;
34
34
  try {
35
- const results = await (0, api_js_1.searchTeams)(keyword, opts.tag, opts.space);
35
+ const results = await (0, api_js_1.searchTeams)(keyword, opts.tag);
36
36
  if (json) {
37
37
  console.log(JSON.stringify({ results }));
38
38
  }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerVersions(program: Command): void;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerVersions = registerVersions;
4
+ const api_js_1 = require("../lib/api.js");
5
+ const slug_js_1 = require("../lib/slug.js");
6
+ function registerVersions(program) {
7
+ program
8
+ .command('versions <slug>')
9
+ .description('팀 버전 목록과 릴리즈 노트를 확인합니다')
10
+ .action(async (slugInput) => {
11
+ const json = program.opts().json ?? false;
12
+ try {
13
+ const resolved = await (0, slug_js_1.resolveSlug)(slugInput);
14
+ const versions = await (0, api_js_1.fetchTeamVersions)(resolved.full);
15
+ if (json) {
16
+ console.log(JSON.stringify({ slug: resolved.full, versions }));
17
+ return;
18
+ }
19
+ if (versions.length === 0) {
20
+ console.log(`\n${resolved.full} 버전 이력이 없습니다.`);
21
+ return;
22
+ }
23
+ console.log(`\n\x1b[1m${resolved.full} 버전 이력\x1b[0m (${versions.length}개):\n`);
24
+ for (const v of versions) {
25
+ const date = new Date(v.created_at).toLocaleDateString('ko-KR');
26
+ console.log(` \x1b[36mv${v.version}\x1b[0m (${date})`);
27
+ if (v.changelog) {
28
+ console.log(` \x1b[90m${v.changelog}\x1b[0m`);
29
+ }
30
+ }
31
+ console.log(`\n\x1b[33m 특정 버전 설치: relay install ${resolved.full}@<version>\x1b[0m`);
32
+ }
33
+ catch (err) {
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ if (json) {
36
+ console.error(JSON.stringify({ error: 'VERSIONS_FAILED', message }));
37
+ }
38
+ else {
39
+ console.error(`\x1b[31m오류: ${message}\x1b[0m`);
40
+ }
41
+ process.exit(1);
42
+ }
43
+ });
44
+ }
package/dist/index.js CHANGED
@@ -18,10 +18,12 @@ const check_update_js_1 = require("./commands/check-update.js");
18
18
  const follow_js_1 = require("./commands/follow.js");
19
19
  const changelog_js_1 = require("./commands/changelog.js");
20
20
  const join_js_1 = require("./commands/join.js");
21
- const spaces_js_1 = require("./commands/spaces.js");
21
+ const orgs_js_1 = require("./commands/orgs.js");
22
22
  const deploy_record_js_1 = require("./commands/deploy-record.js");
23
23
  const ping_js_1 = require("./commands/ping.js");
24
24
  const access_js_1 = require("./commands/access.js");
25
+ const versions_js_1 = require("./commands/versions.js");
26
+ const diff_js_1 = require("./commands/diff.js");
25
27
  // eslint-disable-next-line @typescript-eslint/no-var-requires
26
28
  const pkg = require('../package.json');
27
29
  const program = new commander_1.Command();
@@ -46,8 +48,10 @@ program
46
48
  (0, follow_js_1.registerFollow)(program);
47
49
  (0, changelog_js_1.registerChangelog)(program);
48
50
  (0, join_js_1.registerJoin)(program);
49
- (0, spaces_js_1.registerSpaces)(program);
51
+ (0, orgs_js_1.registerOrgs)(program);
50
52
  (0, deploy_record_js_1.registerDeployRecord)(program);
51
53
  (0, ping_js_1.registerPing)(program);
52
54
  (0, access_js_1.registerAccess)(program);
55
+ (0, versions_js_1.registerVersions)(program);
56
+ (0, diff_js_1.registerDiff)(program);
53
57
  program.parse();
package/dist/lib/api.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import type { TeamRegistryInfo, SearchResult } from '../types.js';
2
+ export declare function fetchMyOrgs(): Promise<{
3
+ id: string;
4
+ slug: string;
5
+ name: string;
6
+ role: string;
7
+ }[]>;
2
8
  export declare function fetchTeamInfo(slug: string): Promise<TeamRegistryInfo>;
3
- export declare function searchTeams(query: string, tag?: string, space?: string): Promise<SearchResult[]>;
9
+ export declare function searchTeams(query: string, tag?: string): Promise<SearchResult[]>;
4
10
  export interface TeamVersionInfo {
5
11
  version: string;
6
12
  changelog: string | null;
@@ -8,11 +14,6 @@ export interface TeamVersionInfo {
8
14
  }
9
15
  export declare function fetchTeamVersions(slug: string): Promise<TeamVersionInfo[]>;
10
16
  export declare function reportInstall(teamId: string, slug: string, version?: string): Promise<void>;
11
- /**
12
- * Space 팀 설치: 멤버십 검증 + install count 증가 + 팀 메타데이터 반환을 한 번에 처리.
13
- * POST /api/spaces/{spaceSlug}/teams/{teamSlug}/install
14
- */
15
- export declare function installSpaceTeam(spaceSlug: string, teamSlug: string, version?: string): Promise<TeamRegistryInfo>;
16
17
  export interface ResolvedSlug {
17
18
  owner: string;
18
19
  name: string;
package/dist/lib/api.js CHANGED
@@ -1,14 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchMyOrgs = fetchMyOrgs;
3
4
  exports.fetchTeamInfo = fetchTeamInfo;
4
5
  exports.searchTeams = searchTeams;
5
6
  exports.fetchTeamVersions = fetchTeamVersions;
6
7
  exports.reportInstall = reportInstall;
7
- exports.installSpaceTeam = installSpaceTeam;
8
8
  exports.resolveSlugFromServer = resolveSlugFromServer;
9
9
  exports.sendUsagePing = sendUsagePing;
10
10
  exports.followBuilder = followBuilder;
11
11
  const config_js_1 = require("./config.js");
12
+ async function fetchMyOrgs() {
13
+ const token = await (0, config_js_1.getValidToken)();
14
+ if (!token)
15
+ return [];
16
+ const res = await fetch(`${config_js_1.API_URL}/api/orgs`, {
17
+ headers: { Authorization: `Bearer ${token}` },
18
+ signal: AbortSignal.timeout(8000),
19
+ });
20
+ if (!res.ok)
21
+ return [];
22
+ return res.json();
23
+ }
12
24
  async function fetchTeamInfo(slug) {
13
25
  const registrySlug = slug.startsWith('@') ? slug.slice(1) : slug;
14
26
  const url = `${config_js_1.API_URL}/api/registry/${registrySlug}`;
@@ -19,12 +31,10 @@ async function fetchTeamInfo(slug) {
19
31
  }
20
32
  return res.json();
21
33
  }
22
- async function searchTeams(query, tag, space) {
34
+ async function searchTeams(query, tag) {
23
35
  const params = new URLSearchParams({ q: query });
24
36
  if (tag)
25
37
  params.set('tag', tag);
26
- if (space)
27
- params.set('space', space);
28
38
  const url = `${config_js_1.API_URL}/api/registry/search?${params.toString()}`;
29
39
  const res = await fetch(url);
30
40
  if (!res.ok) {
@@ -69,31 +79,6 @@ async function reportInstall(teamId, slug, version) {
69
79
  // network error: ignore silently
70
80
  }
71
81
  }
72
- /**
73
- * Space 팀 설치: 멤버십 검증 + install count 증가 + 팀 메타데이터 반환을 한 번에 처리.
74
- * POST /api/spaces/{spaceSlug}/teams/{teamSlug}/install
75
- */
76
- async function installSpaceTeam(spaceSlug, teamSlug, version) {
77
- const url = `${config_js_1.API_URL}/api/spaces/${spaceSlug}/teams/${teamSlug}/install`;
78
- const headers = { 'Content-Type': 'application/json' };
79
- const token = await (0, config_js_1.getValidToken)();
80
- if (token) {
81
- headers['Authorization'] = `Bearer ${token}`;
82
- }
83
- const body = {};
84
- if (version)
85
- body.version = version;
86
- const res = await fetch(url, {
87
- method: 'POST',
88
- headers,
89
- body: JSON.stringify(body),
90
- });
91
- if (!res.ok) {
92
- const text = await res.text();
93
- throw new Error(`Space 팀 설치 실패 (${res.status}): ${text}`);
94
- }
95
- return res.json();
96
- }
97
82
  async function resolveSlugFromServer(name) {
98
83
  const url = `${config_js_1.API_URL}/api/registry/resolve?name=${encodeURIComponent(name)}`;
99
84
  const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
@@ -412,7 +412,7 @@ https://relayax.com/api/registry/{owner}/{slug}/guide.md
412
412
  "installed_at": "2026-03-20T12:00:00.000Z",
413
413
  "scope": "global",
414
414
  "deploy_scope": "global",
415
- "space_slug": null
415
+ "org_slug": null
416
416
  }
417
417
  ]
418
418
  }
@@ -425,19 +425,19 @@ https://relayax.com/api/registry/{owner}/{slug}/guide.md
425
425
  | @author/team-name | v1.2.0 | 글로벌 | 3/20 |
426
426
 
427
427
  - \`deploy_scope\`가 \`"global"\` → 글로벌, \`"local"\` → 로컬, 없으면 → 미배치
428
- - \`space_slug\`가 있으면 \`[Space: slug]\` 표시
428
+ - \`org_slug\`가 있으면 \`[Org: slug]\` 표시
429
429
 
430
- ### 2. Space 목록
430
+ ### 2. Organization 목록
431
431
 
432
- \`relay spaces --json\` 명령어를 실행합니다.
432
+ \`relay orgs list --json\` 명령어를 실행합니다.
433
433
 
434
434
  **JSON 응답 구조:**
435
435
  \`\`\`json
436
436
  {
437
- "spaces": [
437
+ "orgs": [
438
438
  {
439
- "slug": "my-space",
440
- "name": "내 스페이스",
439
+ "slug": "my-org",
440
+ "name": "내 조직",
441
441
  "description": "설명",
442
442
  "role": "owner"
443
443
  }
@@ -446,24 +446,24 @@ https://relayax.com/api/registry/{owner}/{slug}/guide.md
446
446
  \`\`\`
447
447
 
448
448
  **표시:**
449
- - \`role\`: owner → 소유자, builder → 빌더, member → 멤버
449
+ - \`role\`: owner → 오너, admin → 관리자, builder → 빌더, member → 멤버
450
450
  ${ERROR_HANDLING_GUIDE}
451
- - Spaces 조회 실패해도 설치된 팀 목록은 정상 표시합니다 (로컬 데이터).
451
+ - Org 조회 실패해도 설치된 팀 목록은 정상 표시합니다 (로컬 데이터).
452
452
 
453
- ### 3. Space 팀 목록 (옵션)
454
- - \`--space <slug>\` 인자가 있으면: \`relay list --space <space-slug> --json\`으로 해당 Space에서 설치 가능한 팀 목록도 보여줍니다.
453
+ ### 3. Org 팀 목록 (옵션)
454
+ - \`--org <slug>\` 인자가 있으면: \`relay list --org <org-slug> --json\`으로 해당 Organization의 팀 목록도 보여줍니다.
455
455
 
456
456
  ### 4. 안내
457
457
  - 설치된 팀이 없으면 \`/relay-install\`로 팀을 탐색·설치해보라고 안내합니다.
458
- - Space가 있으면 활용법을 안내합니다:
459
- - 비공개 팀 설치: \`relay install @spaces/<slug>/<team>\`
460
- - Space 관리: www.relayax.com/spaces/<slug>
458
+ - Org가 있으면 활용법을 안내합니다:
459
+ - Org 팀 설치: \`relay install @<org-slug>/<team>\`
460
+ - Org 관리: www.relayax.com/orgs/<slug>
461
461
 
462
462
  ## 예시
463
463
 
464
464
  사용자: /relay-status
465
465
  → relay list --json 실행
466
- → relay spaces --json 실행 (병렬 가능)
466
+ → relay orgs list --json 실행 (병렬 가능)
467
467
 
468
468
  **설치된 팀 (2개)**
469
469