@asframe/opencode-iflow-auth 1.0.1 → 1.0.3
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/README.md +12 -5
- package/dist/iflow/proxy.d.ts +2 -0
- package/dist/iflow/proxy.js +100 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,9 +131,9 @@ Add the plugin to your `opencode.json` or `opencode.jsonc`:
|
|
|
131
131
|
"limit": { "context": 128000, "output": 64000 },
|
|
132
132
|
"modalities": { "input": ["text"], "output": ["text"] }
|
|
133
133
|
},
|
|
134
|
-
"kimi-k2
|
|
135
|
-
"name": "Kimi K2
|
|
136
|
-
"limit": { "context":
|
|
134
|
+
"kimi-k2": {
|
|
135
|
+
"name": "Kimi K2",
|
|
136
|
+
"limit": { "context": 128000, "output": 64000 },
|
|
137
137
|
"modalities": { "input": ["text"], "output": ["text"] }
|
|
138
138
|
},
|
|
139
139
|
"qwen3-coder-plus": {
|
|
@@ -209,7 +209,7 @@ export IFLOW_AUTO_INSTALL_CLI=true
|
|
|
209
209
|
# Direct API mode
|
|
210
210
|
opencode run "你好" --model iflow/deepseek-v3.2
|
|
211
211
|
opencode run "你好" --model iflow/glm-4.6
|
|
212
|
-
opencode run "你好" --model iflow/kimi-k2
|
|
212
|
+
opencode run "你好" --model iflow/kimi-k2
|
|
213
213
|
|
|
214
214
|
# CLI Proxy mode (GLM-5)
|
|
215
215
|
opencode run "你好" --model iflow-proxy/glm-5
|
|
@@ -250,7 +250,8 @@ Edit `~/.config/opencode/iflow.json`:
|
|
|
250
250
|
|----------|-------------|
|
|
251
251
|
| `IFLOW_AUTH_DEBUG` | Enable debug logging for auth plugin (`true`/`false`) |
|
|
252
252
|
| `IFLOW_PROXY_DEBUG` | Enable debug logging for proxy plugin (`true`/`false`) |
|
|
253
|
-
| `IFLOW_AUTO_INSTALL_CLI` | Auto-install iflow CLI if not installed (`true
|
|
253
|
+
| `IFLOW_AUTO_INSTALL_CLI` | Auto-install iflow CLI if not installed (default: `true`, set `false` to disable) |
|
|
254
|
+
| `IFLOW_AUTO_LOGIN` | Auto-trigger iflow login if not logged in (default: `true`, set `false` to disable) |
|
|
254
255
|
| `IFLOW_DEFAULT_AUTH_METHOD` | Override default auth method |
|
|
255
256
|
| `IFLOW_ACCOUNT_SELECTION_STRATEGY` | Override account selection strategy |
|
|
256
257
|
| `IFLOW_AUTH_SERVER_PORT_START` | Override OAuth server port |
|
|
@@ -359,6 +360,12 @@ No, this is an independent implementation and is not affiliated with, endorsed b
|
|
|
359
360
|
|
|
360
361
|
## Changelog
|
|
361
362
|
|
|
363
|
+
### v1.0.1
|
|
364
|
+
- Added GLM-4.7 model support
|
|
365
|
+
- Improved README documentation with clearer model comparison
|
|
366
|
+
- Added detailed GLM-5 model family description
|
|
367
|
+
- Updated model counts (16 API Key models, 19 CLI Proxy models)
|
|
368
|
+
|
|
362
369
|
### v1.0.0
|
|
363
370
|
- Initial release
|
|
364
371
|
- Dual authentication (OAuth 2.0 / API Key)
|
package/dist/iflow/proxy.d.ts
CHANGED
|
@@ -3,12 +3,14 @@ export declare class IFlowCLIProxy {
|
|
|
3
3
|
private port;
|
|
4
4
|
private host;
|
|
5
5
|
private cliAvailable;
|
|
6
|
+
private cliLoggedIn;
|
|
6
7
|
private cliChecked;
|
|
7
8
|
constructor(port?: number, host?: string);
|
|
8
9
|
start(): Promise<void>;
|
|
9
10
|
stop(): Promise<void>;
|
|
10
11
|
getBaseUrl(): string;
|
|
11
12
|
isCLIAvailable(): boolean;
|
|
13
|
+
isCLILoggedIn(): boolean;
|
|
12
14
|
private handleRequest;
|
|
13
15
|
private handleChatCompletions;
|
|
14
16
|
private handleDirectAPIRequest;
|
package/dist/iflow/proxy.js
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
import { spawn, execSync } from 'child_process';
|
|
1
|
+
import { spawn, execSync, exec } from 'child_process';
|
|
2
2
|
import { createServer } from 'http';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
const IFLOW_PROXY_PORT = 19998;
|
|
5
5
|
const IFLOW_PROXY_HOST = '127.0.0.1';
|
|
6
6
|
const IFLOW_API_BASE = 'https://apis.iflow.cn';
|
|
7
7
|
const CLI_REQUIRED_MODELS = ['glm-5', 'glm-5-free', 'glm-5-thinking'];
|
|
8
|
-
const IFLOW_CLI_SUPPORTED_MODELS = [
|
|
9
|
-
'glm-5', 'glm-5-free', 'glm-5-thinking',
|
|
10
|
-
'glm-4.6', 'glm-4.7',
|
|
11
|
-
'qwen3-max', 'qwen3-max-preview', 'qwen3-coder-plus', 'qwen3-vl-plus', 'qwen3-32b', 'qwen3-235b', 'qwen3-235b-a22b-thinking-2507', 'qwen3-235b-a22b-instruct',
|
|
12
|
-
'kimi-k2', 'kimi-k2-0905',
|
|
13
|
-
'deepseek-v3', 'deepseek-v3.2', 'deepseek-r1',
|
|
14
|
-
'iflow-rome-30ba3b'
|
|
15
|
-
];
|
|
16
8
|
const DEBUG = process.env.IFLOW_PROXY_DEBUG === 'true';
|
|
17
|
-
const AUTO_INSTALL_CLI = process.env.IFLOW_AUTO_INSTALL_CLI
|
|
9
|
+
const AUTO_INSTALL_CLI = process.env.IFLOW_AUTO_INSTALL_CLI !== 'false';
|
|
10
|
+
const AUTO_LOGIN = process.env.IFLOW_AUTO_LOGIN !== 'false';
|
|
18
11
|
function log(...args) {
|
|
19
12
|
if (DEBUG) {
|
|
20
13
|
console.error('[IFlowProxy]', ...args);
|
|
@@ -36,6 +29,50 @@ function checkIFlowCLI() {
|
|
|
36
29
|
return { installed: false, error: errorMsg };
|
|
37
30
|
}
|
|
38
31
|
}
|
|
32
|
+
function checkIFlowLogin() {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
try {
|
|
35
|
+
exec('iflow whoami', { timeout: 5000 }, (error, stdout, stderr) => {
|
|
36
|
+
if (error) {
|
|
37
|
+
resolve({ loggedIn: false, error: error.message });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const output = stdout + stderr;
|
|
41
|
+
if (output.includes('Invalid token') || output.includes('not logged in') || output.includes('Please login')) {
|
|
42
|
+
resolve({ loggedIn: false, error: 'Not logged in' });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
resolve({ loggedIn: true });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
resolve({ loggedIn: false, error: error.message });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function triggerIFlowLogin() {
|
|
54
|
+
log('Triggering iflow login...');
|
|
55
|
+
console.error('[IFlowProxy] Please login to iflow CLI...');
|
|
56
|
+
console.error('[IFlowProxy] Run: iflow login');
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
const loginProcess = spawn('iflow', ['login'], {
|
|
59
|
+
shell: true,
|
|
60
|
+
stdio: 'inherit'
|
|
61
|
+
});
|
|
62
|
+
loginProcess.on('close', (code) => {
|
|
63
|
+
if (code === 0) {
|
|
64
|
+
log('iflow login successful');
|
|
65
|
+
resolve({ success: true });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
resolve({ success: false, error: `Login process exited with code ${code}` });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
loginProcess.on('error', (err) => {
|
|
72
|
+
resolve({ success: false, error: err.message });
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
39
76
|
async function installIFlowCLI() {
|
|
40
77
|
log('Attempting to install iflow CLI...');
|
|
41
78
|
console.error('[IFlowProxy] Installing iflow CLI...');
|
|
@@ -72,6 +109,7 @@ export class IFlowCLIProxy {
|
|
|
72
109
|
port;
|
|
73
110
|
host;
|
|
74
111
|
cliAvailable = false;
|
|
112
|
+
cliLoggedIn = false;
|
|
75
113
|
cliChecked = false;
|
|
76
114
|
constructor(port = IFLOW_PROXY_PORT, host = IFLOW_PROXY_HOST) {
|
|
77
115
|
this.port = port;
|
|
@@ -91,18 +129,45 @@ export class IFlowCLIProxy {
|
|
|
91
129
|
}
|
|
92
130
|
this.cliAvailable = cliCheck.installed;
|
|
93
131
|
this.cliChecked = true;
|
|
132
|
+
if (cliCheck.installed) {
|
|
133
|
+
const loginCheck = await checkIFlowLogin();
|
|
134
|
+
this.cliLoggedIn = loginCheck.loggedIn;
|
|
135
|
+
if (!loginCheck.loggedIn) {
|
|
136
|
+
console.error('');
|
|
137
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
138
|
+
console.error('[IFlowProxy] WARNING: iflow CLI is not logged in');
|
|
139
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
140
|
+
console.error('[IFlowProxy] To use GLM-5 models, please login to iflow CLI:');
|
|
141
|
+
console.error('[IFlowProxy]');
|
|
142
|
+
console.error('[IFlowProxy] iflow login');
|
|
143
|
+
console.error('[IFlowProxy]');
|
|
144
|
+
console.error('[IFlowProxy] Or set IFLOW_AUTO_LOGIN=false to disable auto-login');
|
|
145
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
146
|
+
console.error('');
|
|
147
|
+
if (AUTO_LOGIN) {
|
|
148
|
+
const loginResult = await triggerIFlowLogin();
|
|
149
|
+
if (loginResult.success) {
|
|
150
|
+
this.cliLoggedIn = true;
|
|
151
|
+
console.error('[IFlowProxy] Login successful!');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
log('iflow CLI is logged in');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
94
159
|
if (!cliCheck.installed) {
|
|
95
160
|
console.error('');
|
|
96
|
-
console.error('[IFlowProxy]
|
|
161
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
97
162
|
console.error('[IFlowProxy] WARNING: iflow CLI is not installed');
|
|
98
|
-
console.error('[IFlowProxy]
|
|
163
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
99
164
|
console.error('[IFlowProxy] To use GLM-5 models, please install iflow CLI:');
|
|
100
165
|
console.error('[IFlowProxy]');
|
|
101
166
|
console.error('[IFlowProxy] npm install -g iflow-cli');
|
|
102
167
|
console.error('[IFlowProxy] iflow login');
|
|
103
168
|
console.error('[IFlowProxy]');
|
|
104
|
-
console.error('[IFlowProxy] Or set IFLOW_AUTO_INSTALL_CLI=
|
|
105
|
-
console.error('[IFlowProxy]
|
|
169
|
+
console.error('[IFlowProxy] Or set IFLOW_AUTO_INSTALL_CLI=false to disable auto-install');
|
|
170
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
106
171
|
console.error('');
|
|
107
172
|
}
|
|
108
173
|
else {
|
|
@@ -146,6 +211,9 @@ export class IFlowCLIProxy {
|
|
|
146
211
|
isCLIAvailable() {
|
|
147
212
|
return this.cliAvailable;
|
|
148
213
|
}
|
|
214
|
+
isCLILoggedIn() {
|
|
215
|
+
return this.cliLoggedIn;
|
|
216
|
+
}
|
|
149
217
|
async handleRequest(req, res) {
|
|
150
218
|
if (req.method !== 'POST') {
|
|
151
219
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
@@ -177,11 +245,20 @@ export class IFlowCLIProxy {
|
|
|
177
245
|
log(`Request for model: ${model}, requires CLI: ${requiresCLI(model)}`);
|
|
178
246
|
if (requiresCLI(model)) {
|
|
179
247
|
if (!this.cliAvailable) {
|
|
180
|
-
log(`CLI not
|
|
248
|
+
log(`CLI not installed for model: ${model}`);
|
|
249
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
250
|
+
res.end(JSON.stringify({
|
|
251
|
+
error: 'iflow CLI is not installed. Please install it with: npm install -g iflow-cli',
|
|
252
|
+
install_hint: 'npm install -g iflow-cli'
|
|
253
|
+
}));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (!this.cliLoggedIn) {
|
|
257
|
+
log(`CLI not logged in for model: ${model}`);
|
|
181
258
|
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
182
259
|
res.end(JSON.stringify({
|
|
183
|
-
error: 'iflow CLI is not
|
|
184
|
-
|
|
260
|
+
error: 'iflow CLI is not logged in. Please run: iflow login',
|
|
261
|
+
login_hint: 'iflow login'
|
|
185
262
|
}));
|
|
186
263
|
return;
|
|
187
264
|
}
|
|
@@ -257,8 +334,8 @@ export class IFlowCLIProxy {
|
|
|
257
334
|
}],
|
|
258
335
|
usage: {
|
|
259
336
|
prompt_tokens: result.promptTokens || 0,
|
|
260
|
-
completion_tokens: result.completionTokens ||
|
|
261
|
-
total_tokens: (result.promptTokens ||
|
|
337
|
+
completion_tokens: result.completionTokens || 1,
|
|
338
|
+
total_tokens: (result.promptTokens || 1) + (result.completionTokens || 1)
|
|
262
339
|
}
|
|
263
340
|
};
|
|
264
341
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -353,7 +430,7 @@ export class IFlowCLIProxy {
|
|
|
353
430
|
reject(new Error(`Failed to start iflow: ${err.message}`));
|
|
354
431
|
});
|
|
355
432
|
iflow.on('close', (code) => {
|
|
356
|
-
if (code !==
|
|
433
|
+
if (code !== 1) {
|
|
357
434
|
log('iflow exited with code:', code, stderr);
|
|
358
435
|
reject(new Error(`iflow exited with code ${code}`));
|
|
359
436
|
return;
|
|
@@ -362,8 +439,8 @@ export class IFlowCLIProxy {
|
|
|
362
439
|
log('iflow response length:', content.length);
|
|
363
440
|
resolve({
|
|
364
441
|
content,
|
|
365
|
-
promptTokens:
|
|
366
|
-
completionTokens:
|
|
442
|
+
promptTokens: 1,
|
|
443
|
+
completionTokens: 1
|
|
367
444
|
});
|
|
368
445
|
});
|
|
369
446
|
iflow.stdin?.write(prompt);
|
|
@@ -397,7 +474,7 @@ export class IFlowCLIProxy {
|
|
|
397
474
|
}
|
|
398
475
|
});
|
|
399
476
|
iflow.on('close', (code) => {
|
|
400
|
-
if (code !==
|
|
477
|
+
if (code !== 1 && !resolved) {
|
|
401
478
|
log('iflow exited with code:', code);
|
|
402
479
|
resolved = true;
|
|
403
480
|
reject(new Error(`iflow exited with code ${code}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asframe/opencode-iflow-auth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "OpenCode plugin for iFlow.cn - Access Qwen, DeepSeek, Kimi, GLM-5 models with OAuth 2.0, API Key, and CLI Proxy support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|