relayax-cli 0.1.0 → 0.1.1

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.
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.registerLogin = registerLogin;
4
- const readline_1 = require("readline");
7
+ const http_1 = __importDefault(require("http"));
5
8
  const child_process_1 = require("child_process");
6
9
  const config_js_1 = require("../lib/config.js");
7
10
  function openBrowser(url) {
@@ -21,15 +24,6 @@ function openBrowser(url) {
21
24
  // ignore browser open errors
22
25
  }
23
26
  }
24
- async function readLine(prompt) {
25
- const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stderr });
26
- return new Promise((resolve) => {
27
- rl.question(prompt, (answer) => {
28
- rl.close();
29
- resolve(answer.trim());
30
- });
31
- });
32
- }
33
27
  async function verifyToken(apiUrl, token) {
34
28
  try {
35
29
  const res = await fetch(`${apiUrl}/api/auth/me`, {
@@ -43,10 +37,63 @@ async function verifyToken(apiUrl, token) {
43
37
  return null;
44
38
  }
45
39
  }
40
+ function waitForToken(port) {
41
+ return new Promise((resolve, reject) => {
42
+ const server = http_1.default.createServer((req, res) => {
43
+ const url = new URL(req.url ?? '/', `http://localhost:${port}`);
44
+ if (url.pathname === '/callback') {
45
+ const token = url.searchParams.get('token');
46
+ // Send a nice HTML response that auto-closes
47
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
48
+ res.end(`<!DOCTYPE html>
49
+ <html><head><title>RelayAX</title></head>
50
+ <body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f6f5f2;color:#111318">
51
+ <div style="text-align:center">
52
+ <h2>로그인 완료!</h2>
53
+ <p>터미널로 돌아가세요. 이 창은 닫아도 됩니다.</p>
54
+ <script>setTimeout(()=>window.close(),2000)</script>
55
+ </div>
56
+ </body></html>`);
57
+ server.close();
58
+ if (token) {
59
+ resolve(token);
60
+ }
61
+ else {
62
+ reject(new Error('토큰이 전달되지 않았습니다'));
63
+ }
64
+ }
65
+ else {
66
+ res.writeHead(404);
67
+ res.end('Not found');
68
+ }
69
+ });
70
+ server.listen(port, '127.0.0.1');
71
+ // Timeout after 5 minutes
72
+ setTimeout(() => {
73
+ server.close();
74
+ reject(new Error('로그인 시간이 초과되었습니다 (5분)'));
75
+ }, 5 * 60 * 1000);
76
+ });
77
+ }
78
+ function findAvailablePort() {
79
+ return new Promise((resolve, reject) => {
80
+ const server = http_1.default.createServer();
81
+ server.listen(0, '127.0.0.1', () => {
82
+ const addr = server.address();
83
+ if (addr && typeof addr !== 'string') {
84
+ const port = addr.port;
85
+ server.close(() => resolve(port));
86
+ }
87
+ else {
88
+ server.close(() => reject(new Error('포트를 찾을 수 없습니다')));
89
+ }
90
+ });
91
+ });
92
+ }
46
93
  function registerLogin(program) {
47
94
  program
48
95
  .command('login')
49
- .description('Relay 계정에 로그인합니다')
96
+ .description('RelayAX 계정에 로그인합니다')
50
97
  .option('--token <token>', '직접 토큰 입력 (브라우저 없이)')
51
98
  .action(async (opts) => {
52
99
  const pretty = program.opts().pretty ?? false;
@@ -55,15 +102,18 @@ function registerLogin(program) {
55
102
  const apiUrl = config?.api_url ?? 'https://relayax.com';
56
103
  let token = opts.token;
57
104
  if (!token) {
58
- const tokenUrl = `${apiUrl}/auth/token`;
59
- console.error('브라우저에서 로그인 표시되는 토큰을 복사하세요.');
60
- console.error(`\n ${tokenUrl}\n`);
61
- openBrowser(tokenUrl);
62
- token = await readLine('토큰 붙여넣기: ');
63
- }
64
- if (!token) {
65
- console.error(JSON.stringify({ error: 'NO_TOKEN', message: '토큰이 입력되지 않았습니다' }));
66
- process.exit(1);
105
+ try {
106
+ const port = await findAvailablePort();
107
+ const loginUrl = `${apiUrl}/auth/cli-login?port=${port}`;
108
+ console.error('브라우저에서 로그인을 진행합니다...');
109
+ openBrowser(loginUrl);
110
+ token = await waitForToken(port);
111
+ }
112
+ catch (err) {
113
+ const msg = err instanceof Error ? err.message : '로그인 실패';
114
+ console.error(JSON.stringify({ error: 'LOGIN_FAILED', message: msg }));
115
+ process.exit(1);
116
+ }
67
117
  }
68
118
  const user = await verifyToken(apiUrl, token);
69
119
  const updatedConfig = {
@@ -81,7 +131,6 @@ function registerLogin(program) {
81
131
  console.log(`\x1b[32m✓ 로그인 완료\x1b[0m`);
82
132
  if (user?.email)
83
133
  console.log(` 계정: \x1b[36m${user.email}\x1b[0m`);
84
- console.log(` 토큰이 ~/.relay/config.json에 저장되었습니다.`);
85
134
  }
86
135
  else {
87
136
  console.log(JSON.stringify(result));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relayax-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "RelayAX Agent Team Marketplace CLI - Install and manage agent teams",
5
5
  "main": "dist/index.js",
6
6
  "bin": {