feat(cliproxy): add Qoder as a CLIProxy provider channel

Add Qoder AI coding assistant as a supported CLIProxy provider:
- Device code OAuth flow with --qoder-login flag
- Plus-only backend (CLIProxyAPIPlus required)
- No built-in token refresh (unsupported, like Kilo)
- Auth URL: https://qoder.com/device/selectAccounts
- Auth file prefix: qoder-
- Token type: qoder
This commit is contained in:
Simon Shi
2026-05-21 01:35:08 +09:00
parent 774f4a49cf
commit 43c830469a
9 changed files with 28 additions and 1 deletions
+7
View File
@@ -306,6 +306,13 @@ export const OAUTH_CONFIGS: Record<CLIProxyProvider, ProviderOAuthConfig> = {
scopes: [],
authFlag: '--kilo-login',
},
qoder: {
provider: 'qoder',
displayName: 'Qoder',
authUrl: 'https://qoder.com/device/selectAccounts',
scopes: [],
authFlag: '--qoder-login',
},
};
/**
+12
View File
@@ -182,6 +182,18 @@ export const PROVIDER_CAPABILITIES: Record<CLIProxyProvider, ProviderCapabilitie
tokenTypeValues: ['kilo'],
aliases: [],
},
qoder: {
displayName: 'Qoder',
description: 'Qoder AI coding assistant',
oauthFlow: 'device_code',
callbackPort: null,
callbackProviderName: 'qoder',
authUrlProviderName: 'qoder',
refreshOwnership: 'unsupported',
authFilePrefixes: ['qoder-'],
tokenTypeValues: ['qoder'],
aliases: [],
},
};
export const CLIPROXY_PROVIDER_IDS = Object.freeze(
+3 -1
View File
@@ -16,7 +16,8 @@ export type CLIProxyProvider =
| 'cursor'
| 'gitlab'
| 'codebuddy'
| 'kilo';
| 'kilo'
| 'qoder';
/** CLIProxy backend selection */
export type CLIProxyBackend = 'original' | 'plus';
@@ -32,6 +33,7 @@ export const PLUS_ONLY_PROVIDERS: CLIProxyProvider[] = [
'gitlab',
'codebuddy',
'kilo',
'qoder',
];
/** Model mapping for each provider */
+1
View File
@@ -205,6 +205,7 @@ export const BUILTIN_PROVIDER_SHORTCUTS: readonly ShortcutEntry[] = CLIPROXY_PRO
gitlab: 'GitLab Duo via CLIProxy OAuth',
codebuddy: 'CodeBuddy via CLIProxy OAuth',
kilo: 'Kilo AI via CLIProxy OAuth',
qoder: 'Qoder AI via CLIProxy OAuth',
}[name] || 'CLIProxy OAuth provider',
})
);
+1
View File
@@ -16,6 +16,7 @@ export const RESERVED_PROFILE_NAMES = [
'gitlab',
'codebuddy',
'kilo',
'qoder',
// Copilot API (GitHub Copilot proxy)
'copilot',
// Cursor IDE (Cursor proxy daemon)
+1
View File
@@ -97,6 +97,7 @@ describe('ProfileDetector', () => {
expect(detector.detectProfileType('gitlab').provider).toBe('gitlab');
expect(detector.detectProfileType('codebuddy').provider).toBe('codebuddy');
expect(detector.detectProfileType('kilo').provider).toBe('kilo');
expect(detector.detectProfileType('qoder').provider).toBe('qoder');
});
it('should detect settings-based profile from unified config', () => {
@@ -85,6 +85,7 @@ describe('completion backend', () => {
expect(values).toContain('gitlab');
expect(values).toContain('codebuddy');
expect(values).toContain('kilo');
expect(values).toContain('qoder');
expect(values).toContain('localglm');
expect(values).toContain('work');
expect(values).toContain('my-codex');
@@ -61,6 +61,7 @@ describe('help command parity', () => {
expect(rendered.includes('gitlab')).toBe(true);
expect(rendered.includes('codebuddy')).toBe(true);
expect(rendered.includes('kilo')).toBe(true);
expect(rendered.includes('qoder')).toBe(true);
expect(rendered.includes('--gitlab-token-login')).toBe(true);
expect(rendered.includes('--token-login')).toBe(true);
expect(rendered.includes('--gitlab-url <url>')).toBe(true);
@@ -17,6 +17,7 @@ describe('cliproxy-auth-routes start-url guard', () => {
"Provider 'codebuddy' uses Device Code flow"
);
expect(getStartUrlUnsupportedReason('kilo')).toContain("Provider 'kilo' uses Device Code flow");
expect(getStartUrlUnsupportedReason('qoder')).toContain("Provider 'qoder' uses Device Code flow");
});
it('allows Cursor browser URL auth on start-url', () => {