@asframe/opencode-iflow-auth 1.0.1 → 1.0.2
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 +11 -4
- package/dist/iflow/proxy.d.ts +2 -0
- package/dist/iflow/proxy.js +97 -21
- 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
|
|
@@ -251,6 +251,7 @@ Edit `~/.config/opencode/iflow.json`:
|
|
|
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
253
|
| `IFLOW_AUTO_INSTALL_CLI` | Auto-install iflow CLI if not installed (`true`/`false`) |
|
|
254
|
+
| `IFLOW_AUTO_LOGIN` | Auto-trigger iflow login if not logged in (`true`/`false`) |
|
|
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,18 +1,10 @@
|
|
|
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
9
|
const AUTO_INSTALL_CLI = process.env.IFLOW_AUTO_INSTALL_CLI === 'true';
|
|
18
10
|
function log(...args) {
|
|
@@ -36,6 +28,50 @@ function checkIFlowCLI() {
|
|
|
36
28
|
return { installed: false, error: errorMsg };
|
|
37
29
|
}
|
|
38
30
|
}
|
|
31
|
+
function checkIFlowLogin() {
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
try {
|
|
34
|
+
exec('iflow whoami', { timeout: 5000 }, (error, stdout, stderr) => {
|
|
35
|
+
if (error) {
|
|
36
|
+
resolve({ loggedIn: false, error: error.message });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const output = stdout + stderr;
|
|
40
|
+
if (output.includes('Invalid token') || output.includes('not logged in') || output.includes('Please login')) {
|
|
41
|
+
resolve({ loggedIn: false, error: 'Not logged in' });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
resolve({ loggedIn: true });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
resolve({ loggedIn: false, error: error.message });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async function triggerIFlowLogin() {
|
|
53
|
+
log('Triggering iflow login...');
|
|
54
|
+
console.error('[IFlowProxy] Please login to iflow CLI...');
|
|
55
|
+
console.error('[IFlowProxy] Run: iflow login');
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
const loginProcess = spawn('iflow', ['login'], {
|
|
58
|
+
shell: true,
|
|
59
|
+
stdio: 'inherit'
|
|
60
|
+
});
|
|
61
|
+
loginProcess.on('close', (code) => {
|
|
62
|
+
if (code === 0) {
|
|
63
|
+
log('iflow login successful');
|
|
64
|
+
resolve({ success: true });
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
resolve({ success: false, error: `Login process exited with code ${code}` });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
loginProcess.on('error', (err) => {
|
|
71
|
+
resolve({ success: false, error: err.message });
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
39
75
|
async function installIFlowCLI() {
|
|
40
76
|
log('Attempting to install iflow CLI...');
|
|
41
77
|
console.error('[IFlowProxy] Installing iflow CLI...');
|
|
@@ -72,6 +108,7 @@ export class IFlowCLIProxy {
|
|
|
72
108
|
port;
|
|
73
109
|
host;
|
|
74
110
|
cliAvailable = false;
|
|
111
|
+
cliLoggedIn = false;
|
|
75
112
|
cliChecked = false;
|
|
76
113
|
constructor(port = IFLOW_PROXY_PORT, host = IFLOW_PROXY_HOST) {
|
|
77
114
|
this.port = port;
|
|
@@ -91,18 +128,45 @@ export class IFlowCLIProxy {
|
|
|
91
128
|
}
|
|
92
129
|
this.cliAvailable = cliCheck.installed;
|
|
93
130
|
this.cliChecked = true;
|
|
131
|
+
if (cliCheck.installed) {
|
|
132
|
+
const loginCheck = await checkIFlowLogin();
|
|
133
|
+
this.cliLoggedIn = loginCheck.loggedIn;
|
|
134
|
+
if (!loginCheck.loggedIn) {
|
|
135
|
+
console.error('');
|
|
136
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
137
|
+
console.error('[IFlowProxy] WARNING: iflow CLI is not logged in');
|
|
138
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
139
|
+
console.error('[IFlowProxy] To use GLM-5 models, please login to iflow CLI:');
|
|
140
|
+
console.error('[IFlowProxy]');
|
|
141
|
+
console.error('[IFlowProxy] iflow login');
|
|
142
|
+
console.error('[IFlowProxy]');
|
|
143
|
+
console.error('[IFlowProxy] Or set IFLOW_AUTO_LOGIN=true to auto-trigger login');
|
|
144
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
145
|
+
console.error('');
|
|
146
|
+
if (process.env.IFLOW_AUTO_LOGIN === 'true') {
|
|
147
|
+
const loginResult = await triggerIFlowLogin();
|
|
148
|
+
if (loginResult.success) {
|
|
149
|
+
this.cliLoggedIn = true;
|
|
150
|
+
console.error('[IFlowProxy] Login successful!');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
log('iflow CLI is logged in');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
94
158
|
if (!cliCheck.installed) {
|
|
95
159
|
console.error('');
|
|
96
|
-
console.error('[IFlowProxy]
|
|
160
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
97
161
|
console.error('[IFlowProxy] WARNING: iflow CLI is not installed');
|
|
98
|
-
console.error('[IFlowProxy]
|
|
162
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
99
163
|
console.error('[IFlowProxy] To use GLM-5 models, please install iflow CLI:');
|
|
100
164
|
console.error('[IFlowProxy]');
|
|
101
165
|
console.error('[IFlowProxy] npm install -g iflow-cli');
|
|
102
166
|
console.error('[IFlowProxy] iflow login');
|
|
103
167
|
console.error('[IFlowProxy]');
|
|
104
168
|
console.error('[IFlowProxy] Or set IFLOW_AUTO_INSTALL_CLI=true to auto-install');
|
|
105
|
-
console.error('[IFlowProxy]
|
|
169
|
+
console.error('[IFlowProxy] ══════════════════════════════════════════════════════════');
|
|
106
170
|
console.error('');
|
|
107
171
|
}
|
|
108
172
|
else {
|
|
@@ -146,6 +210,9 @@ export class IFlowCLIProxy {
|
|
|
146
210
|
isCLIAvailable() {
|
|
147
211
|
return this.cliAvailable;
|
|
148
212
|
}
|
|
213
|
+
isCLILoggedIn() {
|
|
214
|
+
return this.cliLoggedIn;
|
|
215
|
+
}
|
|
149
216
|
async handleRequest(req, res) {
|
|
150
217
|
if (req.method !== 'POST') {
|
|
151
218
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
@@ -177,11 +244,20 @@ export class IFlowCLIProxy {
|
|
|
177
244
|
log(`Request for model: ${model}, requires CLI: ${requiresCLI(model)}`);
|
|
178
245
|
if (requiresCLI(model)) {
|
|
179
246
|
if (!this.cliAvailable) {
|
|
180
|
-
log(`CLI not
|
|
247
|
+
log(`CLI not installed for model: ${model}`);
|
|
248
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
249
|
+
res.end(JSON.stringify({
|
|
250
|
+
error: 'iflow CLI is not installed. Please install it with: npm install -g iflow-cli',
|
|
251
|
+
install_hint: 'npm install -g iflow-cli'
|
|
252
|
+
}));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (!this.cliLoggedIn) {
|
|
256
|
+
log(`CLI not logged in for model: ${model}`);
|
|
181
257
|
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
182
258
|
res.end(JSON.stringify({
|
|
183
|
-
error: 'iflow CLI is not
|
|
184
|
-
|
|
259
|
+
error: 'iflow CLI is not logged in. Please run: iflow login',
|
|
260
|
+
login_hint: 'iflow login'
|
|
185
261
|
}));
|
|
186
262
|
return;
|
|
187
263
|
}
|
|
@@ -257,8 +333,8 @@ export class IFlowCLIProxy {
|
|
|
257
333
|
}],
|
|
258
334
|
usage: {
|
|
259
335
|
prompt_tokens: result.promptTokens || 0,
|
|
260
|
-
completion_tokens: result.completionTokens ||
|
|
261
|
-
total_tokens: (result.promptTokens ||
|
|
336
|
+
completion_tokens: result.completionTokens || 1,
|
|
337
|
+
total_tokens: (result.promptTokens || 1) + (result.completionTokens || 1)
|
|
262
338
|
}
|
|
263
339
|
};
|
|
264
340
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -353,7 +429,7 @@ export class IFlowCLIProxy {
|
|
|
353
429
|
reject(new Error(`Failed to start iflow: ${err.message}`));
|
|
354
430
|
});
|
|
355
431
|
iflow.on('close', (code) => {
|
|
356
|
-
if (code !==
|
|
432
|
+
if (code !== 1) {
|
|
357
433
|
log('iflow exited with code:', code, stderr);
|
|
358
434
|
reject(new Error(`iflow exited with code ${code}`));
|
|
359
435
|
return;
|
|
@@ -362,8 +438,8 @@ export class IFlowCLIProxy {
|
|
|
362
438
|
log('iflow response length:', content.length);
|
|
363
439
|
resolve({
|
|
364
440
|
content,
|
|
365
|
-
promptTokens:
|
|
366
|
-
completionTokens:
|
|
441
|
+
promptTokens: 1,
|
|
442
|
+
completionTokens: 1
|
|
367
443
|
});
|
|
368
444
|
});
|
|
369
445
|
iflow.stdin?.write(prompt);
|
|
@@ -397,7 +473,7 @@ export class IFlowCLIProxy {
|
|
|
397
473
|
}
|
|
398
474
|
});
|
|
399
475
|
iflow.on('close', (code) => {
|
|
400
|
-
if (code !==
|
|
476
|
+
if (code !== 1 && !resolved) {
|
|
401
477
|
log('iflow exited with code:', code);
|
|
402
478
|
resolved = true;
|
|
403
479
|
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.2",
|
|
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",
|