@iamtoricool/opencool-qwen-auth 0.0.1-alpha

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 ADDED
@@ -0,0 +1,125 @@
1
+ # OpenCool Qwen Auth Plugin
2
+
3
+ Qwen AI OAuth Authentication Plugin for [opencode](https://opencode.ai) - Access Qwen models via your chat.qwen.ai subscription.
4
+
5
+ ## Overview
6
+
7
+ This plugin enables opencode to use Qwen AI's models (Qwen3 Max, Qwen3 Coder, etc.) via OAuth authentication with Qwen's chat platform. Instead of using API keys, you can authenticate using your existing Qwen Chat subscription.
8
+
9
+ ## Supported Models
10
+
11
+ - **qwen3-max** - Most capable Qwen3 model for complex tasks
12
+ - **qwen3-coder-plus** - Optimized for code generation and programming
13
+ - **qwen3-vl-plus** - Vision language model for image understanding
14
+ - **qwen3-235b-a22b** - Large mixture-of-experts model
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @iamtoricool/opencool-qwen-auth
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ Add to your `~/.opencode/opencode.json`:
25
+
26
+ ```json
27
+ {
28
+ "plugin": ["@iamtoricool/opencool-qwen-auth"],
29
+ "provider": {
30
+ "qwen": {
31
+ "options": {}
32
+ }
33
+ },
34
+ "model": "qwen/qwen3-max",
35
+ "models": {
36
+ "qwen3-max": {
37
+ "id": "qwen3-max",
38
+ "name": "Qwen3 Max",
39
+ "variants": {
40
+ "latest": "qwen3-max"
41
+ }
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ## Authentication
48
+
49
+ Run the login command:
50
+
51
+ ```bash
52
+ opencode providers login qwen
53
+ ```
54
+
55
+ This will:
56
+ 1. Open your browser to Qwen's OAuth authorization page
57
+ 2. Start a local callback server on port 1455
58
+ 3. Exchange the authorization code for access/refresh tokens
59
+ 4. Store tokens securely for future use
60
+
61
+ ## Features
62
+
63
+ - **OAuth 2.0 with PKCE** - Secure authentication flow
64
+ - **Token Refresh** - Automatic token refresh when expired
65
+ - **Model Configuration** - Per-model options support
66
+ - **Streaming Support** - Full SSE streaming for real-time responses
67
+ - **Fallback Options** - Manual URL paste if browser auto-open fails
68
+
69
+ ## Architecture
70
+
71
+ The plugin follows the opencode plugin architecture:
72
+
73
+ ```
74
+ index.ts # Main plugin entry point
75
+ lib/
76
+ types.ts # TypeScript type definitions
77
+ constants.ts # OAuth endpoints, client IDs, models
78
+ config.ts # Configuration loading
79
+ logger.ts # Request logging
80
+ auth/
81
+ auth.ts # PKCE, token exchange, JWT decode
82
+ server.ts # Local OAuth callback server
83
+ browser.ts # Platform-specific browser opening
84
+ request/
85
+ fetch-helpers.ts # 7-step fetch orchestration
86
+ request-transformer.ts # Model normalization, body transforms
87
+ response-handler.ts # SSE parsing
88
+ config/
89
+ opencode-modern.json # Model definitions
90
+ test/ # Comprehensive test suite
91
+ ```
92
+
93
+ ## Development
94
+
95
+ ```bash
96
+ # Install dependencies
97
+ npm install
98
+
99
+ # Run type check
100
+ npm run typecheck
101
+
102
+ # Run tests
103
+ npm test
104
+
105
+ # Run tests with watch mode
106
+ npm run test:watch
107
+ ```
108
+
109
+ ## OAuth Configuration
110
+
111
+ The plugin uses Qwen's OAuth endpoints:
112
+
113
+ - **Authorization URL**: `https://auth.qwen.ai/oauth/authorize`
114
+ - **Token URL**: `https://auth.qwen.ai/oauth/token`
115
+ - **API Base**: `https://chat.qwen.ai/backend-api`
116
+ - **Redirect URI**: `http://localhost:1455/auth/callback`
117
+ - **Scopes**: `openid profile email offline_access`
118
+
119
+ ## License
120
+
121
+ MIT
122
+
123
+ ## Contributing
124
+
125
+ Contributions are welcome! Please ensure tests pass before submitting PRs.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Qwen AI OAuth Authentication Plugin for opencode
3
+ *
4
+ * This plugin enables opencode to use Qwen's AI models via OAuth authentication
5
+ * with chat.qwen.ai, allowing users to leverage their Qwen subscription.
6
+ *
7
+ * @license MIT
8
+ */
9
+ import type { Plugin } from "@opencode-ai/plugin";
10
+ /**
11
+ * Qwen AI OAuth authentication plugin for opencode
12
+ *
13
+ * This plugin enables opencode to use Qwen AI models via OAuth authentication,
14
+ * allowing users to leverage their Qwen Chat subscription.
15
+ *
16
+ * @example
17
+ * ```json
18
+ * {
19
+ * "plugin": ["opencool-qwen-auth"],
20
+ * "model": "qwen/qwen3-max"
21
+ * }
22
+ * ```
23
+ */
24
+ export declare const QwenAuthPlugin: Plugin;
25
+ export default QwenAuthPlugin;
26
+ export type { UserConfig, PluginConfig, RequestBody, TokenResult, AuthorizationFlow, } from "./lib/types.js";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAoC/D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,MA+P5B,CAAC;AAEF,eAAe,cAAc,CAAC;AAG9B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,iBAAiB,GAClB,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Qwen AI OAuth Authentication Plugin for opencode
3
+ *
4
+ * This plugin enables opencode to use Qwen's AI models via OAuth authentication
5
+ * with chat.qwen.ai, allowing users to leverage their Qwen subscription.
6
+ *
7
+ * @license MIT
8
+ */
9
+ import { createAuthorizationFlow, decodeJWT, exchangeAuthorizationCode, parseAuthorizationInput, extractBrowserSession, isBrowserSessionAvailable, } from "./lib/auth/auth.js";
10
+ import { REDIRECT_URI } from "./lib/constants.js";
11
+ import { openBrowserUrl } from "./lib/auth/browser.js";
12
+ import { startLocalOAuthServer } from "./lib/auth/server.js";
13
+ import { loadPluginConfig, parseUserConfig, initLogger } from "./lib/config.js";
14
+ import { AUTH_LABELS, QWEN_BASE_URL, DUMMY_API_KEY, LOG_STAGES, PLUGIN_NAME, PROVIDER_ID, } from "./lib/constants.js";
15
+ import { logRequest, logDebug } from "./lib/logger.js";
16
+ import { createQwenHeaders, extractRequestUrl, handleErrorResponse, handleSuccessResponse, refreshAndUpdateToken, rewriteUrlForQwen, shouldRefreshToken, transformRequestForQwen, } from "./lib/request/fetch-helpers.js";
17
+ /**
18
+ * Qwen AI OAuth authentication plugin for opencode
19
+ *
20
+ * This plugin enables opencode to use Qwen AI models via OAuth authentication,
21
+ * allowing users to leverage their Qwen Chat subscription.
22
+ *
23
+ * @example
24
+ * ```json
25
+ * {
26
+ * "plugin": ["opencool-qwen-auth"],
27
+ * "model": "qwen/qwen3-max"
28
+ * }
29
+ * ```
30
+ */
31
+ export const QwenAuthPlugin = async ({ client }) => {
32
+ // Initialize logger with plugin config
33
+ const pluginConfig = loadPluginConfig();
34
+ initLogger(pluginConfig);
35
+ /**
36
+ * Build manual OAuth flow for fallback when auto browser open fails
37
+ */
38
+ const buildManualOAuthFlow = (pkce, url) => ({
39
+ url,
40
+ method: "code",
41
+ instructions: AUTH_LABELS.INSTRUCTIONS_MANUAL,
42
+ callback: async (input) => {
43
+ const parsed = parseAuthorizationInput(input);
44
+ if (!parsed.code) {
45
+ return { type: "failed" };
46
+ }
47
+ const tokens = await exchangeAuthorizationCode(parsed.code, pkce.verifier, REDIRECT_URI);
48
+ return tokens?.type === "success" ? tokens : { type: "failed" };
49
+ },
50
+ });
51
+ return {
52
+ auth: {
53
+ provider: PROVIDER_ID,
54
+ /**
55
+ * Loader function that configures OAuth authentication and request handling
56
+ *
57
+ * This function:
58
+ * 1. Validates OAuth authentication
59
+ * 2. Extracts user info from access token
60
+ * 3. Loads user configuration from opencode.json
61
+ * 4. Returns SDK configuration with custom fetch implementation
62
+ *
63
+ * @param getAuth - Function to retrieve current auth state
64
+ * @param provider - Provider configuration from opencode.json
65
+ * @returns SDK configuration object or empty object for non-OAuth auth
66
+ */
67
+ async loader(getAuth, provider) {
68
+ const auth = await getAuth();
69
+ // Only handle OAuth auth type, skip API key auth
70
+ if (auth.type !== "oauth") {
71
+ return {};
72
+ }
73
+ // Decode JWT to verify it's valid
74
+ const decoded = decodeJWT(auth.access);
75
+ if (!decoded) {
76
+ logDebug(`[${PLUGIN_NAME}] Failed to decode access token (skipping plugin)`);
77
+ return {};
78
+ }
79
+ logDebug(`[${PLUGIN_NAME}] Authenticated as:`, decoded.email || decoded.sub);
80
+ // Extract user configuration (global + per-model options)
81
+ const userConfig = parseUserConfig(provider);
82
+ // Return SDK configuration
83
+ return {
84
+ apiKey: DUMMY_API_KEY,
85
+ baseURL: QWEN_BASE_URL,
86
+ /**
87
+ * Custom fetch implementation for Qwen API
88
+ *
89
+ * Handles:
90
+ * - Token refresh when expired
91
+ * - URL rewriting for Qwen backend
92
+ * - Request body transformation
93
+ * - OAuth header injection
94
+ * - SSE to JSON conversion for non-streaming requests
95
+ * - Error handling and logging
96
+ *
97
+ * @param input - Request URL or Request object
98
+ * @param init - Request options
99
+ * @returns Response from Qwen API
100
+ */
101
+ async fetch(input, init) {
102
+ // Step 1: Check and refresh token if needed
103
+ let currentAuth = await getAuth();
104
+ if (shouldRefreshToken(currentAuth)) {
105
+ currentAuth = await refreshAndUpdateToken(currentAuth, client);
106
+ }
107
+ // Step 2: Extract and rewrite URL for Qwen backend
108
+ const originalUrl = extractRequestUrl(input);
109
+ const url = rewriteUrlForQwen(originalUrl);
110
+ // Step 3: Transform request body with user configuration
111
+ // Capture original stream value before transformation
112
+ const originalBody = init?.body
113
+ ? JSON.parse(init.body)
114
+ : {};
115
+ const isStreaming = originalBody.stream === true;
116
+ const transformation = await transformRequestForQwen(init, url, userConfig);
117
+ const requestInit = transformation?.updatedInit ?? init;
118
+ // Step 4: Create headers with OAuth token
119
+ const accessToken = currentAuth.type === "oauth" ? currentAuth.access : "";
120
+ const headers = createQwenHeaders(requestInit, accessToken);
121
+ // Step 5: Make request to Qwen API
122
+ logDebug(`[${PLUGIN_NAME}] Making request to:`, url);
123
+ const response = await fetch(url, {
124
+ ...requestInit,
125
+ headers,
126
+ });
127
+ // Step 6: Log response
128
+ logRequest(LOG_STAGES.RESPONSE, {
129
+ status: response.status,
130
+ ok: response.ok,
131
+ statusText: response.statusText,
132
+ headers: Object.fromEntries(response.headers.entries()),
133
+ });
134
+ // Step 7: Handle error or success response
135
+ if (!response.ok) {
136
+ return await handleErrorResponse(response);
137
+ }
138
+ return await handleSuccessResponse(response, isStreaming);
139
+ },
140
+ };
141
+ },
142
+ methods: [
143
+ {
144
+ label: AUTH_LABELS.OAUTH,
145
+ type: "oauth",
146
+ /**
147
+ * OAuth authorization flow
148
+ *
149
+ * Steps:
150
+ * 1. Generate PKCE challenge and state for security
151
+ * 2. Start local OAuth callback server on port 1455
152
+ * 3. Open browser to Qwen authorization page
153
+ * 4. Wait for user to complete login
154
+ * 5. Exchange authorization code for tokens
155
+ *
156
+ * @returns Authorization flow configuration
157
+ */
158
+ authorize: async () => {
159
+ const { pkce, state, url } = await createAuthorizationFlow();
160
+ const serverInfo = await startLocalOAuthServer({ state });
161
+ // Attempt to open browser automatically
162
+ openBrowserUrl(url);
163
+ if (!serverInfo.ready) {
164
+ serverInfo.close();
165
+ return buildManualOAuthFlow(pkce, url);
166
+ }
167
+ return {
168
+ url,
169
+ method: "auto",
170
+ instructions: AUTH_LABELS.INSTRUCTIONS,
171
+ callback: async () => {
172
+ const result = await serverInfo.waitForCode(state);
173
+ serverInfo.close();
174
+ if (!result) {
175
+ return { type: "failed" };
176
+ }
177
+ const tokens = await exchangeAuthorizationCode(result.code, pkce.verifier, REDIRECT_URI);
178
+ return tokens?.type === "success"
179
+ ? tokens
180
+ : { type: "failed" };
181
+ },
182
+ };
183
+ },
184
+ },
185
+ {
186
+ label: AUTH_LABELS.OAUTH_MANUAL,
187
+ type: "oauth",
188
+ authorize: async () => {
189
+ const { pkce, url } = await createAuthorizationFlow();
190
+ return buildManualOAuthFlow(pkce, url);
191
+ },
192
+ },
193
+ {
194
+ label: "Use Browser Session (Firefox/Chrome)",
195
+ type: "oauth",
196
+ authorize: async () => {
197
+ // Try to extract session from browser
198
+ const token = await extractBrowserSession();
199
+ if (token) {
200
+ // Validate and exchange the token
201
+ const tokens = await exchangeAuthorizationCode(token);
202
+ if (tokens.type === "success") {
203
+ return {
204
+ url: "https://chat.qwen.ai",
205
+ method: "code",
206
+ instructions: "Browser session authenticated successfully!",
207
+ callback: async () => tokens,
208
+ };
209
+ }
210
+ }
211
+ // If browser session failed, provide manual instructions
212
+ const available = await isBrowserSessionAvailable();
213
+ if (!available) {
214
+ return {
215
+ url: "https://chat.qwen.ai",
216
+ method: "code",
217
+ instructions: "Browser session extraction requires better-sqlite3. Please install it with: npm install better-sqlite3\n\nOr use API key authentication instead.",
218
+ callback: async () => ({ type: "failed" }),
219
+ };
220
+ }
221
+ return {
222
+ url: "https://chat.qwen.ai",
223
+ method: "code",
224
+ instructions: "No Qwen session found in browser cookies. Please:\n1. Open Firefox or Chrome\n2. Go to https://chat.qwen.ai\n3. Sign in with your account\n4. Try again\n\nOr use API key authentication.",
225
+ callback: async () => ({ type: "failed" }),
226
+ };
227
+ },
228
+ },
229
+ {
230
+ label: AUTH_LABELS.API_KEY,
231
+ type: "api",
232
+ },
233
+ ],
234
+ },
235
+ };
236
+ };
237
+ export default QwenAuthPlugin;
238
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@iamtoricool/opencool-qwen-auth",
3
+ "version": "0.0.1-alpha",
4
+ "description": "Qwen AI OAuth Authentication Plugin for opencode - Access Qwen models via chat.qwen.ai subscription",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc && cp lib/oauth-success.html dist/lib/",
10
+ "typecheck": "tsc --noEmit",
11
+ "test": "vitest run",
12
+ "test:e2e": "vitest run test/e2e/",
13
+ "test:unit": "vitest run test/*.test.ts",
14
+ "test:watch": "vitest",
15
+ "test:coverage": "vitest run --coverage"
16
+ },
17
+ "peerDependencies": {
18
+ "@opencode-ai/plugin": "^1.0.150"
19
+ },
20
+ "devDependencies": {
21
+ "@opencode-ai/plugin": "^1.0.150",
22
+ "@opencode-ai/sdk": "^1.0.150",
23
+ "@types/node": "^24.6.2",
24
+ "@vitest/ui": "^3.2.4",
25
+ "msw": "^2.6.0",
26
+ "typescript": "^5.9.3",
27
+ "vitest": "^3.2.4"
28
+ },
29
+ "dependencies": {
30
+ "@openauthjs/openauth": "^0.4.3",
31
+ "hono": "^4.10.4"
32
+ },
33
+ "engines": {
34
+ "node": ">=20.0.0"
35
+ },
36
+ "keywords": [
37
+ "opencode",
38
+ "plugin",
39
+ "qwen",
40
+ "oauth",
41
+ "ai",
42
+ "qwen3"
43
+ ],
44
+ "author": "",
45
+ "license": "MIT"
46
+ }