opencode-qwencode-auth 1.0.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.
- package/LICENSE +21 -0
- package/README.md +198 -0
- package/README.pt-BR.md +198 -0
- package/index.ts +3 -0
- package/package.json +50 -0
- package/src/cli.ts +100 -0
- package/src/constants.ts +56 -0
- package/src/index.ts +217 -0
- package/src/plugin/auth.ts +114 -0
- package/src/plugin/client.ts +217 -0
- package/src/plugin/utils.ts +17 -0
- package/src/qwen/oauth.ts +266 -0
- package/src/types.ts +105 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gustavo Dias
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# π€ Qwen Code OAuth Plugin for OpenCode
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
**Authenticate OpenCode CLI with your qwen.ai account.** This plugin enables you to use Qwen3-Coder models with **2,000 free requests per day** - no API key or credit card required!
|
|
7
|
+
|
|
8
|
+
[π§π· Leia em PortuguΓͺs](./README.pt-BR.md)
|
|
9
|
+
|
|
10
|
+
## β¨ Features
|
|
11
|
+
|
|
12
|
+
- π **OAuth Device Flow** - Secure browser-based authentication (RFC 8628)
|
|
13
|
+
- β‘ **Automatic Polling** - No need to press Enter after authorizing
|
|
14
|
+
- π **2,000 req/day free** - Generous free tier with no credit card
|
|
15
|
+
- π§ **1M context window** - Models with 1 million token context
|
|
16
|
+
- π **Auto-refresh** - Tokens renewed automatically before expiration
|
|
17
|
+
- π **qwen-code compatible** - Reuses credentials from `~/.qwen/oauth_creds.json`
|
|
18
|
+
|
|
19
|
+
## π Prerequisites
|
|
20
|
+
|
|
21
|
+
- [OpenCode CLI](https://opencode.ai) installed
|
|
22
|
+
- A [qwen.ai](https://chat.qwen.ai) account (free to create)
|
|
23
|
+
|
|
24
|
+
## π Installation
|
|
25
|
+
|
|
26
|
+
### 1. Add the plugin to OpenCode
|
|
27
|
+
|
|
28
|
+
Edit `~/.opencode/package.json`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"opencode-qwencode-auth": "github:gustavodiasdev/opencode-qwencode-auth"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Edit `~/.opencode/opencode.jsonc`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"plugin": ["opencode-qwencode-auth"]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Install dependencies
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd ~/.opencode && npm install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## π Usage
|
|
53
|
+
|
|
54
|
+
### 1. Login
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
opencode auth login
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Select Provider
|
|
61
|
+
|
|
62
|
+
Choose **"Other"** and type `qwen-code`
|
|
63
|
+
|
|
64
|
+
### 3. Authenticate
|
|
65
|
+
|
|
66
|
+
Select **"Qwen Code (qwen.ai OAuth)"**
|
|
67
|
+
|
|
68
|
+
- A browser window will open for you to authorize
|
|
69
|
+
- The plugin automatically detects when you complete authorization
|
|
70
|
+
- No need to copy/paste codes or press Enter!
|
|
71
|
+
|
|
72
|
+
> [!TIP]
|
|
73
|
+
> In the OpenCode TUI (graphical interface), the **Qwen Code** provider appears automatically in the provider list.
|
|
74
|
+
|
|
75
|
+
## π― Available Models
|
|
76
|
+
|
|
77
|
+
| Model | Context | Max Output | Best For |
|
|
78
|
+
|-------|---------|------------|----------|
|
|
79
|
+
| `qwen3-coder-plus` | 1M tokens | 64K tokens | Complex coding tasks |
|
|
80
|
+
| `qwen3-coder-flash` | 1M tokens | 64K tokens | Fast responses |
|
|
81
|
+
|
|
82
|
+
### Using a specific model
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
opencode --provider qwen-code --model qwen3-coder-plus
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## βοΈ How It Works
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
|
|
92
|
+
β OpenCode CLI ββββββΆβ qwen.ai OAuth ββββββΆβ Qwen3-Coder β
|
|
93
|
+
β βββββββ (Device Flow) βββββββ API β
|
|
94
|
+
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
1. **Device Flow (RFC 8628)**: Opens your browser to `chat.qwen.ai` for authentication
|
|
98
|
+
2. **Automatic Polling**: Detects authorization completion automatically
|
|
99
|
+
3. **Token Storage**: Saves credentials to `~/.qwen/oauth_creds.json`
|
|
100
|
+
4. **Auto-refresh**: Renews tokens 30 seconds before expiration
|
|
101
|
+
|
|
102
|
+
## π Usage Limits
|
|
103
|
+
|
|
104
|
+
| Plan | Rate Limit | Daily Limit |
|
|
105
|
+
|------|------------|-------------|
|
|
106
|
+
| Free (OAuth) | 60 req/min | 2,000 req/day |
|
|
107
|
+
|
|
108
|
+
> [!NOTE]
|
|
109
|
+
> Limits reset at midnight UTC. For higher limits, consider using an API key from [DashScope](https://dashscope.aliyun.com).
|
|
110
|
+
|
|
111
|
+
## π§ Troubleshooting
|
|
112
|
+
|
|
113
|
+
### Token expired
|
|
114
|
+
|
|
115
|
+
The plugin automatically renews tokens. If issues persist:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Remove old credentials
|
|
119
|
+
rm ~/.qwen/oauth_creds.json
|
|
120
|
+
|
|
121
|
+
# Re-authenticate
|
|
122
|
+
opencode auth login
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Provider not showing in `auth login`
|
|
126
|
+
|
|
127
|
+
The `qwen-code` provider is added via plugin. In the `opencode auth login` command:
|
|
128
|
+
|
|
129
|
+
1. Select **"Other"**
|
|
130
|
+
2. Type `qwen-code`
|
|
131
|
+
|
|
132
|
+
### Rate limit exceeded (429 errors)
|
|
133
|
+
|
|
134
|
+
- Wait until midnight UTC for quota reset
|
|
135
|
+
- Try using `qwen3-coder-flash` for faster, lighter requests
|
|
136
|
+
- Consider [DashScope API](https://dashscope.aliyun.com) for higher limits
|
|
137
|
+
|
|
138
|
+
## π οΈ Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Clone the repository
|
|
142
|
+
git clone https://github.com/gustavodiasdev/opencode-qwencode-auth.git
|
|
143
|
+
cd opencode-qwencode-auth
|
|
144
|
+
|
|
145
|
+
# Install dependencies
|
|
146
|
+
bun install
|
|
147
|
+
|
|
148
|
+
# Type check
|
|
149
|
+
bun run typecheck
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Local testing
|
|
153
|
+
|
|
154
|
+
Edit `~/.opencode/package.json`:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"dependencies": {
|
|
159
|
+
"opencode-qwencode-auth": "file:///absolute/path/to/opencode-qwencode-auth"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Then reinstall:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
cd ~/.opencode && npm install
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## π Project Structure
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
src/
|
|
174
|
+
βββ constants.ts # OAuth endpoints, models config
|
|
175
|
+
βββ types.ts # TypeScript interfaces
|
|
176
|
+
βββ index.ts # Main plugin entry point
|
|
177
|
+
βββ qwen/
|
|
178
|
+
β βββ oauth.ts # OAuth Device Flow + PKCE
|
|
179
|
+
βββ plugin/
|
|
180
|
+
βββ auth.ts # Credentials management
|
|
181
|
+
βββ utils.ts # Helper utilities
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## π Related Projects
|
|
185
|
+
|
|
186
|
+
- [qwen-code](https://github.com/QwenLM/qwen-code) - Official Qwen coding CLI
|
|
187
|
+
- [OpenCode](https://opencode.ai) - AI-powered CLI for development
|
|
188
|
+
- [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) - Similar plugin for Google Gemini
|
|
189
|
+
|
|
190
|
+
## π License
|
|
191
|
+
|
|
192
|
+
MIT
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
<p align="center">
|
|
197
|
+
Made with β€οΈ for the OpenCode community
|
|
198
|
+
</p>
|
package/README.pt-BR.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# π€ Qwen Code OAuth Plugin para OpenCode
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
**Autentique o OpenCode CLI com sua conta qwen.ai.** Este plugin permite usar modelos Qwen3-Coder com **2.000 requisiΓ§Γ΅es gratuitas por dia** - sem API key ou cartΓ£o de crΓ©dito!
|
|
7
|
+
|
|
8
|
+
[πΊπΈ Read in English](./README.md)
|
|
9
|
+
|
|
10
|
+
## β¨ Funcionalidades
|
|
11
|
+
|
|
12
|
+
- π **OAuth Device Flow** - AutenticaΓ§Γ£o segura via navegador (RFC 8628)
|
|
13
|
+
- β‘ **Polling AutomΓ‘tico** - NΓ£o precisa pressionar Enter apΓ³s autorizar
|
|
14
|
+
- π **2.000 req/dia grΓ‘tis** - Plano gratuito generoso sem cartΓ£o
|
|
15
|
+
- π§ **1M de contexto** - Modelos com 1 milhΓ£o de tokens de contexto
|
|
16
|
+
- π **Auto-refresh** - Tokens renovados automaticamente antes de expirar
|
|
17
|
+
- π **CompatΓvel com qwen-code** - Reutiliza credenciais de `~/.qwen/oauth_creds.json`
|
|
18
|
+
|
|
19
|
+
## π PrΓ©-requisitos
|
|
20
|
+
|
|
21
|
+
- [OpenCode CLI](https://opencode.ai) instalado
|
|
22
|
+
- Uma conta [qwen.ai](https://chat.qwen.ai) (gratuita)
|
|
23
|
+
|
|
24
|
+
## π InstalaΓ§Γ£o
|
|
25
|
+
|
|
26
|
+
### 1. Adicione o plugin ao OpenCode
|
|
27
|
+
|
|
28
|
+
Edite `~/.opencode/package.json`:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"opencode-qwencode-auth": "github:gustavodiasdev/opencode-qwencode-auth"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Edite `~/.opencode/opencode.jsonc`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"plugin": ["opencode-qwencode-auth"]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Instale as dependΓͺncias
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd ~/.opencode && npm install
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## π Uso
|
|
53
|
+
|
|
54
|
+
### 1. Login
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
opencode auth login
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Selecione o Provider
|
|
61
|
+
|
|
62
|
+
Escolha **"Other"** e digite `qwen-code`
|
|
63
|
+
|
|
64
|
+
### 3. Autentique
|
|
65
|
+
|
|
66
|
+
Selecione **"Qwen Code (qwen.ai OAuth)"**
|
|
67
|
+
|
|
68
|
+
- Uma janela do navegador abrirΓ‘ para vocΓͺ autorizar
|
|
69
|
+
- O plugin detecta automaticamente quando vocΓͺ completa a autorizaΓ§Γ£o
|
|
70
|
+
- NΓ£o precisa copiar/colar cΓ³digos ou pressionar Enter!
|
|
71
|
+
|
|
72
|
+
> [!TIP]
|
|
73
|
+
> No TUI do OpenCode (interface grΓ‘fica), o provider **Qwen Code** aparece automaticamente na lista de providers.
|
|
74
|
+
|
|
75
|
+
## π― Modelos DisponΓveis
|
|
76
|
+
|
|
77
|
+
| Modelo | Contexto | Max Output | Melhor Para |
|
|
78
|
+
|--------|----------|------------|-------------|
|
|
79
|
+
| `qwen3-coder-plus` | 1M tokens | 64K tokens | Tarefas complexas de cΓ³digo |
|
|
80
|
+
| `qwen3-coder-flash` | 1M tokens | 64K tokens | Respostas rΓ‘pidas |
|
|
81
|
+
|
|
82
|
+
### Usando um modelo especΓfico
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
opencode --provider qwen-code --model qwen3-coder-plus
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## βοΈ Como Funciona
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
|
|
92
|
+
β OpenCode CLI ββββββΆβ qwen.ai OAuth ββββββΆβ Qwen3-Coder β
|
|
93
|
+
β βββββββ (Device Flow) βββββββ API β
|
|
94
|
+
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
1. **Device Flow (RFC 8628)**: Abre seu navegador em `chat.qwen.ai` para autenticaΓ§Γ£o
|
|
98
|
+
2. **Polling AutomΓ‘tico**: Detecta a conclusΓ£o da autorizaΓ§Γ£o automaticamente
|
|
99
|
+
3. **Armazenamento de Token**: Salva credenciais em `~/.qwen/oauth_creds.json`
|
|
100
|
+
4. **Auto-refresh**: Renova tokens 30 segundos antes de expirar
|
|
101
|
+
|
|
102
|
+
## π Limites de Uso
|
|
103
|
+
|
|
104
|
+
| Plano | Rate Limit | Limite DiΓ‘rio |
|
|
105
|
+
|-------|------------|---------------|
|
|
106
|
+
| Gratuito (OAuth) | 60 req/min | 2.000 req/dia |
|
|
107
|
+
|
|
108
|
+
> [!NOTE]
|
|
109
|
+
> Os limites resetam Γ meia-noite UTC. Para limites maiores, considere usar uma API key do [DashScope](https://dashscope.aliyun.com).
|
|
110
|
+
|
|
111
|
+
## π§ SoluΓ§Γ£o de Problemas
|
|
112
|
+
|
|
113
|
+
### Token expirado
|
|
114
|
+
|
|
115
|
+
O plugin renova tokens automaticamente. Se houver problemas:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Remova credenciais antigas
|
|
119
|
+
rm ~/.qwen/oauth_creds.json
|
|
120
|
+
|
|
121
|
+
# Re-autentique
|
|
122
|
+
opencode auth login
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Provider nΓ£o aparece no `auth login`
|
|
126
|
+
|
|
127
|
+
O provider `qwen-code` Γ© adicionado via plugin. No comando `opencode auth login`:
|
|
128
|
+
|
|
129
|
+
1. Selecione **"Other"**
|
|
130
|
+
2. Digite `qwen-code`
|
|
131
|
+
|
|
132
|
+
### Rate limit excedido (erros 429)
|
|
133
|
+
|
|
134
|
+
- Aguarde atΓ© meia-noite UTC para reset da cota
|
|
135
|
+
- Tente usar `qwen3-coder-flash` para requisiΓ§Γ΅es mais leves
|
|
136
|
+
- Considere a [API DashScope](https://dashscope.aliyun.com) para limites maiores
|
|
137
|
+
|
|
138
|
+
## π οΈ Desenvolvimento
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Clone o repositΓ³rio
|
|
142
|
+
git clone https://github.com/gustavodiasdev/opencode-qwencode-auth.git
|
|
143
|
+
cd opencode-qwencode-auth
|
|
144
|
+
|
|
145
|
+
# Instale dependΓͺncias
|
|
146
|
+
bun install
|
|
147
|
+
|
|
148
|
+
# Verifique tipos
|
|
149
|
+
bun run typecheck
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Teste local
|
|
153
|
+
|
|
154
|
+
Edite `~/.opencode/package.json`:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"dependencies": {
|
|
159
|
+
"opencode-qwencode-auth": "file:///caminho/absoluto/para/opencode-qwencode-auth"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Depois reinstale:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
cd ~/.opencode && npm install
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## π Estrutura do Projeto
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
src/
|
|
174
|
+
βββ constants.ts # Endpoints OAuth, config de modelos
|
|
175
|
+
βββ types.ts # Interfaces TypeScript
|
|
176
|
+
βββ index.ts # Entry point principal do plugin
|
|
177
|
+
βββ qwen/
|
|
178
|
+
β βββ oauth.ts # OAuth Device Flow + PKCE
|
|
179
|
+
βββ plugin/
|
|
180
|
+
βββ auth.ts # Gerenciamento de credenciais
|
|
181
|
+
βββ utils.ts # UtilitΓ‘rios
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## π Projetos Relacionados
|
|
185
|
+
|
|
186
|
+
- [qwen-code](https://github.com/QwenLM/qwen-code) - CLI oficial do Qwen para programaΓ§Γ£o
|
|
187
|
+
- [OpenCode](https://opencode.ai) - CLI com IA para desenvolvimento
|
|
188
|
+
- [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) - Plugin similar para Google Gemini
|
|
189
|
+
|
|
190
|
+
## π LicenΓ§a
|
|
191
|
+
|
|
192
|
+
MIT
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
<p align="center">
|
|
197
|
+
Feito com β€οΈ para a comunidade OpenCode
|
|
198
|
+
</p>
|
package/index.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-qwencode-auth",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Qwen OAuth authentication plugin for OpenCode - Access Qwen3-Coder models with your qwen.ai account",
|
|
5
|
+
"module": "index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target node --format esm && bun build ./src/cli.ts --outdir ./dist --target node --format esm",
|
|
9
|
+
"dev": "bun run --watch src/index.ts",
|
|
10
|
+
"typecheck": "tsc --noEmit"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"opencode",
|
|
14
|
+
"qwen",
|
|
15
|
+
"qwen-code",
|
|
16
|
+
"qwen3-coder",
|
|
17
|
+
"oauth",
|
|
18
|
+
"authentication",
|
|
19
|
+
"ai",
|
|
20
|
+
"llm",
|
|
21
|
+
"opencode-plugins"
|
|
22
|
+
],
|
|
23
|
+
"author": "Gustavo Dias <me@gustavodias.dev>",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/gustavodiasdev/opencode-qwencode-auth.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/gustavodiasdev/opencode-qwencode-auth#readme",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/gustavodiasdev/opencode-qwencode-auth/issues"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"open": "^10.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@opencode-ai/plugin": "^1.1.48",
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"bun-types": "^1.1.0",
|
|
40
|
+
"typescript": "^5.6.0"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"index.ts",
|
|
44
|
+
"src",
|
|
45
|
+
"README.md"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Qwen Auth CLI Helper
|
|
4
|
+
*
|
|
5
|
+
* This script helps with manual authentication when the automatic
|
|
6
|
+
* OAuth flow doesn't work (e.g., in SSH sessions, containers, etc.)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { createInterface } from 'node:readline';
|
|
13
|
+
|
|
14
|
+
const CREDS_PATH = join(homedir(), '.qwen', 'oauth_creds.json');
|
|
15
|
+
|
|
16
|
+
const rl = createInterface({
|
|
17
|
+
input: process.stdin,
|
|
18
|
+
output: process.stdout,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
function question(prompt: string): Promise<string> {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
rl.question(prompt, resolve);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function main() {
|
|
28
|
+
console.log('\nQwen Auth CLI Helper\n');
|
|
29
|
+
console.log('This tool helps you set up Qwen authentication manually.\n');
|
|
30
|
+
|
|
31
|
+
// Check for existing credentials
|
|
32
|
+
if (existsSync(CREDS_PATH)) {
|
|
33
|
+
const data = JSON.parse(readFileSync(CREDS_PATH, 'utf-8'));
|
|
34
|
+
console.log('Existing credentials found at:', CREDS_PATH);
|
|
35
|
+
|
|
36
|
+
if (data.access_token) {
|
|
37
|
+
console.log('Access token: Present');
|
|
38
|
+
console.log('Email:', data.email || 'Not set');
|
|
39
|
+
console.log('Updated at:', data.updated_at ? new Date(data.updated_at).toISOString() : 'Unknown');
|
|
40
|
+
|
|
41
|
+
const overwrite = await question('\nOverwrite existing credentials? (y/N): ');
|
|
42
|
+
if (overwrite.toLowerCase() !== 'y') {
|
|
43
|
+
console.log('\nKeeping existing credentials. Exiting.');
|
|
44
|
+
rl.close();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log('\nInstructions:');
|
|
51
|
+
console.log('1. Open https://chat.qwen.ai in your browser');
|
|
52
|
+
console.log('2. Sign in with your account');
|
|
53
|
+
console.log('3. Open Developer Tools (F12) -> Network tab');
|
|
54
|
+
console.log('4. Make any chat request');
|
|
55
|
+
console.log('5. Find a request to chat.qwen.ai');
|
|
56
|
+
console.log('6. Copy the "Authorization" header value (starts with "Bearer ...")');
|
|
57
|
+
console.log('');
|
|
58
|
+
|
|
59
|
+
const token = await question('Paste your Bearer token (or just the token without "Bearer "): ');
|
|
60
|
+
|
|
61
|
+
if (!token.trim()) {
|
|
62
|
+
console.log('No token provided. Exiting.');
|
|
63
|
+
rl.close();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Clean up the token
|
|
68
|
+
let accessToken = token.trim();
|
|
69
|
+
if (accessToken.toLowerCase().startsWith('bearer ')) {
|
|
70
|
+
accessToken = accessToken.slice(7);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const email = await question('Email (optional, press Enter to skip): ');
|
|
74
|
+
|
|
75
|
+
// Save credentials
|
|
76
|
+
const dir = join(homedir(), '.qwen');
|
|
77
|
+
if (!existsSync(dir)) {
|
|
78
|
+
mkdirSync(dir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const credentials = {
|
|
82
|
+
access_token: accessToken,
|
|
83
|
+
email: email.trim() || undefined,
|
|
84
|
+
updated_at: Date.now(),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
writeFileSync(CREDS_PATH, JSON.stringify(credentials, null, 2));
|
|
88
|
+
|
|
89
|
+
console.log('\nCredentials saved to:', CREDS_PATH);
|
|
90
|
+
console.log('\nYou can now use OpenCode with Qwen models:');
|
|
91
|
+
console.log(' opencode --model qwen/qwen3-coder-plus');
|
|
92
|
+
|
|
93
|
+
rl.close();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
main().catch((error) => {
|
|
97
|
+
console.error('Error:', error);
|
|
98
|
+
rl.close();
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qwen OAuth and API Constants
|
|
3
|
+
* Based on qwen-code implementation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Provider ID - cria provider separado para OAuth
|
|
7
|
+
export const QWEN_PROVIDER_ID = 'qwen-code';
|
|
8
|
+
|
|
9
|
+
// OAuth Device Flow Endpoints (descobertos do qwen-code)
|
|
10
|
+
export const QWEN_OAUTH_CONFIG = {
|
|
11
|
+
baseUrl: 'https://chat.qwen.ai',
|
|
12
|
+
deviceCodeEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/device/code',
|
|
13
|
+
tokenEndpoint: 'https://chat.qwen.ai/api/v1/oauth2/token',
|
|
14
|
+
clientId: 'f0304373b74a44d2b584a3fb70ca9e56',
|
|
15
|
+
scope: 'openid profile email model.completion',
|
|
16
|
+
grantType: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
// Qwen API Configuration
|
|
20
|
+
// O resource_url das credenciais Γ© usado para determinar a URL base
|
|
21
|
+
export const QWEN_API_CONFIG = {
|
|
22
|
+
// Default base URL (pode ser sobrescrito pelo resource_url das credenciais)
|
|
23
|
+
defaultBaseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
24
|
+
// Portal URL (usado quando resource_url = "portal.qwen.ai")
|
|
25
|
+
portalBaseUrl: 'https://portal.qwen.ai/v1',
|
|
26
|
+
// Endpoint de chat completions
|
|
27
|
+
chatEndpoint: '/chat/completions',
|
|
28
|
+
// Endpoint de models
|
|
29
|
+
modelsEndpoint: '/models',
|
|
30
|
+
// Usado pelo OpenCode para configurar o provider
|
|
31
|
+
baseUrl: 'https://portal.qwen.ai/v1',
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
// OAuth callback port (para futuro Device Flow no plugin)
|
|
35
|
+
export const CALLBACK_PORT = 14561;
|
|
36
|
+
|
|
37
|
+
// Available Qwen models through OAuth
|
|
38
|
+
// Baseado nos modelos disponΓveis no qwen-code
|
|
39
|
+
export const QWEN_MODELS = {
|
|
40
|
+
'qwen3-coder-plus': {
|
|
41
|
+
id: 'qwen3-coder-plus',
|
|
42
|
+
name: 'Qwen3 Coder Plus',
|
|
43
|
+
contextWindow: 1048576, // 1M tokens
|
|
44
|
+
maxOutput: 65536, // 64K tokens
|
|
45
|
+
description: 'Most capable Qwen coding model with 1M context window',
|
|
46
|
+
cost: { input: 0, output: 0 }, // Free via OAuth
|
|
47
|
+
},
|
|
48
|
+
'qwen3-coder-flash': {
|
|
49
|
+
id: 'qwen3-coder-flash',
|
|
50
|
+
name: 'Qwen3 Coder Flash',
|
|
51
|
+
contextWindow: 1048576,
|
|
52
|
+
maxOutput: 65536,
|
|
53
|
+
description: 'Faster Qwen coding model for quick responses',
|
|
54
|
+
cost: { input: 0, output: 0 },
|
|
55
|
+
},
|
|
56
|
+
} as const;
|