@iamtoricool/opencool-qwen-auth 0.0.1-alpha → 0.0.2-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/dist/lib/auth/auth.d.ts +72 -0
- package/dist/lib/auth/auth.d.ts.map +1 -0
- package/dist/lib/auth/auth.js +212 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/browser-session.d.ts +49 -0
- package/dist/lib/auth/browser-session.d.ts.map +1 -0
- package/dist/lib/auth/browser-session.js +211 -0
- package/dist/lib/auth/browser-session.js.map +1 -0
- package/dist/lib/auth/browser.d.ts +17 -0
- package/dist/lib/auth/browser.d.ts.map +1 -0
- package/dist/lib/auth/browser.js +86 -0
- package/dist/lib/auth/browser.js.map +1 -0
- package/dist/lib/auth/server.d.ts +14 -0
- package/dist/lib/auth/server.d.ts.map +1 -0
- package/dist/lib/auth/server.js +253 -0
- package/dist/lib/auth/server.js.map +1 -0
- package/dist/lib/config.d.ts +28 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +67 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +77 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +109 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/logger.d.ts +49 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +56 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/oauth-success.html +83 -0
- package/dist/lib/request/fetch-helpers.d.ts +66 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/request/fetch-helpers.js +193 -0
- package/dist/lib/request/fetch-helpers.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +27 -0
- package/dist/lib/request/request-transformer.d.ts.map +1 -0
- package/dist/lib/request/request-transformer.js +159 -0
- package/dist/lib/request/request-transformer.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +32 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -0
- package/dist/lib/request/response-handler.js +176 -0
- package/dist/lib/request/response-handler.js.map +1 -0
- package/dist/lib/types.d.ts +159 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +5 -0
- package/dist/lib/types.js.map +1 -0
- package/iamtoricool-opencool-qwen-auth-0.0.1-alpha.tgz +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser utilities for OAuth flow
|
|
3
|
+
* Handles platform-specific browser opening
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { PLATFORM_OPENERS } from "../constants.js";
|
|
9
|
+
/**
|
|
10
|
+
* Gets the platform-specific command to open a URL in the default browser
|
|
11
|
+
* @returns Browser opener command for the current platform
|
|
12
|
+
*/
|
|
13
|
+
export function getBrowserOpener() {
|
|
14
|
+
const platform = process.platform;
|
|
15
|
+
if (platform === "darwin")
|
|
16
|
+
return PLATFORM_OPENERS.darwin;
|
|
17
|
+
if (platform === "win32")
|
|
18
|
+
return PLATFORM_OPENERS.win32;
|
|
19
|
+
return PLATFORM_OPENERS.linux;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a command exists in PATH
|
|
23
|
+
* @param command - Command to check
|
|
24
|
+
* @returns True if command exists
|
|
25
|
+
*/
|
|
26
|
+
function commandExists(command) {
|
|
27
|
+
if (!command)
|
|
28
|
+
return false;
|
|
29
|
+
// "start" is a shell builtin on Windows; rely on shell execution
|
|
30
|
+
if (process.platform === "win32" && command.toLowerCase() === "start") {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const pathValue = process.env.PATH || "";
|
|
34
|
+
const entries = pathValue.split(path.delimiter).filter(Boolean);
|
|
35
|
+
if (entries.length === 0)
|
|
36
|
+
return false;
|
|
37
|
+
if (process.platform === "win32") {
|
|
38
|
+
const pathext = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM")
|
|
39
|
+
.split(";")
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
for (const ext of pathext) {
|
|
43
|
+
const candidate = path.join(entry, `${command}${ext}`);
|
|
44
|
+
if (fs.existsSync(candidate))
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
const candidate = path.join(entry, command);
|
|
52
|
+
if (fs.existsSync(candidate))
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Opens a URL in the default browser
|
|
59
|
+
* Silently fails if browser cannot be opened (user can copy URL manually)
|
|
60
|
+
* @param url - URL to open
|
|
61
|
+
* @returns True if a browser launch was attempted
|
|
62
|
+
*/
|
|
63
|
+
export function openBrowserUrl(url) {
|
|
64
|
+
try {
|
|
65
|
+
const opener = getBrowserOpener();
|
|
66
|
+
if (!commandExists(opener)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const child = spawn(opener, [url], {
|
|
70
|
+
stdio: "ignore",
|
|
71
|
+
shell: process.platform === "win32",
|
|
72
|
+
detached: true,
|
|
73
|
+
});
|
|
74
|
+
child.on("error", () => {
|
|
75
|
+
// Silently fail - user can manually open the URL from instructions
|
|
76
|
+
});
|
|
77
|
+
// Unref so the process can exit independently
|
|
78
|
+
child.unref();
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// Silently fail - user can manually open the URL from instructions
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../lib/auth/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local OAuth callback server for handling the OAuth redirect
|
|
3
|
+
* Listens on port 1455 for the authorization code/token
|
|
4
|
+
*/
|
|
5
|
+
import type { OAuthServerInfo } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Start a local HTTP server that waits for /auth/callback and returns the token
|
|
8
|
+
* @param options - OAuth state for validation
|
|
9
|
+
* @returns Promise that resolves to server info
|
|
10
|
+
*/
|
|
11
|
+
export declare function startLocalOAuthServer({ state }: {
|
|
12
|
+
state: string;
|
|
13
|
+
}): Promise<OAuthServerInfo>;
|
|
14
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../lib/auth/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAoKnD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAqF5F"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local OAuth callback server for handling the OAuth redirect
|
|
3
|
+
* Listens on port 1455 for the authorization code/token
|
|
4
|
+
*/
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { PLUGIN_NAME, ERROR_MESSAGES } from "../constants.js";
|
|
9
|
+
// Resolve path to oauth-success.html (one level up from auth/ subfolder)
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const successHtmlPath = path.join(__dirname, "..", "oauth-success.html");
|
|
12
|
+
/**
|
|
13
|
+
* Generate HTML page that extracts token from URL fragment
|
|
14
|
+
* This is needed because URL fragments are not sent to the server
|
|
15
|
+
*/
|
|
16
|
+
function getFragmentExtractorPage(state) {
|
|
17
|
+
return `
|
|
18
|
+
<!DOCTYPE html>
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="UTF-8">
|
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
23
|
+
<title>Qwen Authentication</title>
|
|
24
|
+
<style>
|
|
25
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
26
|
+
body {
|
|
27
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
28
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
29
|
+
min-height: 100vh;
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
padding: 20px;
|
|
34
|
+
}
|
|
35
|
+
.container {
|
|
36
|
+
background: white;
|
|
37
|
+
border-radius: 16px;
|
|
38
|
+
padding: 48px;
|
|
39
|
+
text-align: center;
|
|
40
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
41
|
+
max-width: 500px;
|
|
42
|
+
width: 100%;
|
|
43
|
+
}
|
|
44
|
+
.icon {
|
|
45
|
+
width: 80px;
|
|
46
|
+
height: 80px;
|
|
47
|
+
background: linear-gradient(135deg, #10a37f 0%, #0d8c6d 100%);
|
|
48
|
+
border-radius: 50%;
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
margin: 0 auto 24px;
|
|
53
|
+
font-size: 40px;
|
|
54
|
+
color: white;
|
|
55
|
+
}
|
|
56
|
+
.icon.error {
|
|
57
|
+
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
|
|
58
|
+
}
|
|
59
|
+
h1 {
|
|
60
|
+
color: #1a1a1a;
|
|
61
|
+
font-size: 28px;
|
|
62
|
+
margin-bottom: 12px;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
}
|
|
65
|
+
p {
|
|
66
|
+
color: #666;
|
|
67
|
+
font-size: 16px;
|
|
68
|
+
line-height: 1.6;
|
|
69
|
+
margin-bottom: 16px;
|
|
70
|
+
}
|
|
71
|
+
.token-box {
|
|
72
|
+
background: #f5f5f5;
|
|
73
|
+
border-radius: 8px;
|
|
74
|
+
padding: 16px;
|
|
75
|
+
margin: 20px 0;
|
|
76
|
+
word-break: break-all;
|
|
77
|
+
font-family: monospace;
|
|
78
|
+
font-size: 12px;
|
|
79
|
+
text-align: left;
|
|
80
|
+
max-height: 150px;
|
|
81
|
+
overflow-y: auto;
|
|
82
|
+
border: 1px solid #ddd;
|
|
83
|
+
}
|
|
84
|
+
.loading {
|
|
85
|
+
display: inline-block;
|
|
86
|
+
width: 40px;
|
|
87
|
+
height: 40px;
|
|
88
|
+
border: 4px solid #f3f3f3;
|
|
89
|
+
border-top: 4px solid #667eea;
|
|
90
|
+
border-radius: 50%;
|
|
91
|
+
animation: spin 1s linear infinite;
|
|
92
|
+
margin: 20px auto;
|
|
93
|
+
}
|
|
94
|
+
@keyframes spin {
|
|
95
|
+
0% { transform: rotate(0deg); }
|
|
96
|
+
100% { transform: rotate(360deg); }
|
|
97
|
+
}
|
|
98
|
+
.hidden { display: none; }
|
|
99
|
+
</style>
|
|
100
|
+
</head>
|
|
101
|
+
<body>
|
|
102
|
+
<div class="container">
|
|
103
|
+
<div id="loading-state">
|
|
104
|
+
<div class="loading"></div>
|
|
105
|
+
<h1>Completing Authentication...</h1>
|
|
106
|
+
<p>Please wait while we complete the authentication process.</p>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div id="success-state" class="hidden">
|
|
110
|
+
<div class="icon">✓</div>
|
|
111
|
+
<h1>Authentication Successful!</h1>
|
|
112
|
+
<p>You can now close this window and return to the terminal.</p>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div id="error-state" class="hidden">
|
|
116
|
+
<div class="icon error">✗</div>
|
|
117
|
+
<h1>Authentication Failed</h1>
|
|
118
|
+
<p id="error-message">An error occurred during authentication.</p>
|
|
119
|
+
<div id="token-display" class="token-box hidden"></div>
|
|
120
|
+
<p>If you see a token above, you may need to manually copy it.</p>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<script>
|
|
125
|
+
const STATE = "${state}";
|
|
126
|
+
|
|
127
|
+
async function completeAuth() {
|
|
128
|
+
try {
|
|
129
|
+
// Extract token from URL fragment
|
|
130
|
+
const fragment = window.location.hash;
|
|
131
|
+
const params = new URLSearchParams(fragment.substring(1));
|
|
132
|
+
const token = params.get("token");
|
|
133
|
+
|
|
134
|
+
if (!token) {
|
|
135
|
+
throw new Error("No token found in URL");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Send token to local server
|
|
139
|
+
const response = await fetch("/auth/callback?token=" + encodeURIComponent(token) + "&state=" + encodeURIComponent(STATE));
|
|
140
|
+
|
|
141
|
+
if (response.ok) {
|
|
142
|
+
document.getElementById("loading-state").classList.add("hidden");
|
|
143
|
+
document.getElementById("success-state").classList.remove("hidden");
|
|
144
|
+
} else {
|
|
145
|
+
throw new Error("Server rejected token");
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
document.getElementById("loading-state").classList.add("hidden");
|
|
149
|
+
document.getElementById("error-state").classList.remove("hidden");
|
|
150
|
+
document.getElementById("error-message").textContent = error.message;
|
|
151
|
+
|
|
152
|
+
// Show token if we have it
|
|
153
|
+
const fragment = window.location.hash;
|
|
154
|
+
if (fragment) {
|
|
155
|
+
document.getElementById("token-display").textContent = fragment;
|
|
156
|
+
document.getElementById("token-display").classList.remove("hidden");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Run on page load
|
|
162
|
+
completeAuth();
|
|
163
|
+
</script>
|
|
164
|
+
</body>
|
|
165
|
+
</html>
|
|
166
|
+
`.trim();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Start a local HTTP server that waits for /auth/callback and returns the token
|
|
170
|
+
* @param options - OAuth state for validation
|
|
171
|
+
* @returns Promise that resolves to server info
|
|
172
|
+
*/
|
|
173
|
+
export function startLocalOAuthServer({ state }) {
|
|
174
|
+
const server = http.createServer((req, res) => {
|
|
175
|
+
try {
|
|
176
|
+
const url = new URL(req.url || "", "http://localhost");
|
|
177
|
+
// Handle root path - serve fragment extractor page
|
|
178
|
+
if (url.pathname === "/") {
|
|
179
|
+
res.statusCode = 200;
|
|
180
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
181
|
+
res.end(getFragmentExtractorPage(state));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Only handle /auth/callback path
|
|
185
|
+
if (url.pathname !== "/auth/callback") {
|
|
186
|
+
res.statusCode = 404;
|
|
187
|
+
res.end("Not found");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Validate state
|
|
191
|
+
const returnedState = url.searchParams.get("state");
|
|
192
|
+
if (returnedState !== state) {
|
|
193
|
+
res.statusCode = 400;
|
|
194
|
+
res.end("State mismatch");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Extract token from query params (sent by JavaScript from fragment)
|
|
198
|
+
const token = url.searchParams.get("token");
|
|
199
|
+
if (!token) {
|
|
200
|
+
res.statusCode = 400;
|
|
201
|
+
res.end(ERROR_MESSAGES.MISSING_AUTH_CODE);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Serve success response
|
|
205
|
+
res.statusCode = 200;
|
|
206
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
207
|
+
res.end("<html><body>OK</body></html>");
|
|
208
|
+
// Store the token
|
|
209
|
+
server._lastToken = token;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
res.statusCode = 500;
|
|
213
|
+
res.end("Internal error");
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
return new Promise((resolve) => {
|
|
217
|
+
server
|
|
218
|
+
.listen(1455, "127.0.0.1", () => {
|
|
219
|
+
resolve({
|
|
220
|
+
port: 1455,
|
|
221
|
+
ready: true,
|
|
222
|
+
close: () => server.close(),
|
|
223
|
+
waitForCode: async () => {
|
|
224
|
+
const poll = () => new Promise((r) => setTimeout(r, 100));
|
|
225
|
+
for (let i = 0; i < 600; i++) {
|
|
226
|
+
const lastToken = server._lastToken;
|
|
227
|
+
if (lastToken)
|
|
228
|
+
return { code: lastToken };
|
|
229
|
+
await poll();
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
})
|
|
235
|
+
.on("error", (err) => {
|
|
236
|
+
console.error(`[${PLUGIN_NAME}] Failed to bind http://127.0.0.1:1455 (${err?.code}). Falling back to manual paste.`);
|
|
237
|
+
resolve({
|
|
238
|
+
port: 1455,
|
|
239
|
+
ready: false,
|
|
240
|
+
close: () => {
|
|
241
|
+
try {
|
|
242
|
+
server.close();
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Ignore close errors
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
waitForCode: async () => null,
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../lib/auth/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration loading for the Qwen Auth Plugin
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginConfig, UserConfig } from "./types.js";
|
|
5
|
+
import { initLogger as initLoggerFromLogger } from "./logger.js";
|
|
6
|
+
/**
|
|
7
|
+
* Load plugin configuration from ~/.opencode/qwen-auth-config.json
|
|
8
|
+
* @returns Plugin configuration with defaults
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadPluginConfig(): PluginConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Get debug mode from environment or config
|
|
13
|
+
* @param config - Plugin configuration
|
|
14
|
+
* @returns Whether debug mode is enabled
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDebugMode(config: PluginConfig): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Parse user configuration from provider options
|
|
19
|
+
* @param provider - Provider configuration from opencode.json
|
|
20
|
+
* @returns Normalized user configuration
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseUserConfig(provider: unknown): UserConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Initialize the logger with plugin configuration
|
|
25
|
+
* Re-exported from logger module for convenience
|
|
26
|
+
*/
|
|
27
|
+
export declare const initLogger: typeof initLoggerFromLogger;
|
|
28
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,YAAY,CAsB/C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAS1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,GAChB,UAAU,CASZ;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,6BAAuB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration loading for the Qwen Auth Plugin
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { PLUGIN_NAME } from "./constants.js";
|
|
8
|
+
import { initLogger as initLoggerFromLogger } from "./logger.js";
|
|
9
|
+
/**
|
|
10
|
+
* Load plugin configuration from ~/.opencode/qwen-auth-config.json
|
|
11
|
+
* @returns Plugin configuration with defaults
|
|
12
|
+
*/
|
|
13
|
+
export function loadPluginConfig() {
|
|
14
|
+
const configPath = join(homedir(), ".opencode", "qwen-auth-config.json");
|
|
15
|
+
if (!existsSync(configPath)) {
|
|
16
|
+
return {
|
|
17
|
+
debug: false,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const content = readFileSync(configPath, "utf-8");
|
|
22
|
+
const config = JSON.parse(content);
|
|
23
|
+
return {
|
|
24
|
+
debug: false,
|
|
25
|
+
...config,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.warn(`[${PLUGIN_NAME}] Failed to load plugin config:`, error);
|
|
30
|
+
return {
|
|
31
|
+
debug: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get debug mode from environment or config
|
|
37
|
+
* @param config - Plugin configuration
|
|
38
|
+
* @returns Whether debug mode is enabled
|
|
39
|
+
*/
|
|
40
|
+
export function getDebugMode(config) {
|
|
41
|
+
// Environment variable takes precedence
|
|
42
|
+
if (process.env.QWEN_AUTH_DEBUG === "true") {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (process.env.QWEN_AUTH_DEBUG === "false") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return config.debug ?? false;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parse user configuration from provider options
|
|
52
|
+
* @param provider - Provider configuration from opencode.json
|
|
53
|
+
* @returns Normalized user configuration
|
|
54
|
+
*/
|
|
55
|
+
export function parseUserConfig(provider) {
|
|
56
|
+
const providerConfig = provider;
|
|
57
|
+
return {
|
|
58
|
+
global: providerConfig?.options || {},
|
|
59
|
+
models: providerConfig?.models || {},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Initialize the logger with plugin configuration
|
|
64
|
+
* Re-exported from logger module for convenience
|
|
65
|
+
*/
|
|
66
|
+
export const initLogger = initLoggerFromLogger;
|
|
67
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEjE;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,uBAAuB,CAAC,CAAC;IAEzE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QACnD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,IAAI,WAAW,iCAAiC,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO;YACL,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,wCAAwC;IACxC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,OAAO,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAiB;IAEjB,MAAM,cAAc,GAAG,QAEV,CAAC;IAEd,OAAO;QACL,MAAM,EAAG,cAAc,EAAE,OAAgC,IAAI,EAAE;QAC/D,MAAM,EAAE,cAAc,EAAE,MAAM,IAAI,EAAE;KACrC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used throughout the Qwen Auth Plugin
|
|
3
|
+
* Centralized for easy maintenance and configuration
|
|
4
|
+
*/
|
|
5
|
+
/** Plugin identifier for logging and error messages */
|
|
6
|
+
export declare const PLUGIN_NAME = "opencool-qwen-auth";
|
|
7
|
+
/** Base URL for Qwen chat backend API */
|
|
8
|
+
export declare const QWEN_BASE_URL = "https://chat.qwen.ai/api";
|
|
9
|
+
/** Dummy API key used for Qwen SDK (actual auth via OAuth) */
|
|
10
|
+
export declare const DUMMY_API_KEY = "qwen-oauth";
|
|
11
|
+
/** Provider ID for opencode configuration */
|
|
12
|
+
export declare const PROVIDER_ID = "qwen";
|
|
13
|
+
/** OAuth Client ID from Google (extracted from HAR) */
|
|
14
|
+
export declare const GOOGLE_CLIENT_ID = "452911428355-3lrs59r3icntb0d0e053n98fkg9ha1j3.apps.googleusercontent.com";
|
|
15
|
+
/** Qwen OAuth endpoints (uses Google OAuth) */
|
|
16
|
+
export declare const QWEN_OAUTH_LOGIN = "https://chat.qwen.ai/oauth/google/login";
|
|
17
|
+
export declare const QWEN_OAUTH_CALLBACK = "https://chat.qwen.ai/oauth/google/callback";
|
|
18
|
+
/** Google OAuth authorization endpoint */
|
|
19
|
+
export declare const GOOGLE_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
20
|
+
/** OAuth redirect URI for local callback */
|
|
21
|
+
export declare const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
22
|
+
/** OAuth scope for Google */
|
|
23
|
+
export declare const GOOGLE_SCOPE = "openid email profile";
|
|
24
|
+
/** HTTP Status Codes */
|
|
25
|
+
export declare const HTTP_STATUS: {
|
|
26
|
+
readonly OK: 200;
|
|
27
|
+
readonly UNAUTHORIZED: 401;
|
|
28
|
+
readonly NOT_FOUND: 404;
|
|
29
|
+
readonly TOO_MANY_REQUESTS: 429;
|
|
30
|
+
};
|
|
31
|
+
/** Qwen-specific headers */
|
|
32
|
+
export declare const QWEN_HEADERS: {
|
|
33
|
+
readonly AUTHORIZATION: "Authorization";
|
|
34
|
+
readonly CONTENT_TYPE: "Content-Type";
|
|
35
|
+
readonly ACCEPT: "Accept";
|
|
36
|
+
};
|
|
37
|
+
/** URL path segments */
|
|
38
|
+
export declare const URL_PATHS: {
|
|
39
|
+
readonly CHAT_COMPLETIONS: "/v1/chat/completions";
|
|
40
|
+
readonly MODELS: "/models";
|
|
41
|
+
readonly AUTHS: "/v1/auths";
|
|
42
|
+
};
|
|
43
|
+
/** Error messages */
|
|
44
|
+
export declare const ERROR_MESSAGES: {
|
|
45
|
+
readonly NO_ACCOUNT_ID: "Failed to extract account info from token";
|
|
46
|
+
readonly TOKEN_REFRESH_FAILED: "Failed to refresh token, authentication required";
|
|
47
|
+
readonly REQUEST_PARSE_ERROR: "Error parsing request";
|
|
48
|
+
readonly OAUTH_STATE_MISMATCH: "OAuth state mismatch - possible CSRF attack";
|
|
49
|
+
readonly MISSING_AUTH_CODE: "Missing authorization code in callback";
|
|
50
|
+
readonly MISSING_TOKEN: "Missing token";
|
|
51
|
+
readonly TOKEN_NOT_FOUND: "Token not found in URL fragment";
|
|
52
|
+
};
|
|
53
|
+
/** Log stages for request logging */
|
|
54
|
+
export declare const LOG_STAGES: {
|
|
55
|
+
readonly BEFORE_TRANSFORM: "before-transform";
|
|
56
|
+
readonly AFTER_TRANSFORM: "after-transform";
|
|
57
|
+
readonly RESPONSE: "response";
|
|
58
|
+
readonly ERROR_RESPONSE: "error-response";
|
|
59
|
+
};
|
|
60
|
+
/** Platform-specific browser opener commands */
|
|
61
|
+
export declare const PLATFORM_OPENERS: {
|
|
62
|
+
readonly darwin: "open";
|
|
63
|
+
readonly win32: "start";
|
|
64
|
+
readonly linux: "xdg-open";
|
|
65
|
+
};
|
|
66
|
+
/** OAuth authorization labels */
|
|
67
|
+
export declare const AUTH_LABELS: {
|
|
68
|
+
readonly OAUTH: "Qwen AI (Google Sign-In)";
|
|
69
|
+
readonly OAUTH_MANUAL: "Qwen AI (Manual Token Paste)";
|
|
70
|
+
readonly API_KEY: "Manually enter API Key";
|
|
71
|
+
readonly INSTRUCTIONS: "A browser window should open. Sign in with Google to authenticate with Qwen.";
|
|
72
|
+
readonly INSTRUCTIONS_MANUAL: "After logging in, copy the token from the URL and paste it here.";
|
|
73
|
+
};
|
|
74
|
+
/** Qwen model definitions */
|
|
75
|
+
export declare const QWEN_MODELS: Record<string, QwenModel>;
|
|
76
|
+
import type { QwenModel } from "./types.js";
|
|
77
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD,yCAAyC;AACzC,eAAO,MAAM,aAAa,6BAA6B,CAAC;AAExD,8DAA8D;AAC9D,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,6CAA6C;AAC7C,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,6EAA6E,CAAC;AAE3G,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,4CAA4C,CAAC;AAC1E,eAAO,MAAM,mBAAmB,+CAA+C,CAAC;AAEhF,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,iDAAiD,CAAC;AAEnF,4CAA4C;AAC5C,eAAO,MAAM,YAAY,wCAAwC,CAAC;AAElE,6BAA6B;AAC7B,eAAO,MAAM,YAAY,yBAAyB,CAAC;AAEnD,wBAAwB;AACxB,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAEX,4BAA4B;AAC5B,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,wBAAwB;AACxB,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,qBAAqB;AACrB,eAAO,MAAM,cAAc;;;;;;;;CAQjB,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,UAAU;;;;;CAKb,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,gBAAgB;;;;CAInB,CAAC;AAEX,iCAAiC;AACjC,eAAO,MAAM,WAAW;;;;;;CAQd,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAiCxC,CAAC;AAGX,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used throughout the Qwen Auth Plugin
|
|
3
|
+
* Centralized for easy maintenance and configuration
|
|
4
|
+
*/
|
|
5
|
+
/** Plugin identifier for logging and error messages */
|
|
6
|
+
export const PLUGIN_NAME = "opencool-qwen-auth";
|
|
7
|
+
/** Base URL for Qwen chat backend API */
|
|
8
|
+
export const QWEN_BASE_URL = "https://chat.qwen.ai/api";
|
|
9
|
+
/** Dummy API key used for Qwen SDK (actual auth via OAuth) */
|
|
10
|
+
export const DUMMY_API_KEY = "qwen-oauth";
|
|
11
|
+
/** Provider ID for opencode configuration */
|
|
12
|
+
export const PROVIDER_ID = "qwen";
|
|
13
|
+
/** OAuth Client ID from Google (extracted from HAR) */
|
|
14
|
+
export const GOOGLE_CLIENT_ID = "452911428355-3lrs59r3icntb0d0e053n98fkg9ha1j3.apps.googleusercontent.com";
|
|
15
|
+
/** Qwen OAuth endpoints (uses Google OAuth) */
|
|
16
|
+
export const QWEN_OAUTH_LOGIN = "https://chat.qwen.ai/oauth/google/login";
|
|
17
|
+
export const QWEN_OAUTH_CALLBACK = "https://chat.qwen.ai/oauth/google/callback";
|
|
18
|
+
/** Google OAuth authorization endpoint */
|
|
19
|
+
export const GOOGLE_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
20
|
+
/** OAuth redirect URI for local callback */
|
|
21
|
+
export const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
22
|
+
/** OAuth scope for Google */
|
|
23
|
+
export const GOOGLE_SCOPE = "openid email profile";
|
|
24
|
+
/** HTTP Status Codes */
|
|
25
|
+
export const HTTP_STATUS = {
|
|
26
|
+
OK: 200,
|
|
27
|
+
UNAUTHORIZED: 401,
|
|
28
|
+
NOT_FOUND: 404,
|
|
29
|
+
TOO_MANY_REQUESTS: 429,
|
|
30
|
+
};
|
|
31
|
+
/** Qwen-specific headers */
|
|
32
|
+
export const QWEN_HEADERS = {
|
|
33
|
+
AUTHORIZATION: "Authorization",
|
|
34
|
+
CONTENT_TYPE: "Content-Type",
|
|
35
|
+
ACCEPT: "Accept",
|
|
36
|
+
};
|
|
37
|
+
/** URL path segments */
|
|
38
|
+
export const URL_PATHS = {
|
|
39
|
+
CHAT_COMPLETIONS: "/v1/chat/completions",
|
|
40
|
+
MODELS: "/models",
|
|
41
|
+
AUTHS: "/v1/auths",
|
|
42
|
+
};
|
|
43
|
+
/** Error messages */
|
|
44
|
+
export const ERROR_MESSAGES = {
|
|
45
|
+
NO_ACCOUNT_ID: "Failed to extract account info from token",
|
|
46
|
+
TOKEN_REFRESH_FAILED: "Failed to refresh token, authentication required",
|
|
47
|
+
REQUEST_PARSE_ERROR: "Error parsing request",
|
|
48
|
+
OAUTH_STATE_MISMATCH: "OAuth state mismatch - possible CSRF attack",
|
|
49
|
+
MISSING_AUTH_CODE: "Missing authorization code in callback",
|
|
50
|
+
MISSING_TOKEN: "Missing token",
|
|
51
|
+
TOKEN_NOT_FOUND: "Token not found in URL fragment",
|
|
52
|
+
};
|
|
53
|
+
/** Log stages for request logging */
|
|
54
|
+
export const LOG_STAGES = {
|
|
55
|
+
BEFORE_TRANSFORM: "before-transform",
|
|
56
|
+
AFTER_TRANSFORM: "after-transform",
|
|
57
|
+
RESPONSE: "response",
|
|
58
|
+
ERROR_RESPONSE: "error-response",
|
|
59
|
+
};
|
|
60
|
+
/** Platform-specific browser opener commands */
|
|
61
|
+
export const PLATFORM_OPENERS = {
|
|
62
|
+
darwin: "open",
|
|
63
|
+
win32: "start",
|
|
64
|
+
linux: "xdg-open",
|
|
65
|
+
};
|
|
66
|
+
/** OAuth authorization labels */
|
|
67
|
+
export const AUTH_LABELS = {
|
|
68
|
+
OAUTH: "Qwen AI (Google Sign-In)",
|
|
69
|
+
OAUTH_MANUAL: "Qwen AI (Manual Token Paste)",
|
|
70
|
+
API_KEY: "Manually enter API Key",
|
|
71
|
+
INSTRUCTIONS: "A browser window should open. Sign in with Google to authenticate with Qwen.",
|
|
72
|
+
INSTRUCTIONS_MANUAL: "After logging in, copy the token from the URL and paste it here.",
|
|
73
|
+
};
|
|
74
|
+
/** Qwen model definitions */
|
|
75
|
+
export const QWEN_MODELS = {
|
|
76
|
+
"qwen3-max": {
|
|
77
|
+
id: "qwen3-max",
|
|
78
|
+
name: "Qwen3 Max",
|
|
79
|
+
description: "Most capable Qwen3 model for complex tasks",
|
|
80
|
+
maxTokens: 32768,
|
|
81
|
+
supportsVision: false,
|
|
82
|
+
supportsCode: true,
|
|
83
|
+
},
|
|
84
|
+
"qwen3-coder-plus": {
|
|
85
|
+
id: "qwen3-coder-plus",
|
|
86
|
+
name: "Qwen3 Coder Plus",
|
|
87
|
+
description: "Optimized for code generation and programming tasks",
|
|
88
|
+
maxTokens: 32768,
|
|
89
|
+
supportsVision: false,
|
|
90
|
+
supportsCode: true,
|
|
91
|
+
},
|
|
92
|
+
"qwen3-vl-plus": {
|
|
93
|
+
id: "qwen3-vl-plus",
|
|
94
|
+
name: "Qwen3 VL Plus",
|
|
95
|
+
description: "Vision language model for image understanding",
|
|
96
|
+
maxTokens: 32768,
|
|
97
|
+
supportsVision: true,
|
|
98
|
+
supportsCode: false,
|
|
99
|
+
},
|
|
100
|
+
"qwen3-235b-a22b": {
|
|
101
|
+
id: "qwen3-235b-a22b",
|
|
102
|
+
name: "Qwen3 235B A22B",
|
|
103
|
+
description: "Large mixture-of-experts model",
|
|
104
|
+
maxTokens: 32768,
|
|
105
|
+
supportsVision: false,
|
|
106
|
+
supportsCode: true,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../lib/constants.ts"],"names":[],"mappings":"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"}
|