@redonvn/cli 0.1.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 (141) hide show
  1. package/README.md +99 -0
  2. package/bin/redai.js +22 -0
  3. package/dist/auth/client-id.d.ts +8 -0
  4. package/dist/auth/client-id.js +41 -0
  5. package/dist/auth/client-id.js.map +1 -0
  6. package/dist/auth/store.d.ts +16 -0
  7. package/dist/auth/store.js +39 -0
  8. package/dist/auth/store.js.map +1 -0
  9. package/dist/cli/commands/login.d.ts +6 -0
  10. package/dist/cli/commands/login.js +82 -0
  11. package/dist/cli/commands/login.js.map +1 -0
  12. package/dist/cli/commands/logout.d.ts +1 -0
  13. package/dist/cli/commands/logout.js +18 -0
  14. package/dist/cli/commands/logout.js.map +1 -0
  15. package/dist/cli/commands/oauth.d.ts +11 -0
  16. package/dist/cli/commands/oauth.js +311 -0
  17. package/dist/cli/commands/oauth.js.map +1 -0
  18. package/dist/cli/commands/serve.d.ts +7 -0
  19. package/dist/cli/commands/serve.js +24 -0
  20. package/dist/cli/commands/serve.js.map +1 -0
  21. package/dist/cli/commands/start.d.ts +1 -0
  22. package/dist/cli/commands/start.js +26 -0
  23. package/dist/cli/commands/start.js.map +1 -0
  24. package/dist/cli/commands/status.d.ts +1 -0
  25. package/dist/cli/commands/status.js +51 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/index.d.ts +2 -0
  28. package/dist/cli/index.js +127 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/cli-router/detect.d.ts +13 -0
  31. package/dist/cli-router/detect.js +58 -0
  32. package/dist/cli-router/detect.js.map +1 -0
  33. package/dist/config.d.ts +12 -0
  34. package/dist/config.js +24 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/daemon/router.d.ts +17 -0
  37. package/dist/daemon/router.js +39 -0
  38. package/dist/daemon/router.js.map +1 -0
  39. package/dist/daemon/tunnel.d.ts +10 -0
  40. package/dist/daemon/tunnel.js +156 -0
  41. package/dist/daemon/tunnel.js.map +1 -0
  42. package/dist/llm/llm-request.d.ts +9 -0
  43. package/dist/llm/llm-request.js +98 -0
  44. package/dist/llm/llm-request.js.map +1 -0
  45. package/dist/llm/oauth/antigravity-oauth.d.ts +22 -0
  46. package/dist/llm/oauth/antigravity-oauth.js +128 -0
  47. package/dist/llm/oauth/antigravity-oauth.js.map +1 -0
  48. package/dist/llm/oauth/callback-server.d.ts +18 -0
  49. package/dist/llm/oauth/callback-server.js +78 -0
  50. package/dist/llm/oauth/callback-server.js.map +1 -0
  51. package/dist/llm/oauth/claude-oauth.d.ts +29 -0
  52. package/dist/llm/oauth/claude-oauth.js +115 -0
  53. package/dist/llm/oauth/claude-oauth.js.map +1 -0
  54. package/dist/llm/oauth/codex-oauth.d.ts +21 -0
  55. package/dist/llm/oauth/codex-oauth.js +137 -0
  56. package/dist/llm/oauth/codex-oauth.js.map +1 -0
  57. package/dist/llm/oauth/gemini-oauth.d.ts +26 -0
  58. package/dist/llm/oauth/gemini-oauth.js +132 -0
  59. package/dist/llm/oauth/gemini-oauth.js.map +1 -0
  60. package/dist/llm/oauth/iflow-oauth.d.ts +26 -0
  61. package/dist/llm/oauth/iflow-oauth.js +151 -0
  62. package/dist/llm/oauth/iflow-oauth.js.map +1 -0
  63. package/dist/llm/oauth/kimi-oauth.d.ts +16 -0
  64. package/dist/llm/oauth/kimi-oauth.js +126 -0
  65. package/dist/llm/oauth/kimi-oauth.js.map +1 -0
  66. package/dist/llm/oauth/open-browser.d.ts +5 -0
  67. package/dist/llm/oauth/open-browser.js +32 -0
  68. package/dist/llm/oauth/open-browser.js.map +1 -0
  69. package/dist/llm/oauth/pkce.d.ts +12 -0
  70. package/dist/llm/oauth/pkce.js +27 -0
  71. package/dist/llm/oauth/pkce.js.map +1 -0
  72. package/dist/llm/oauth/qwen-oauth.d.ts +27 -0
  73. package/dist/llm/oauth/qwen-oauth.js +138 -0
  74. package/dist/llm/oauth/qwen-oauth.js.map +1 -0
  75. package/dist/llm/oauth/store.d.ts +34 -0
  76. package/dist/llm/oauth/store.js +72 -0
  77. package/dist/llm/oauth/store.js.map +1 -0
  78. package/dist/llm/oauth/xai-oauth.d.ts +28 -0
  79. package/dist/llm/oauth/xai-oauth.js +132 -0
  80. package/dist/llm/oauth/xai-oauth.js.map +1 -0
  81. package/dist/llm/providers/antigravity.d.ts +23 -0
  82. package/dist/llm/providers/antigravity.js +103 -0
  83. package/dist/llm/providers/antigravity.js.map +1 -0
  84. package/dist/llm/providers/claude.d.ts +36 -0
  85. package/dist/llm/providers/claude.js +148 -0
  86. package/dist/llm/providers/claude.js.map +1 -0
  87. package/dist/llm/providers/codex.d.ts +23 -0
  88. package/dist/llm/providers/codex.js +122 -0
  89. package/dist/llm/providers/codex.js.map +1 -0
  90. package/dist/llm/providers/gemini.d.ts +23 -0
  91. package/dist/llm/providers/gemini.js +112 -0
  92. package/dist/llm/providers/gemini.js.map +1 -0
  93. package/dist/llm/providers/generic-client.d.ts +45 -0
  94. package/dist/llm/providers/generic-client.js +98 -0
  95. package/dist/llm/providers/generic-client.js.map +1 -0
  96. package/dist/llm/providers/iflow.d.ts +8 -0
  97. package/dist/llm/providers/iflow.js +15 -0
  98. package/dist/llm/providers/iflow.js.map +1 -0
  99. package/dist/llm/providers/kimi.d.ts +8 -0
  100. package/dist/llm/providers/kimi.js +16 -0
  101. package/dist/llm/providers/kimi.js.map +1 -0
  102. package/dist/llm/providers/qwen.d.ts +8 -0
  103. package/dist/llm/providers/qwen.js +15 -0
  104. package/dist/llm/providers/qwen.js.map +1 -0
  105. package/dist/llm/providers/xai.d.ts +8 -0
  106. package/dist/llm/providers/xai.js +15 -0
  107. package/dist/llm/providers/xai.js.map +1 -0
  108. package/dist/llm/selector.d.ts +14 -0
  109. package/dist/llm/selector.js +81 -0
  110. package/dist/llm/selector.js.map +1 -0
  111. package/dist/server/http-server.d.ts +22 -0
  112. package/dist/server/http-server.js +194 -0
  113. package/dist/server/http-server.js.map +1 -0
  114. package/dist/tools/bash.d.ts +7 -0
  115. package/dist/tools/bash.js +61 -0
  116. package/dist/tools/bash.js.map +1 -0
  117. package/dist/tools/edit.d.ts +4 -0
  118. package/dist/tools/edit.js +35 -0
  119. package/dist/tools/edit.js.map +1 -0
  120. package/dist/tools/glob.d.ts +5 -0
  121. package/dist/tools/glob.js +27 -0
  122. package/dist/tools/glob.js.map +1 -0
  123. package/dist/tools/grep.d.ts +5 -0
  124. package/dist/tools/grep.js +63 -0
  125. package/dist/tools/grep.js.map +1 -0
  126. package/dist/tools/read.d.ts +6 -0
  127. package/dist/tools/read.js +25 -0
  128. package/dist/tools/read.js.map +1 -0
  129. package/dist/tools/registry.d.ts +8 -0
  130. package/dist/tools/registry.js +43 -0
  131. package/dist/tools/registry.js.map +1 -0
  132. package/dist/tools/run-cli.d.ts +7 -0
  133. package/dist/tools/run-cli.js +83 -0
  134. package/dist/tools/run-cli.js.map +1 -0
  135. package/dist/tools/webfetch.d.ts +7 -0
  136. package/dist/tools/webfetch.js +26 -0
  137. package/dist/tools/webfetch.js.map +1 -0
  138. package/dist/tools/write.d.ts +5 -0
  139. package/dist/tools/write.js +29 -0
  140. package/dist/tools/write.js.map +1 -0
  141. package/package.json +67 -0
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @redonvn/cli
2
+
3
+ RedAI CLI — kết nối máy bạn với RedAI agent runtime. AI cloud agent có thể:
4
+
5
+ - **Thao tác máy** qua tools: Read / Write / Edit / Bash / Grep / Glob / WebFetch
6
+ - **Spawn code-CLI** có sẵn: `claude` / `codex` / `gemini`
7
+ - **Proxy LLM request** qua OAuth của bạn: Claude Code, ChatGPT, Gemini Code Assist, Antigravity, Qwen, Kimi, iFlow, xAI Grok
8
+
9
+ ## Cài đặt
10
+
11
+ ```bash
12
+ npm i -g @redonvn/cli
13
+ ```
14
+
15
+ Yêu cầu Node.js ≥ 18.17.
16
+
17
+ ## Quick start
18
+
19
+ ### 1. Đăng nhập RedAI
20
+
21
+ Tạo API key trên dashboard RedAI với permission `cli:connect`, sau đó:
22
+
23
+ ```bash
24
+ redai login
25
+ # Paste API key khi prompt
26
+ ```
27
+
28
+ ### 2. (Tuỳ chọn) Đăng nhập OAuth provider để dùng quota của bạn
29
+
30
+ ```bash
31
+ redai oauth claude # Claude Code (PKCE)
32
+ redai oauth codex # Sign in with ChatGPT
33
+ redai oauth gemini # Gemini Code Assist
34
+ redai oauth antigravity # Antigravity (Google)
35
+ redai oauth qwen # Qwen (device flow)
36
+ redai oauth kimi # Kimi (device flow)
37
+ redai oauth iflow # iFlow (OAuth hoặc cookie)
38
+ redai oauth xai # xAI Grok (OIDC)
39
+
40
+ redai oauth list # xem tất cả account đã login
41
+ ```
42
+
43
+ ### 3. Chọn mode
44
+
45
+ **Mode A — Tunnel WS với RedAI cloud** (AI agent trên RedAI dùng máy bạn làm runtime):
46
+
47
+ ```bash
48
+ redai start
49
+ ```
50
+
51
+ Cloud worker gọi: `POST /cli/clients/<clientId>/actions/...`
52
+
53
+ **Mode B — HTTP local server** (Cursor / Cline / Claude Code trỏ tới localhost):
54
+
55
+ ```bash
56
+ redai serve --port 8317 --api-key <key>
57
+
58
+ # Cursor config: baseURL = http://localhost:8317/v1, apiKey = <key>
59
+ ```
60
+
61
+ Endpoints expose:
62
+ - `POST /v1/messages` → Claude
63
+ - `POST /v1/chat/completions` → Codex
64
+ - `POST /v1beta/models/*:action` → Gemini
65
+ - `POST /llm/<provider>/<rest>` → Generic passthrough cho mọi provider
66
+
67
+ ## Lệnh đầy đủ
68
+
69
+ ```
70
+ redai login [--api-key <k>] [--api-url <url>]
71
+ redai status
72
+ redai start
73
+ redai serve [--port 8317] [--host 127.0.0.1] [--api-key <k>]
74
+ redai logout
75
+
76
+ redai oauth <provider> [--account <name>] [--no-browser] [--cookie <c>]
77
+ redai oauth list
78
+ redai oauth logout <provider> [<account>]
79
+ ```
80
+
81
+ ## Files
82
+
83
+ ```
84
+ ~/.redai/
85
+ ├── config.json # cliToken + clientId (chmod 600)
86
+ ├── client.id # UUID stable của máy
87
+ └── oauth/
88
+ └── <provider>/<account>.json # OAuth token (chmod 600)
89
+ ```
90
+
91
+ ## Bảo mật
92
+
93
+ - OAuth token **chỉ lưu local**, RedAI server không thấy.
94
+ - API key chỉ gửi qua HTTPS để verify một lần, sau đó dùng `cliToken` JWT 90 ngày.
95
+ - File chmod 600 — chỉ chủ máy đọc được.
96
+
97
+ ## License
98
+
99
+ MIT
package/bin/redai.js ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Tiny launcher. Real logic in `dist/cli/index.js` (or `src/cli/index.ts` via ts-node in dev).
5
+ try {
6
+ require('../dist/cli/index.js');
7
+ } catch (err) {
8
+ if (err && err.code === 'MODULE_NOT_FOUND') {
9
+ // Dev mode fallback
10
+ try {
11
+ require('ts-node/register/transpile-only');
12
+ require('../src/cli/index.ts');
13
+ } catch (devErr) {
14
+ console.error('[redai] Failed to load CLI: ' + (devErr && devErr.message ? devErr.message : devErr));
15
+ console.error('[redai] If you installed via `npm i -g @redai/cli`, please report this issue.');
16
+ process.exit(1);
17
+ }
18
+ } else {
19
+ console.error('[redai] Fatal:', err && err.message ? err.message : err);
20
+ process.exit(1);
21
+ }
22
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Đọc UUID stable định danh máy. Tạo mới + lưu vào ~/.redai/client.id nếu chưa có.
3
+ * UUID này theo máy này suốt đời, kể cả khi user logout/login lại — để BE biết
4
+ * "vẫn là chiếc laptop X" và không tạo CliClient mới mỗi lần.
5
+ */
6
+ export declare function loadOrCreateClientId(): string;
7
+ export declare function configDir(): string;
8
+ export declare function configFilePath(): string;
@@ -0,0 +1,41 @@
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.loadOrCreateClientId = loadOrCreateClientId;
7
+ exports.configDir = configDir;
8
+ exports.configFilePath = configFilePath;
9
+ const crypto_1 = require("crypto");
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const config_1 = require("../config");
13
+ /**
14
+ * Đọc UUID stable định danh máy. Tạo mới + lưu vào ~/.redai/client.id nếu chưa có.
15
+ * UUID này theo máy này suốt đời, kể cả khi user logout/login lại — để BE biết
16
+ * "vẫn là chiếc laptop X" và không tạo CliClient mới mỗi lần.
17
+ */
18
+ function loadOrCreateClientId() {
19
+ ensureDir();
20
+ if (fs_1.default.existsSync(config_1.REDAI_CLIENT_ID_FILE)) {
21
+ const existing = fs_1.default.readFileSync(config_1.REDAI_CLIENT_ID_FILE, 'utf8').trim();
22
+ if (existing)
23
+ return existing;
24
+ }
25
+ const generated = `dsk-${(0, crypto_1.randomUUID)()}`;
26
+ fs_1.default.writeFileSync(config_1.REDAI_CLIENT_ID_FILE, generated, { encoding: 'utf8', mode: 0o600 });
27
+ return generated;
28
+ }
29
+ function ensureDir() {
30
+ if (!fs_1.default.existsSync(config_1.REDAI_CONFIG_DIR)) {
31
+ fs_1.default.mkdirSync(config_1.REDAI_CONFIG_DIR, { recursive: true, mode: 0o700 });
32
+ }
33
+ }
34
+ function configDir() {
35
+ ensureDir();
36
+ return config_1.REDAI_CONFIG_DIR;
37
+ }
38
+ function configFilePath() {
39
+ return path_1.default.join(config_1.REDAI_CONFIG_DIR, 'config.json');
40
+ }
41
+ //# sourceMappingURL=client-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-id.js","sourceRoot":"","sources":["../../src/auth/client-id.ts"],"names":[],"mappings":";;;;;AAUA,oDASC;AAQD,8BAGC;AAED,wCAEC;AAlCD,mCAAoC;AACpC,4CAAoB;AACpB,gDAAwB;AACxB,sCAAmE;AAEnE;;;;GAIG;AACH,SAAgB,oBAAoB;IAClC,SAAS,EAAE,CAAC;IACZ,IAAI,YAAE,CAAC,UAAU,CAAC,6BAAoB,CAAC,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,YAAE,CAAC,YAAY,CAAC,6BAAoB,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;IAChC,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,IAAA,mBAAU,GAAE,EAAE,CAAC;IACxC,YAAE,CAAC,aAAa,CAAC,6BAAoB,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,yBAAgB,CAAC,EAAE,CAAC;QACrC,YAAE,CAAC,SAAS,CAAC,yBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,SAAgB,SAAS;IACvB,SAAS,EAAE,CAAC;IACZ,OAAO,yBAAgB,CAAC;AAC1B,CAAC;AAED,SAAgB,cAAc;IAC5B,OAAO,cAAI,CAAC,IAAI,CAAC,yBAAgB,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface RedaiCliConfig {
2
+ cliToken: string;
3
+ clientId: string;
4
+ wsUrl: string;
5
+ apiBaseUrl: string;
6
+ userId: number;
7
+ userEmail: string | null;
8
+ userName: string | null;
9
+ expiresAt: number;
10
+ projectSchemaId: string;
11
+ /** Tools BE đã bootstrap cho máy này (chỉ informational, không enforce ở CLI). */
12
+ registeredTools: string[];
13
+ }
14
+ export declare function loadConfig(): RedaiCliConfig | null;
15
+ export declare function saveConfig(cfg: RedaiCliConfig): void;
16
+ export declare function clearConfig(): void;
@@ -0,0 +1,39 @@
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.loadConfig = loadConfig;
7
+ exports.saveConfig = saveConfig;
8
+ exports.clearConfig = clearConfig;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const config_1 = require("../config");
11
+ function ensureDir() {
12
+ if (!fs_1.default.existsSync(config_1.REDAI_CONFIG_DIR)) {
13
+ fs_1.default.mkdirSync(config_1.REDAI_CONFIG_DIR, { recursive: true, mode: 0o700 });
14
+ }
15
+ }
16
+ function loadConfig() {
17
+ if (!fs_1.default.existsSync(config_1.REDAI_CONFIG_FILE))
18
+ return null;
19
+ try {
20
+ const raw = fs_1.default.readFileSync(config_1.REDAI_CONFIG_FILE, 'utf8');
21
+ return JSON.parse(raw);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ function saveConfig(cfg) {
28
+ ensureDir();
29
+ fs_1.default.writeFileSync(config_1.REDAI_CONFIG_FILE, JSON.stringify(cfg, null, 2), {
30
+ encoding: 'utf8',
31
+ mode: 0o600,
32
+ });
33
+ }
34
+ function clearConfig() {
35
+ if (fs_1.default.existsSync(config_1.REDAI_CONFIG_FILE)) {
36
+ fs_1.default.unlinkSync(config_1.REDAI_CONFIG_FILE);
37
+ }
38
+ }
39
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":";;;;;AAuBA,gCAQC;AAED,gCAMC;AAED,kCAIC;AA7CD,4CAAoB;AACpB,sCAAgE;AAgBhE,SAAS,SAAS;IAChB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,yBAAgB,CAAC,EAAE,CAAC;QACrC,YAAE,CAAC,SAAS,CAAC,yBAAgB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,SAAgB,UAAU;IACxB,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAE,CAAC,YAAY,CAAC,0BAAiB,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,UAAU,CAAC,GAAmB;IAC5C,SAAS,EAAE,CAAC;IACZ,YAAE,CAAC,aAAa,CAAC,0BAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAChE,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,WAAW;IACzB,IAAI,YAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,EAAE,CAAC;QACrC,YAAE,CAAC,UAAU,CAAC,0BAAiB,CAAC,CAAC;IACnC,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ interface LoginOptions {
2
+ apiKey?: string;
3
+ apiUrl?: string;
4
+ }
5
+ export declare function loginCommand(options?: LoginOptions): Promise<void>;
6
+ export {};
@@ -0,0 +1,82 @@
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.loginCommand = loginCommand;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const prompts_1 = __importDefault(require("prompts"));
11
+ const config_1 = require("../../config");
12
+ const client_id_1 = require("../../auth/client-id");
13
+ const store_1 = require("../../auth/store");
14
+ const detect_1 = require("../../cli-router/detect");
15
+ async function loginCommand(options = {}) {
16
+ const apiBaseUrl = (options.apiUrl ?? config_1.DEFAULT_API_BASE_URL).replace(/\/+$/, '');
17
+ let apiKey = options.apiKey;
18
+ if (!apiKey) {
19
+ const response = await (0, prompts_1.default)({
20
+ type: 'password',
21
+ name: 'apiKey',
22
+ message: 'Paste your RedAI API key (with permission "cli:connect"):',
23
+ validate: (v) => typeof v === 'string' && v.trim().length >= 8 ? true : 'API key looks too short',
24
+ });
25
+ apiKey = response.apiKey?.trim();
26
+ }
27
+ if (!apiKey) {
28
+ console.error(chalk_1.default.red('No API key provided. Aborting.'));
29
+ process.exit(1);
30
+ }
31
+ const clientId = (0, client_id_1.loadOrCreateClientId)();
32
+ const { capabilities, cliDetected } = (0, detect_1.detectCapabilities)();
33
+ console.log(chalk_1.default.cyan('→ Verifying API key with'), apiBaseUrl);
34
+ let result;
35
+ try {
36
+ const res = await axios_1.default.post(`${apiBaseUrl}/cli/auth/verify`, {
37
+ apiKey,
38
+ clientId,
39
+ hostname: os_1.default.hostname(),
40
+ platform: process.platform,
41
+ cliVersion: config_1.CLI_VERSION,
42
+ capabilities,
43
+ cliDetected,
44
+ }, {
45
+ timeout: 15000,
46
+ headers: { 'user-agent': `redai-cli/${config_1.CLI_VERSION}` },
47
+ });
48
+ result = res.data;
49
+ }
50
+ catch (err) {
51
+ if (axios_1.default.isAxiosError(err) && err.response) {
52
+ console.error(chalk_1.default.red('✗ Login failed:'), err.response.data);
53
+ }
54
+ else {
55
+ console.error(chalk_1.default.red('✗ Login failed:'), err instanceof Error ? err.message : err);
56
+ }
57
+ process.exit(1);
58
+ return;
59
+ }
60
+ (0, store_1.saveConfig)({
61
+ cliToken: result.cliToken,
62
+ clientId: result.clientId,
63
+ wsUrl: result.wsUrl,
64
+ apiBaseUrl,
65
+ userId: result.user.id,
66
+ userEmail: result.user.email,
67
+ userName: result.user.name,
68
+ expiresAt: result.expiresAt,
69
+ projectSchemaId: result.projectSchemaId,
70
+ registeredTools: result.registeredTools,
71
+ });
72
+ console.log();
73
+ console.log(chalk_1.default.green('✓ Logged in.'));
74
+ console.log(` ${chalk_1.default.gray('User :')} ${result.user.name ?? result.user.email ?? result.user.id}`);
75
+ console.log(` ${chalk_1.default.gray('Client ID :')} ${result.clientId}`);
76
+ console.log(` ${chalk_1.default.gray('Schema :')} ${result.projectSchemaId}`);
77
+ console.log(` ${chalk_1.default.gray('Tools :')} ${result.registeredTools.join(', ') || '(none)'}`);
78
+ console.log(` ${chalk_1.default.gray('Expires :')} ${new Date(result.expiresAt).toISOString()}`);
79
+ console.log();
80
+ console.log(chalk_1.default.dim('Next: run `redai start` to keep this machine connected.'));
81
+ }
82
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function logoutCommand(): Promise<void>;
@@ -0,0 +1,18 @@
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.logoutCommand = logoutCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const store_1 = require("../../auth/store");
9
+ async function logoutCommand() {
10
+ const cfg = (0, store_1.loadConfig)();
11
+ if (!cfg) {
12
+ console.log(chalk_1.default.yellow('Not logged in.'));
13
+ return;
14
+ }
15
+ (0, store_1.clearConfig)();
16
+ console.log(chalk_1.default.green('✓ Logged out. Token removed from ~/.redai/config.json.'));
17
+ }
18
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/cli/commands/logout.ts"],"names":[],"mappings":";;;;;AAGA,sCAQC;AAXD,kDAA0B;AAC1B,4CAA2D;AAEpD,KAAK,UAAU,aAAa;IACjC,MAAM,GAAG,GAAG,IAAA,kBAAU,GAAE,CAAC;IACzB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IACD,IAAA,mBAAW,GAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,11 @@
1
+ interface OAuthCommandOptions {
2
+ provider: string;
3
+ account?: string;
4
+ noBrowser?: boolean;
5
+ /** Cho iFlow: paste cookie thay vì OAuth flow. */
6
+ cookie?: string;
7
+ }
8
+ export declare function oauthCommand(options: OAuthCommandOptions): Promise<void>;
9
+ export declare function oauthListCommand(): Promise<void>;
10
+ export declare function oauthLogoutCommand(provider: string, account?: string): Promise<void>;
11
+ export {};