Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ dist/
*.log
.DS_Store
package-lock.json
opencode.json
reference/
bunfig.toml
117 changes: 117 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### πŸ”§ Fixes

- **Dynamic User-Agent detection** - User-Agent header now dynamically detects platform and architecture instead of hardcoded Linux/x64
- Supports Linux, macOS, Windows, FreeBSD, OpenBSD, Solaris, AIX
- Supports x64, arm64, ia32, ppc64, arm, mips architectures
- Maintains qwen-code v0.12.0 client version for compatibility
- Fixes authentication on non-Linux systems and ARM devices (M1/M2/M3 Macs, Raspberry Pi, etc.)


## [1.5.0] - 2026-03-14 (Updated)

### 🚨 Critical Fixes

- **Fixed credentials loading on new sessions** - Added explicit snake_case to camelCase conversion in `loadCredentials()` to correctly parse `~/.qwen/oauth_creds.json`
- **Fixed rate limiting issue (#4)** - Added official Qwen Code headers to prevent aggressive rate limiting
- Headers include `X-DashScope-CacheControl`, `X-DashScope-AuthType`, `X-DashScope-UserAgent`
- Requests now recognized as legitimate Qwen Code client
- Full 1,000 requests/day quota now available (OAuth free tier)
- **HTTP 401 handling in device polling** - Added explicit error handling for HTTP 401 during device authorization polling
- Attaches HTTP status code to errors for proper classification
- User-friendly error message: "Device code expired or invalid. Please restart authentication."
- **Token refresh response validation** - Validates access_token presence in refresh response before accepting
- **Refresh token security** - Removed refresh token from console logs to prevent credential leakage

### πŸ”§ Production Hardening

- **Multi-process safety**
- Implemented file locking with atomic `fs.openSync('wx')`
- Added stale lock detection (10s threshold) matching official client
- Registered 5 process exit handlers (exit, SIGINT, SIGTERM, uncaughtException, unhandledRejection)
- Implemented atomic file writes using temp file + rename pattern
- **Token Management**
- Added `TokenManager` with in-memory caching and promise tracking
- Implemented file check throttling (5s interval) to reduce I/O overhead
- Added file watcher for real-time cache invalidation when credentials change externally
- Implemented atomic cache state updates to prevent inconsistent states
- **Error Recovery**
- Added reactive 401 recovery: automatically forces token refresh and retries request
- Implemented comprehensive credentials validation matching official client
- Added timeout wrappers (3s) for file operations to prevent indefinite hangs
- **Performance & Reliability**
- Added request throttling (1s min interval + random jitter) to prevent hitting 60 req/min limits
- Implemented `retryWithBackoff` with exponential backoff and jitter (up to 7 attempts)
- Added support for `Retry-After` header from server
- OAuth requests now use 30s timeout to prevent indefinite hangs

### ✨ New Features

- **Dynamic API endpoint resolution** - Automatic region detection based on `resource_url` in OAuth token
- **Aligned with qwen-code-0.12.1** - Achieved 98% feature parity with official client
- **Enhanced Debug Logging** - Detailed context, timing, and state information (enabled via `OPENCODE_QWEN_DEBUG=1`)
- **Custom error hierarchy** - `QwenAuthError`, `CredentialsClearRequiredError`, `TokenManagerError` with error classification
- **Error classification system** - `classifyError()` helper for programmatic error handling with retry hints

### πŸ§ͺ Testing Infrastructure

- **Comprehensive test suite** - 104 unit tests across 6 test files with 197 assertions
- `errors.test.ts` - Error handling and classification tests (30+ tests)
- `oauth.test.ts` - OAuth device flow and PKCE tests (20+ tests)
- `file-lock.test.ts` - File locking and concurrency tests (20 tests)
- `token-manager.test.ts` - Token caching and refresh tests (10 tests)
- `request-queue.test.ts` - Request throttling tests (15+ tests)
- `auth-integration.test.ts` - End-to-end integration tests (15 tests)
- **Integration tests** - Manual test scripts for race conditions and end-to-end debugging
- **Robust stress tests** - Multi-process concurrency tests with 10 parallel workers
- **Test isolation** - `QWEN_TEST_CREDS_PATH` environment variable prevents tests from modifying user credentials
- **Test configuration** - `bunfig.toml` for test runner configuration
- **Test documentation** - `tests/README.md` with complete testing guide

### πŸ“š Documentation

- User-focused README cleanup (English and Portuguese)
- Updated troubleshooting section with practical recovery steps
- Detailed CHANGELOG for technical history
- Test suite documentation with commands and examples
- Architecture documentation in code comments

---

## [1.4.0] - 2026-02-27

### Added
- Dynamic API endpoint resolution
- DashScope headers support
- `loadCredentials()` and `resolveBaseUrl()` functions

### Fixed
- `ERR_INVALID_URL` error - loader now returns `baseURL` correctly
- "Incorrect API key provided" error for portal.qwen.ai tokens

---

## [1.3.0] - 2026-02-10

### Added
- OAuth Device Flow authentication
- Support for qwen3-coder-plus, qwen3-coder-flash models
- Automatic token refresh
- Compatibility with qwen-code credentials

---

## [1.2.0] - 2026-01-15

### Added
- Initial release
- Basic OAuth authentication
- Model configuration for Qwen providers
169 changes: 60 additions & 109 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,141 +8,119 @@
<img src="assets/screenshot.png" alt="OpenCode with Qwen Code" width="800">
</p>

**Authenticate OpenCode CLI with your qwen.ai account.** This plugin enables you to use Qwen models (Coder, Max, Plus and more) with **2,000 free requests per day** - no API key or credit card required!
**Authenticate OpenCode CLI with your qwen.ai account.** This plugin enables you to use the `coder-model` with **1,000 free requests per day** - no API key or credit card required!

[πŸ‡§πŸ‡· Leia em PortuguΓͺs](./README.pt-BR.md)
[πŸ‡§πŸ‡· Leia em PortuguΓͺs](./README.pt-BR.md) | [πŸ“œ Changelog](./CHANGELOG.md)

## ✨ Features

- πŸ” **OAuth Device Flow** - Secure browser-based authentication (RFC 8628)
- ⚑ **Automatic Polling** - No need to press Enter after authorizing
- πŸ†“ **2,000 req/day free** - Generous free tier with no credit card
- 🧠 **1M context window** - Models with 1 million token context
- πŸ†“ **1,000 req/day free** - Free quota reset daily at midnight UTC
- ⚑ **60 req/min** - Rate limit of 60 requests per minute
- 🧠 **1M context window** - Massive context support for large projects
- πŸ”„ **Auto-refresh** - Tokens renewed automatically before expiration
- ⏱️ **Reliability** - Built-in request throttling and automatic retry for transient errors
- πŸ”— **qwen-code compatible** - Reuses credentials from `~/.qwen/oauth_creds.json`

## πŸ“‹ Prerequisites

- [OpenCode CLI](https://opencode.ai) installed
- A [qwen.ai](https://chat.qwen.ai) account (free to create)

## πŸš€ Installation

### 1. Install the plugin

```bash
cd ~/.opencode && npm install opencode-qwencode-auth
# Using npm
cd ~/.config/opencode && npm install opencode-qwencode-auth

# Using bun (recommended)
cd ~/.config/opencode && bun add opencode-qwencode-auth
```

### 2. Enable the plugin

Edit `~/.opencode/opencode.jsonc`:
Edit `~/.config/opencode/opencode.json`:

```json
{
"plugin": ["opencode-qwencode-auth"]
}
```

## ⚠️ Limits & Quotas

- **Rate Limit:** 60 requests per minute
- **Daily Quota:** 1,000 requests per day (reset at midnight UTC)
- **Web Search:** 200 requests/minute, 1,000/day (separate quota)

> **Note:** These limits are set by the Qwen OAuth API and may change. For professional use with higher quotas, consider using a [DashScope API Key](https://dashscope.aliyun.com).

## πŸ”‘ Usage

### 1. Login

Run the following command to start the OAuth flow:

```bash
opencode auth login
```

### 2. Select Provider

Choose **"Other"** and type `qwen-code`
Choose **"Other"** and type `qwen-code`.

### 3. Authenticate

Select **"Qwen Code (qwen.ai OAuth)"**
Select **"Qwen Code (qwen.ai OAuth)"**.

- A browser window will open for you to authorize
- The plugin automatically detects when you complete authorization
- No need to copy/paste codes or press Enter!

> [!TIP]
> In the OpenCode TUI (graphical interface), the **Qwen Code** provider appears automatically in the provider list.
- A browser window will open for you to authorize.
- The plugin automatically detects when you complete authorization.
- **No need to copy/paste codes or press Enter!**

## 🎯 Available Models

### Coding Models
### Coding Model

| Model | Context | Max Output | Best For |
| Model | Context | Max Output | Features |
|-------|---------|------------|----------|
| `qwen3-coder-plus` | 1M tokens | 64K tokens | Complex coding tasks |
| `qwen3-coder-flash` | 1M tokens | 64K tokens | Fast coding responses |
| `coder-model` | 1M tokens | Up to 64K tokensΒΉ | Official alias (Auto-routes to Qwen 3.5 Plus - Hybrid & Vision) |

### General Purpose Models
> ΒΉ Actual max output may vary depending on the specific model `coder-model` routes to.

| Model | Context | Max Output | Reasoning | Best For |
|-------|---------|------------|-----------|----------|
| `qwen3-max` | 256K tokens | 64K tokens | No | Flagship model, complex reasoning and tool use |
| `qwen-plus-latest` | 128K tokens | 16K tokens | Yes | Balanced quality-speed with thinking mode |
| `qwen3-235b-a22b` | 128K tokens | 32K tokens | Yes | Largest open-weight MoE with thinking mode |
| `qwen-flash` | 1M tokens | 8K tokens | No | Ultra-fast, low-cost simple tasks |
> **Note:** This plugin aligns with the official `qwen-code` client. The `coder-model` alias automatically routes to the best available Qwen 3.5 Plus model with hybrid reasoning and vision capabilities.

### Using a specific model
### Using the model

```bash
opencode --provider qwen-code --model qwen3-coder-plus
opencode --provider qwen-code --model qwen3-max
opencode --provider qwen-code --model qwen-plus-latest
opencode --provider qwen-code --model coder-model
```

## βš™οΈ How It Works

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OpenCode CLI │────▢│ qwen.ai OAuth │────▢│ Qwen Models β”‚
β”‚ │◀────│ (Device Flow) │◀────│ API β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
## πŸ”§ Troubleshooting

1. **Device Flow (RFC 8628)**: Opens your browser to `chat.qwen.ai` for authentication
2. **Automatic Polling**: Detects authorization completion automatically
3. **Token Storage**: Saves credentials to `~/.qwen/oauth_creds.json`
4. **Auto-refresh**: Renews tokens 30 seconds before expiration
### "Invalid access token" or "Token expired"

## πŸ“Š Usage Limits
The plugin usually handles refresh automatically. If you see this error immediately:

| Plan | Rate Limit | Daily Limit |
|------|------------|-------------|
| Free (OAuth) | 60 req/min | 2,000 req/day |
1. **Re-authenticate:** Run `opencode auth login` again.
2. **Clear cache:** Delete the credentials file and login again:
```bash
rm ~/.qwen/oauth_creds.json
opencode auth login
```

> [!NOTE]
> Limits reset at midnight UTC. For higher limits, consider using an API key from [DashScope](https://dashscope.aliyun.com).
### Rate limit exceeded (429 errors)

## πŸ”§ Troubleshooting
If you hit the 60 req/min or 1,000 req/day limits:
- **Rate limit (60/min):** Wait a few minutes before trying again
- **Daily quota (1,000/day):** Wait until midnight UTC for the quota to reset
- **Web Search (200/min, 1,000/day):** Separate quota for web search tool
- Consider using a [DashScope API Key](https://dashscope.aliyun.com) for professional use with higher quotas

### Token expired
### Enable Debug Logs

The plugin automatically renews tokens. If issues persist:
If something isn't working, you can see detailed logs by setting the debug environment variable:

```bash
# Remove old credentials
rm ~/.qwen/oauth_creds.json

# Re-authenticate
opencode auth login
OPENCODE_QWEN_DEBUG=1 opencode
```

### Provider not showing in `auth login`

The `qwen-code` provider is added via plugin. In the `opencode auth login` command:

1. Select **"Other"**
2. Type `qwen-code`

### Rate limit exceeded (429 errors)

- Wait until midnight UTC for quota reset
- Try using `qwen3-coder-flash` for faster, lighter requests
- Consider [DashScope API](https://dashscope.aliyun.com) for higher limits

## πŸ› οΈ Development

```bash
Expand All @@ -153,48 +131,21 @@ cd opencode-qwencode-auth
# Install dependencies
bun install

# Type check
bun run typecheck
# Run tests
bun run tests/debug.ts full
```

### Local testing

Edit `~/.opencode/package.json`:

```json
{
"dependencies": {
"opencode-qwencode-auth": "file:///absolute/path/to/opencode-qwencode-auth"
}
}
```

Then reinstall:

```bash
cd ~/.opencode && npm install
```

## πŸ“ Project Structure
### Project Structure

```
src/
β”œβ”€β”€ constants.ts # OAuth endpoints, models config
β”œβ”€β”€ types.ts # TypeScript interfaces
β”œβ”€β”€ index.ts # Main plugin entry point
β”œβ”€β”€ qwen/
β”‚ └── oauth.ts # OAuth Device Flow + PKCE
└── plugin/
β”œβ”€β”€ auth.ts # Credentials management
└── utils.ts # Helper utilities
β”œβ”€β”€ qwen/ # OAuth implementation
β”œβ”€β”€ plugin/ # Token management & caching
β”œβ”€β”€ utils/ # Retry, locking and logging utilities
β”œβ”€β”€ constants.ts # Models and endpoints
└── index.ts # Plugin entry point
```

## πŸ”— Related Projects

- [qwen-code](https://github.com/QwenLM/qwen-code) - Official Qwen coding CLI
- [OpenCode](https://opencode.ai) - AI-powered CLI for development
- [opencode-gemini-auth](https://github.com/jenslys/opencode-gemini-auth) - Similar plugin for Google Gemini

## πŸ“„ License

MIT
Expand Down
Loading