@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
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidCodexToken = getValidCodexToken;
4
+ exports.streamCodex = streamCodex;
5
+ exports.callCodex = callCodex;
6
+ const crypto_1 = require("crypto");
7
+ const undici_1 = require("undici");
8
+ const codex_oauth_1 = require("../oauth/codex-oauth");
9
+ const store_1 = require("../oauth/store");
10
+ /**
11
+ * Codex client — port logic từ `internal/runtime/executor/codex_executor.go`.
12
+ *
13
+ * Default base URL: `https://chatgpt.com/backend-api/codex` (Sign in with ChatGPT).
14
+ * Cho phép override qua `headers['x-base-url']` để dùng OpenAI Platform khi cần.
15
+ */
16
+ const CODEX_DEFAULT_BASE = 'https://chatgpt.com/backend-api/codex';
17
+ const CODEX_USER_AGENT = 'codex_cli_rs/0.118.0 (Mac OS 26.3.1; arm64) iTerm.app/3.6.9';
18
+ const CODEX_ORIGINATOR = 'codex_cli_rs';
19
+ const REFRESH_GRACE_MS = 60000;
20
+ function buildCodexHeaders(token, opts) {
21
+ const headers = {
22
+ Authorization: `Bearer ${token.accessToken}`,
23
+ 'Content-Type': 'application/json',
24
+ 'User-Agent': CODEX_USER_AGENT,
25
+ Originator: CODEX_ORIGINATOR,
26
+ Version: '0.118.0',
27
+ Session_id: (0, crypto_1.randomUUID)(),
28
+ 'X-Client-Request-Id': (0, crypto_1.randomUUID)(),
29
+ 'X-Codex-Turn-Metadata': '',
30
+ Connection: 'Keep-Alive',
31
+ };
32
+ const accountId = token.metadata && typeof token.metadata.accountId === 'string'
33
+ ? token.metadata.accountId
34
+ : null;
35
+ if (accountId) {
36
+ headers['Chatgpt-Account-Id'] = accountId;
37
+ }
38
+ if (opts.stream)
39
+ headers.Accept = 'text/event-stream';
40
+ else
41
+ headers.Accept = 'application/json';
42
+ if (opts.override)
43
+ Object.assign(headers, opts.override);
44
+ return headers;
45
+ }
46
+ async function getValidCodexToken(account = 'default') {
47
+ const token = (0, store_1.loadToken)('codex', account);
48
+ if (!token) {
49
+ throw new Error(`Codex not logged in (account=${account}). Run \`redai oauth codex\`.`);
50
+ }
51
+ if (token.expiresAt > Date.now() + REFRESH_GRACE_MS)
52
+ return token;
53
+ const refreshed = await (0, codex_oauth_1.refreshCodexToken)(token);
54
+ (0, store_1.saveToken)('codex', refreshed);
55
+ return refreshed;
56
+ }
57
+ async function* streamCodex(input) {
58
+ const account = input.account ?? 'default';
59
+ const token = await getValidCodexToken(account);
60
+ let base = CODEX_DEFAULT_BASE;
61
+ let overrideHeaders = input.headers;
62
+ if (overrideHeaders && overrideHeaders['x-base-url']) {
63
+ base = overrideHeaders['x-base-url'].replace(/\/+$/, '');
64
+ overrideHeaders = { ...overrideHeaders };
65
+ delete overrideHeaders['x-base-url'];
66
+ }
67
+ const headers = buildCodexHeaders(token, { stream: true, override: overrideHeaders });
68
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
69
+ method: input.method ?? 'POST',
70
+ headers,
71
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
72
+ headersTimeout: 30000,
73
+ bodyTimeout: 0,
74
+ });
75
+ for await (const chunk of res.body) {
76
+ const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
77
+ yield { chunk: text };
78
+ }
79
+ return { status: res.statusCode, account };
80
+ }
81
+ async function callCodex(input) {
82
+ const account = input.account ?? 'default';
83
+ const token = await getValidCodexToken(account);
84
+ // Cho phép caller override base URL qua header 'x-base-url' (sẽ strip khỏi headers gửi đi)
85
+ let base = CODEX_DEFAULT_BASE;
86
+ let overrideHeaders = input.headers;
87
+ if (overrideHeaders && overrideHeaders['x-base-url']) {
88
+ base = overrideHeaders['x-base-url'].replace(/\/+$/, '');
89
+ overrideHeaders = { ...overrideHeaders };
90
+ delete overrideHeaders['x-base-url'];
91
+ }
92
+ const headers = buildCodexHeaders(token, { stream: false, override: overrideHeaders });
93
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
94
+ method: input.method ?? 'POST',
95
+ headers,
96
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
97
+ headersTimeout: 30000,
98
+ bodyTimeout: 120000,
99
+ });
100
+ const rawHeaders = {};
101
+ for (const [k, v] of Object.entries(res.headers)) {
102
+ rawHeaders[k] = Array.isArray(v) ? v.join(', ') : String(v ?? '');
103
+ }
104
+ const text = await res.body.text();
105
+ let parsedBody = text;
106
+ const ct = res.headers['content-type'] ?? '';
107
+ if (ct.includes('application/json')) {
108
+ try {
109
+ parsedBody = JSON.parse(text);
110
+ }
111
+ catch {
112
+ // keep raw
113
+ }
114
+ }
115
+ let errorType;
116
+ if (res.statusCode >= 400 && parsedBody && typeof parsedBody === 'object') {
117
+ const errObj = parsedBody.error;
118
+ errorType = errObj?.type ?? errObj?.code;
119
+ }
120
+ return { status: res.statusCode, headers: rawHeaders, body: parsedBody, errorType, account };
121
+ }
122
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/llm/providers/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { OAuthTokenStorage } from '../oauth/store';
2
+ export declare function getValidGeminiToken(account?: string): Promise<OAuthTokenStorage>;
3
+ export interface GeminiRequestInput {
4
+ path: string;
5
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
6
+ body?: unknown;
7
+ headers?: Record<string, string>;
8
+ account?: string;
9
+ }
10
+ export interface GeminiResponse {
11
+ status: number;
12
+ headers: Record<string, string>;
13
+ body: unknown;
14
+ errorType?: string;
15
+ account: string;
16
+ }
17
+ export declare function streamGemini(input: GeminiRequestInput): AsyncGenerator<{
18
+ chunk: string;
19
+ }, {
20
+ status: number;
21
+ account: string;
22
+ }, void>;
23
+ export declare function callGemini(input: GeminiRequestInput): Promise<GeminiResponse>;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidGeminiToken = getValidGeminiToken;
4
+ exports.streamGemini = streamGemini;
5
+ exports.callGemini = callGemini;
6
+ const undici_1 = require("undici");
7
+ const gemini_oauth_1 = require("../oauth/gemini-oauth");
8
+ const store_1 = require("../oauth/store");
9
+ /**
10
+ * Gemini client — passthrough sang Google APIs.
11
+ *
12
+ * Default base URL:
13
+ * - `https://cloudcode-pa.googleapis.com` cho Code Assist / Gemini CLI flow.
14
+ * - Override bằng header `x-base-url` để dùng generativelanguage.googleapis.com.
15
+ *
16
+ * Header spoofing tối giản hơn 2 provider kia: Google API yêu cầu chủ yếu
17
+ * `Authorization: Bearer` + `Content-Type`, không có UA fingerprint nghiêm.
18
+ */
19
+ const GEMINI_DEFAULT_BASE = 'https://cloudcode-pa.googleapis.com';
20
+ const GEMINI_USER_AGENT = 'GeminiCLI/v0.1.5 (linux; x64)';
21
+ const REFRESH_GRACE_MS = 60000;
22
+ function buildGeminiHeaders(token, opts) {
23
+ const headers = {
24
+ Authorization: `Bearer ${token.accessToken}`,
25
+ 'Content-Type': 'application/json',
26
+ 'User-Agent': GEMINI_USER_AGENT,
27
+ };
28
+ if (opts.stream)
29
+ headers.Accept = 'text/event-stream';
30
+ else
31
+ headers.Accept = 'application/json';
32
+ if (opts.override)
33
+ Object.assign(headers, opts.override);
34
+ return headers;
35
+ }
36
+ async function getValidGeminiToken(account = 'default') {
37
+ const token = (0, store_1.loadToken)('gemini', account);
38
+ if (!token) {
39
+ throw new Error(`Gemini not logged in (account=${account}). Run \`redai oauth gemini\`.`);
40
+ }
41
+ if (token.expiresAt > Date.now() + REFRESH_GRACE_MS)
42
+ return token;
43
+ const refreshed = await (0, gemini_oauth_1.refreshGeminiToken)(token);
44
+ (0, store_1.saveToken)('gemini', refreshed);
45
+ return refreshed;
46
+ }
47
+ async function* streamGemini(input) {
48
+ const account = input.account ?? 'default';
49
+ const token = await getValidGeminiToken(account);
50
+ let base = GEMINI_DEFAULT_BASE;
51
+ let overrideHeaders = input.headers;
52
+ if (overrideHeaders && overrideHeaders['x-base-url']) {
53
+ base = overrideHeaders['x-base-url'].replace(/\/+$/, '');
54
+ overrideHeaders = { ...overrideHeaders };
55
+ delete overrideHeaders['x-base-url'];
56
+ }
57
+ const headers = buildGeminiHeaders(token, { stream: true, override: overrideHeaders });
58
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
59
+ method: input.method ?? 'POST',
60
+ headers,
61
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
62
+ headersTimeout: 30000,
63
+ bodyTimeout: 0,
64
+ });
65
+ for await (const chunk of res.body) {
66
+ const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
67
+ yield { chunk: text };
68
+ }
69
+ return { status: res.statusCode, account };
70
+ }
71
+ async function callGemini(input) {
72
+ const account = input.account ?? 'default';
73
+ const token = await getValidGeminiToken(account);
74
+ let base = GEMINI_DEFAULT_BASE;
75
+ let overrideHeaders = input.headers;
76
+ if (overrideHeaders && overrideHeaders['x-base-url']) {
77
+ base = overrideHeaders['x-base-url'].replace(/\/+$/, '');
78
+ overrideHeaders = { ...overrideHeaders };
79
+ delete overrideHeaders['x-base-url'];
80
+ }
81
+ const headers = buildGeminiHeaders(token, { stream: false, override: overrideHeaders });
82
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
83
+ method: input.method ?? 'POST',
84
+ headers,
85
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
86
+ headersTimeout: 30000,
87
+ bodyTimeout: 120000,
88
+ });
89
+ const rawHeaders = {};
90
+ for (const [k, v] of Object.entries(res.headers)) {
91
+ rawHeaders[k] = Array.isArray(v) ? v.join(', ') : String(v ?? '');
92
+ }
93
+ const text = await res.body.text();
94
+ let parsedBody = text;
95
+ const ct = res.headers['content-type'] ?? '';
96
+ if (ct.includes('application/json')) {
97
+ try {
98
+ parsedBody = JSON.parse(text);
99
+ }
100
+ catch {
101
+ // keep raw
102
+ }
103
+ }
104
+ // Google error envelope: {"error":{"code":401,"message":"...","status":"UNAUTHENTICATED"}}
105
+ let errorType;
106
+ if (res.statusCode >= 400 && parsedBody && typeof parsedBody === 'object') {
107
+ const errObj = parsedBody.error;
108
+ errorType = errObj?.status;
109
+ }
110
+ return { status: res.statusCode, headers: rawHeaders, body: parsedBody, errorType, account };
111
+ }
112
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/llm/providers/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { OAuthTokenStorage } from '../oauth/store';
2
+ /**
3
+ * Generic OAuth-bearer client factory — dùng cho các provider không có
4
+ * fingerprint phức tạp (Qwen / Kimi / iFlow / xAI). Caller cung cấp:
5
+ * - defaultBase: URL gốc
6
+ * - userAgent
7
+ * - refreshFn: async fn nhận token cũ → token mới
8
+ * - extraHeaders (optional): static headers cần thêm
9
+ *
10
+ * Trả về 2 hàm: call + stream + getValidToken.
11
+ */
12
+ export interface GenericClientOpts {
13
+ providerKey: string;
14
+ defaultBase: string;
15
+ userAgent: string;
16
+ refresh: (current: OAuthTokenStorage) => Promise<OAuthTokenStorage>;
17
+ /** Static headers cần thêm trên mỗi request. */
18
+ extraHeaders?: Record<string, string>;
19
+ /** Refresh grace before expiry (ms). */
20
+ refreshGraceMs?: number;
21
+ }
22
+ export interface ProviderRequestInput {
23
+ path: string;
24
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
25
+ body?: unknown;
26
+ headers?: Record<string, string>;
27
+ account?: string;
28
+ }
29
+ export interface ProviderResponse {
30
+ status: number;
31
+ headers: Record<string, string>;
32
+ body: unknown;
33
+ errorType?: string;
34
+ account: string;
35
+ }
36
+ export declare function createGenericClient(opts: GenericClientOpts): {
37
+ call: (input: ProviderRequestInput) => Promise<ProviderResponse>;
38
+ stream: (input: ProviderRequestInput) => AsyncGenerator<{
39
+ chunk: string;
40
+ }, {
41
+ status: number;
42
+ account: string;
43
+ }, void>;
44
+ getValidToken: (account?: string) => Promise<OAuthTokenStorage>;
45
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGenericClient = createGenericClient;
4
+ const undici_1 = require("undici");
5
+ const store_1 = require("../oauth/store");
6
+ function createGenericClient(opts) {
7
+ const grace = opts.refreshGraceMs ?? 60000;
8
+ async function getValidToken(account = 'default') {
9
+ const token = (0, store_1.loadToken)(opts.providerKey, account);
10
+ if (!token) {
11
+ throw new Error(`${opts.providerKey} not logged in (account=${account}). Run \`redai oauth ${opts.providerKey}\`.`);
12
+ }
13
+ if (token.expiresAt > Date.now() + grace)
14
+ return token;
15
+ const refreshed = await opts.refresh(token);
16
+ (0, store_1.saveToken)(opts.providerKey, refreshed);
17
+ return refreshed;
18
+ }
19
+ function buildHeaders(token, streamMode, override) {
20
+ const headers = {
21
+ Authorization: `Bearer ${token.accessToken}`,
22
+ 'Content-Type': 'application/json',
23
+ 'User-Agent': opts.userAgent,
24
+ Accept: streamMode ? 'text/event-stream' : 'application/json',
25
+ ...(opts.extraHeaders ?? {}),
26
+ };
27
+ if (override)
28
+ Object.assign(headers, override);
29
+ return headers;
30
+ }
31
+ function resolveBaseAndHeaders(input) {
32
+ let base = opts.defaultBase;
33
+ let overrideHeaders = input.headers;
34
+ if (overrideHeaders && overrideHeaders['x-base-url']) {
35
+ base = overrideHeaders['x-base-url'].replace(/\/+$/, '');
36
+ overrideHeaders = { ...overrideHeaders };
37
+ delete overrideHeaders['x-base-url'];
38
+ }
39
+ return { base, overrideHeaders };
40
+ }
41
+ async function call(input) {
42
+ const account = input.account ?? 'default';
43
+ const token = await getValidToken(account);
44
+ const { base, overrideHeaders } = resolveBaseAndHeaders(input);
45
+ const headers = buildHeaders(token, false, overrideHeaders);
46
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
47
+ method: input.method ?? 'POST',
48
+ headers,
49
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
50
+ headersTimeout: 30000,
51
+ bodyTimeout: 120000,
52
+ });
53
+ return finalize(res, account);
54
+ }
55
+ async function* stream(input) {
56
+ const account = input.account ?? 'default';
57
+ const token = await getValidToken(account);
58
+ const { base, overrideHeaders } = resolveBaseAndHeaders(input);
59
+ const headers = buildHeaders(token, true, overrideHeaders);
60
+ const res = await (0, undici_1.request)(`${base}${input.path}`, {
61
+ method: input.method ?? 'POST',
62
+ headers,
63
+ body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
64
+ headersTimeout: 30000,
65
+ bodyTimeout: 0,
66
+ });
67
+ for await (const chunk of res.body) {
68
+ const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
69
+ yield { chunk: text };
70
+ }
71
+ return { status: res.statusCode, account };
72
+ }
73
+ return { call, stream, getValidToken };
74
+ }
75
+ async function finalize(res, account) {
76
+ const rawHeaders = {};
77
+ for (const [k, v] of Object.entries(res.headers)) {
78
+ rawHeaders[k] = Array.isArray(v) ? v.join(', ') : String(v ?? '');
79
+ }
80
+ const text = await res.body.text();
81
+ let parsedBody = text;
82
+ const ct = res.headers['content-type'] ?? '';
83
+ if (ct.includes('application/json')) {
84
+ try {
85
+ parsedBody = JSON.parse(text);
86
+ }
87
+ catch {
88
+ /* keep raw */
89
+ }
90
+ }
91
+ let errorType;
92
+ if (res.statusCode >= 400 && parsedBody && typeof parsedBody === 'object') {
93
+ const err = parsedBody.error;
94
+ errorType = err?.type ?? err?.status ?? err?.code;
95
+ }
96
+ return { status: res.statusCode, headers: rawHeaders, body: parsedBody, errorType, account };
97
+ }
98
+ //# sourceMappingURL=generic-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generic-client.js","sourceRoot":"","sources":["../../../src/llm/providers/generic-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare const callIFlow: (input: import("./generic-client").ProviderRequestInput) => Promise<import("./generic-client").ProviderResponse>;
2
+ export declare const streamIFlow: (input: import("./generic-client").ProviderRequestInput) => AsyncGenerator<{
3
+ chunk: string;
4
+ }, {
5
+ status: number;
6
+ account: string;
7
+ }, void>;
8
+ export declare const getValidIFlowToken: (account?: string) => Promise<import("../oauth/store").OAuthTokenStorage>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidIFlowToken = exports.streamIFlow = exports.callIFlow = void 0;
4
+ const generic_client_1 = require("./generic-client");
5
+ const iflow_oauth_1 = require("../oauth/iflow-oauth");
6
+ const client = (0, generic_client_1.createGenericClient)({
7
+ providerKey: 'iflow',
8
+ defaultBase: iflow_oauth_1.IFLOW_DEFAULT_API_BASE,
9
+ userAgent: 'iflow-cli/1.0',
10
+ refresh: iflow_oauth_1.refreshIFlowToken,
11
+ });
12
+ exports.callIFlow = client.call;
13
+ exports.streamIFlow = client.stream;
14
+ exports.getValidIFlowToken = client.getValidToken;
15
+ //# sourceMappingURL=iflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iflow.js","sourceRoot":"","sources":["../../../src/llm/providers/iflow.ts"],"names":[],"mappings":";;;AAAA,qDAAuD;AACvD,sDAAiF;AAEjF,MAAM,MAAM,GAAG,IAAA,oCAAmB,EAAC;IACjC,WAAW,EAAE,OAAO;IACpB,WAAW,EAAE,oCAAsB;IACnC,SAAS,EAAE,eAAe;IAC1B,OAAO,EAAE,+BAAiB;CAC3B,CAAC,CAAC;AAEU,QAAA,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC;AACxB,QAAA,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;AAC5B,QAAA,kBAAkB,GAAG,MAAM,CAAC,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const callKimi: (input: import("./generic-client").ProviderRequestInput) => Promise<import("./generic-client").ProviderResponse>;
2
+ export declare const streamKimi: (input: import("./generic-client").ProviderRequestInput) => AsyncGenerator<{
3
+ chunk: string;
4
+ }, {
5
+ status: number;
6
+ account: string;
7
+ }, void>;
8
+ export declare const getValidKimiToken: (account?: string) => Promise<import("../oauth/store").OAuthTokenStorage>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidKimiToken = exports.streamKimi = exports.callKimi = void 0;
4
+ const generic_client_1 = require("./generic-client");
5
+ const kimi_oauth_1 = require("../oauth/kimi-oauth");
6
+ const kimi_oauth_2 = require("../oauth/kimi-oauth");
7
+ const client = (0, generic_client_1.createGenericClient)({
8
+ providerKey: 'kimi',
9
+ defaultBase: kimi_oauth_2.KIMI_API_BASE_URL,
10
+ userAgent: 'kimi-cli/1.0',
11
+ refresh: kimi_oauth_1.refreshKimiToken,
12
+ });
13
+ exports.callKimi = client.call;
14
+ exports.streamKimi = client.stream;
15
+ exports.getValidKimiToken = client.getValidToken;
16
+ //# sourceMappingURL=kimi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kimi.js","sourceRoot":"","sources":["../../../src/llm/providers/kimi.ts"],"names":[],"mappings":";;;AAAA,qDAAuD;AACvD,oDAAuD;AACvD,oDAAwD;AAExD,MAAM,MAAM,GAAG,IAAA,oCAAmB,EAAC;IACjC,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,8BAAiB;IAC9B,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,6BAAgB;CAC1B,CAAC,CAAC;AAEU,QAAA,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;AACvB,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3B,QAAA,iBAAiB,GAAG,MAAM,CAAC,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const callQwen: (input: import("./generic-client").ProviderRequestInput) => Promise<import("./generic-client").ProviderResponse>;
2
+ export declare const streamQwen: (input: import("./generic-client").ProviderRequestInput) => AsyncGenerator<{
3
+ chunk: string;
4
+ }, {
5
+ status: number;
6
+ account: string;
7
+ }, void>;
8
+ export declare const getValidQwenToken: (account?: string) => Promise<import("../oauth/store").OAuthTokenStorage>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidQwenToken = exports.streamQwen = exports.callQwen = void 0;
4
+ const generic_client_1 = require("./generic-client");
5
+ const qwen_oauth_1 = require("../oauth/qwen-oauth");
6
+ const client = (0, generic_client_1.createGenericClient)({
7
+ providerKey: 'qwen',
8
+ defaultBase: 'https://portal.qwen.ai/v1',
9
+ userAgent: 'qwen-cli/1.0',
10
+ refresh: qwen_oauth_1.refreshQwenToken,
11
+ });
12
+ exports.callQwen = client.call;
13
+ exports.streamQwen = client.stream;
14
+ exports.getValidQwenToken = client.getValidToken;
15
+ //# sourceMappingURL=qwen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qwen.js","sourceRoot":"","sources":["../../../src/llm/providers/qwen.ts"],"names":[],"mappings":";;;AAAA,qDAAuD;AACvD,oDAAuD;AAEvD,MAAM,MAAM,GAAG,IAAA,oCAAmB,EAAC;IACjC,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,2BAA2B;IACxC,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,6BAAgB;CAC1B,CAAC,CAAC;AAEU,QAAA,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;AACvB,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3B,QAAA,iBAAiB,GAAG,MAAM,CAAC,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const callXAI: (input: import("./generic-client").ProviderRequestInput) => Promise<import("./generic-client").ProviderResponse>;
2
+ export declare const streamXAI: (input: import("./generic-client").ProviderRequestInput) => AsyncGenerator<{
3
+ chunk: string;
4
+ }, {
5
+ status: number;
6
+ account: string;
7
+ }, void>;
8
+ export declare const getValidXAIToken: (account?: string) => Promise<import("../oauth/store").OAuthTokenStorage>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidXAIToken = exports.streamXAI = exports.callXAI = void 0;
4
+ const generic_client_1 = require("./generic-client");
5
+ const xai_oauth_1 = require("../oauth/xai-oauth");
6
+ const client = (0, generic_client_1.createGenericClient)({
7
+ providerKey: 'xai',
8
+ defaultBase: xai_oauth_1.XAI_DEFAULT_API_BASE,
9
+ userAgent: 'grok-cli/1.0',
10
+ refresh: xai_oauth_1.refreshXAIToken,
11
+ });
12
+ exports.callXAI = client.call;
13
+ exports.streamXAI = client.stream;
14
+ exports.getValidXAIToken = client.getValidToken;
15
+ //# sourceMappingURL=xai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/llm/providers/xai.ts"],"names":[],"mappings":";;;AAAA,qDAAuD;AACvD,kDAA2E;AAE3E,MAAM,MAAM,GAAG,IAAA,oCAAmB,EAAC;IACjC,WAAW,EAAE,KAAK;IAClB,WAAW,EAAE,gCAAoB;IACjC,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,2BAAe;CACzB,CAAC,CAAC;AAEU,QAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AACtB,QAAA,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;AAC1B,QAAA,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @param hint Account name caller truyền vào. Nếu live → dùng. Nếu kh cooldown → fallback.
3
+ */
4
+ export declare function pickAccount(provider: string, hint?: string): string;
5
+ export declare function markCooldown(provider: string, account: string, opts?: {
6
+ retryAfterSec?: number;
7
+ durationMs?: number;
8
+ }): void;
9
+ export declare function clearCooldown(provider: string, account: string): void;
10
+ export declare function listCooldowns(): Array<{
11
+ provider: string;
12
+ account: string;
13
+ until: number;
14
+ }>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pickAccount = pickAccount;
4
+ exports.markCooldown = markCooldown;
5
+ exports.clearCooldown = clearCooldown;
6
+ exports.listCooldowns = listCooldowns;
7
+ const store_1 = require("./oauth/store");
8
+ const lastUsed = new Map(); // cursor per provider
9
+ const cooldownUntil = new Map(); // (provider:account) → epoch ms
10
+ function key(provider, account) {
11
+ return `${provider}:${account}`;
12
+ }
13
+ function isLive(provider, account) {
14
+ const until = cooldownUntil.get(key(provider, account)) ?? 0;
15
+ if (until > Date.now())
16
+ return false;
17
+ // double-check token tồn tại + chưa expired hoàn toàn
18
+ const token = (0, store_1.loadToken)(provider, account);
19
+ if (!token)
20
+ return false;
21
+ // expiresAt < now nhưng refresh sẽ tự handle ở provider client; coi là live.
22
+ return true;
23
+ }
24
+ /**
25
+ * @param hint Account name caller truyền vào. Nếu live → dùng. Nếu kh cooldown → fallback.
26
+ */
27
+ function pickAccount(provider, hint) {
28
+ const accounts = (0, store_1.listAccounts)(provider);
29
+ if (!accounts.length) {
30
+ throw new Error(`No OAuth account for provider "${provider}". Run \`redai oauth ${provider}\`.`);
31
+ }
32
+ if (hint && hint.trim()) {
33
+ const wanted = hint.trim();
34
+ if (accounts.includes(wanted) && isLive(provider, wanted)) {
35
+ return wanted;
36
+ }
37
+ // Hint không live → log nhẹ rồi fallback
38
+ }
39
+ // Round-robin qua live accounts
40
+ const liveAccounts = accounts.filter((a) => isLive(provider, a));
41
+ if (!liveAccounts.length) {
42
+ throw new Error(`All accounts for "${provider}" are in cooldown. Try again later or run \`redai oauth ${provider}\` to add new.`);
43
+ }
44
+ if (liveAccounts.length === 1)
45
+ return liveAccounts[0];
46
+ const cursor = lastUsed.get(provider) ?? -1;
47
+ const next = (cursor + 1) % liveAccounts.length;
48
+ lastUsed.set(provider, next);
49
+ return liveAccounts[next];
50
+ }
51
+ const DEFAULT_COOLDOWN_MS = 60000;
52
+ const MAX_COOLDOWN_MS = 30 * 60000;
53
+ function markCooldown(provider, account, opts = {}) {
54
+ let until = Date.now();
55
+ if (opts.retryAfterSec && opts.retryAfterSec > 0) {
56
+ until += opts.retryAfterSec * 1000;
57
+ }
58
+ else if (opts.durationMs && opts.durationMs > 0) {
59
+ until += opts.durationMs;
60
+ }
61
+ else {
62
+ until += DEFAULT_COOLDOWN_MS;
63
+ }
64
+ const capped = Math.min(until, Date.now() + MAX_COOLDOWN_MS);
65
+ cooldownUntil.set(key(provider, account), capped);
66
+ }
67
+ function clearCooldown(provider, account) {
68
+ cooldownUntil.delete(key(provider, account));
69
+ }
70
+ function listCooldowns() {
71
+ const now = Date.now();
72
+ const out = [];
73
+ for (const [k, until] of cooldownUntil.entries()) {
74
+ if (until <= now)
75
+ continue;
76
+ const [provider, account] = k.split(':');
77
+ out.push({ provider, account, until });
78
+ }
79
+ return out;
80
+ }
81
+ //# sourceMappingURL=selector.js.map