Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ See [Choosing A CPA Panel](https://seakee.github.io/CPA-Manager-Plus/docs/en/gui

### CPA Gateway Management

- Manage CPA provider configurations, including Gemini, Codex, Claude, Vertex, xAI, and OpenAI-compatible providers.
- Manage CPA provider configurations, including Gemini, Codex, Claude, Vertex, xAI, Devin, and OpenAI-compatible providers.
- Maintain auth files, OAuth logins, API keys, model aliases, priorities, plugins, logs, and system settings.
- Import official Sub2API OpenAI OAuth exports and split multiple accounts into separate CPA Codex auth files.

Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ CPA / CLIProxyAPI 可以在 `:8317` 直接托管官方 Management Center,也

### CPA 网关管理

- 管理 CPA Provider 配置,包括 Gemini、Codex、Claude、Vertex、xAI 和 OpenAI-compatible Provider。
- 管理 CPA Provider 配置,包括 Gemini、Codex、Claude、Vertex、xAI、Devin 和 OpenAI-compatible Provider。
- 维护认证文件、OAuth 登录、API Key、模型别名、优先级、插件、日志和系统配置。
- 导入官方 Sub2API OpenAI OAuth 导出,并把多账号拆分为独立的 CPA Codex 认证文件。

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/en/manual/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Open the unified [Accounts Demo](https://seakee.github.io/CPA-Manager-Plus/#/dem

## What To Check First

- **Credential and provider**: confirm whether the account belongs to Codex, Claude, Vertex, Antigravity, Kimi, xAI, or another source.
- **Credential and provider**: confirm whether the account belongs to Codex, Claude, Vertex, Antigravity, Kimi, xAI, Devin, or another source.
- **`auth_index`**: the stable account index used to connect usage, quota, inspection, and account actions.
- **Enabled state**: automated recovery does not override manually disabled accounts.
- **Note, priority, and project ID**: use them to separate account purpose and routing preference.
Expand Down
1 change: 1 addition & 0 deletions apps/docs/en/manual/oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The page shows login methods based on CPA and plugin capabilities. Common entrie
- Antigravity OAuth
- Kimi OAuth
- xAI OAuth
- Devin OAuth
- iFlow OAuth
- Plugin-provided OAuth
- Vertex credential import
Expand Down
1 change: 1 addition & 0 deletions apps/docs/en/reference/capability-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Docker and native packages provide the same Full Mode capabilities; only the ins
| xAI/Grok OAuth | Provider/Auth File/OAuth | CLI billing, paid OAuth identity fallback, and request-event evidence | Local and server |
| xAI API Key | `xai-api-key`, priority, models, and key testing | Request results and provider responses | Provider key test |
| Gemini / Vertex / Antigravity / Kimi | Provider, auth file, or OAuth depending on CPA | Provider-specific quota or recent request evidence | Depends on CPA and provider APIs |
| Devin | Provider, Auth File, OAuth, `devin.sensitive-words` | Daily/weekly quota percentages, exact reset, Devin plan metadata | Quota read without model requests |
| OpenAI-compatible | Base URL, API key, headers, model mapping, and key testing | Request status, latency, redacted failures, and cost | No assumed common quota API |

## Data And Automation Boundaries
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/manual/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ description: 在统一 Accounts 工作区管理 CPA 凭证、账号健康、配

## 先看哪些信息

- **凭证和 Provider**:确认账号属于 Codex、Claude、Vertex、Antigravity、Kimi、xAI 或其他来源。
- **凭证和 Provider**:确认账号属于 Codex、Claude、Vertex、Antigravity、Kimi、xAI、Devin 或其他来源。
- **`auth_index`**:账号的稳定索引。用量、配额、巡检和账号处理都依赖它做关联。
- **启用状态**:手动禁用的账号不会被自动恢复流程覆盖。
- **备注、优先级和项目 ID**:用于区分账号用途和路由偏好。
Expand Down
1 change: 1 addition & 0 deletions apps/docs/manual/oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ OAuth 登录页面用于添加或重新授权账号。它解决的是“如何
- Antigravity OAuth
- Kimi OAuth
- xAI OAuth
- Devin OAuth
- iFlow OAuth
- 插件提供的 OAuth
- Vertex 凭证导入
Expand Down
1 change: 1 addition & 0 deletions apps/docs/reference/capability-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Docker 和原生包提供相同的完整模式能力,只是安装方式不同
| xAI/Grok OAuth | Provider/Auth File/OAuth | CLI billing、付费 OAuth identity fallback、请求事件证据 | 本地与服务端 |
| xAI API Key | `xai-api-key` 配置、优先级、模型和密钥测试 | 请求结果与 Provider 返回信息 | Provider key test |
| Gemini / Vertex / Antigravity / Kimi | Provider、Auth File 或 OAuth(按 CPA 能力) | Provider 特定 quota 或最近请求证据 | 取决于 CPA 与 Provider 接口 |
| Devin | Provider、Auth File、OAuth、`devin.sensitive-words` | 日/周额度百分比、精确 reset、Devin 计划名称与起止时间 | 配额读取,不执行模型请求 |
| OpenAI-compatible | Base URL、API Key、Header、模型映射和密钥测试 | 请求状态、延迟、失败摘要和成本 | 不假设存在统一 quota API |

## 数据与自动化边界
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/assets/icons/devin-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/web/src/assets/icons/devin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions apps/web/src/components/config/VisualConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
PayloadFilterRulesEditor,
PayloadRulesEditor,
PluginStoreAuthEditor,
StringListEditor,
} from './VisualConfigEditorBlocks';
import type { ApiKeyMutation } from './ApiKeysCardEditor';
import styles from './VisualConfigEditor.module.scss';
Expand Down Expand Up @@ -954,6 +955,34 @@ export function VisualConfigEditor({
error={redisUsageQueueRetentionError}
/>
</SectionGrid>

<SectionSubsection
title={t('config_management.visual.sections.system.devin_title')}
description={t(
'config_management.visual.sections.system.devin_sensitive_words_desc'
)}
>
<FieldShell
label={t(
'config_management.visual.sections.system.devin_sensitive_words_label'
)}
hint={t(
'config_management.visual.sections.system.devin_sensitive_words_hint'
)}
>
<StringListEditor
value={values.devinSensitiveWords}
disabled={disabled}
placeholder={t(
'config_management.visual.sections.system.devin_sensitive_words_placeholder'
)}
inputAriaLabel={t(
'config_management.visual.sections.system.devin_sensitive_words_label'
)}
onChange={(devinSensitiveWords) => onChange({ devinSensitiveWords })}
/>
</FieldShell>
</SectionSubsection>
</SectionStack>
</ConfigSection>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ function buildProtocolOptions(
return options;
}

const StringListEditor = memo(function StringListEditor({
export const StringListEditor = memo(function StringListEditor({
value,
disabled,
placeholder,
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/quota/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
CLAUDE_CONFIG,
CODEX_CONFIG,
CODEX_SUMMARY_CONFIG,
DEVIN_CONFIG,
KIMI_CONFIG,
XAI_CONFIG,
buildObservedCodexQuotaState,
Expand Down
63 changes: 62 additions & 1 deletion apps/web/src/components/quota/quotaConfigs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
buildQuotaFailureState,
CLAUDE_CONFIG,
CODEX_CONFIG,
DEVIN_CONFIG,
getCodexQuotaStoreKey,
KIMI_CONFIG,
getSortedCodexResetCreditExpiries,
Expand Down Expand Up @@ -47,7 +48,14 @@ describe('getCodexQuotaStoreKey', () => {
provider: 'claude',
authIndex: 'auth-1',
};
const configs = [CLAUDE_CONFIG, ANTIGRAVITY_CONFIG, CODEX_CONFIG, KIMI_CONFIG, XAI_CONFIG];
const configs = [
CLAUDE_CONFIG,
ANTIGRAVITY_CONFIG,
CODEX_CONFIG,
DEVIN_CONFIG,
KIMI_CONFIG,
XAI_CONFIG,
];

configs.forEach((config) => {
expect(config.getStoreKey?.(file)).toBe('shared.json::auth-1');
Expand Down Expand Up @@ -1486,3 +1494,56 @@ describe('Codex plan precedence', () => {
]);
});
});

describe('DEVIN_CONFIG', () => {
it('correctly builds loading, success, and error states', () => {
const file = { name: 'devin.json', type: 'devin', authIndex: 'd-1' };

const loading = DEVIN_CONFIG.buildLoadingState(file);
expect(loading).toMatchObject({
status: 'loading',
windows: [],
observedAtMs: null,
plan: null,
planStartMs: null,
planEndMs: null,
authFileKey: 'devin.json::d-1',
});

const success = DEVIN_CONFIG.buildSuccessState(
{
windows: [
{ id: 'daily', remainingPercent: 50, resetAtMs: 1726000000000, periodHours: 24 },
{ id: 'weekly', remainingPercent: 80, resetAtMs: 1726500000000, periodHours: 168 },
],
observedAtMs: 1726000000100,
plan: 'Team',
planStartMs: 1725000000000,
planEndMs: 1727000000000,
},
file
);
expect(success).toMatchObject({
status: 'success',
plan: 'Team',
planStartMs: 1725000000000,
planEndMs: 1727000000000,
windows: [
{ id: 'daily', remainingPercent: 50 },
{ id: 'weekly', remainingPercent: 80 },
],
fetchedAtMs: 1726000000100,
authFileKey: 'devin.json::d-1',
});

const error = DEVIN_CONFIG.buildErrorState('quota failed', 429, file);
expect(error).toMatchObject({
status: 'error',
windows: [],
error: 'quota failed',
errorStatus: 429,
authFileKey: 'devin.json::d-1',
});
});
});

45 changes: 44 additions & 1 deletion apps/web/src/components/quota/quotaConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import type {
CodexQuotaWindow,
CodexRateLimitResetCredit,
CredentialScopedQuotaState,
DevinQuotaData,
DevinQuotaState,
KimiQuotaState,
XaiBillingSummary,
XaiQuotaState,
Expand All @@ -25,6 +27,7 @@ import {
fetchClaudeQuota,
fetchCodexQuota,
fetchCodexQuotaSummary,
fetchDevinQuota,
fetchKimiQuota,
fetchXaiQuota,
filterFreshCodexQuotaWindows,
Expand Down Expand Up @@ -52,7 +55,7 @@ import {
scopeQuotaStateToCredential,
} from '@/utils/quota/credentialScope';

type QuotaType = 'antigravity' | 'claude' | 'codex' | 'kimi' | 'xai';
type QuotaType = 'antigravity' | 'claude' | 'codex' | 'kimi' | 'xai' | 'devin';

export interface QuotaConfig<TState, TData> {
type: QuotaType;
Expand Down Expand Up @@ -771,3 +774,43 @@ export const XAI_CONFIG: QuotaConfig<XaiQuotaState, XaiBillingSummary> = {
}),
scopeState: scopeCredentialQuotaState,
};

export const DEVIN_CONFIG: QuotaConfig<DevinQuotaState, DevinQuotaData> = {
type: 'devin',
i18nPrefix: 'devin_quota',
fetchQuota: fetchDevinQuota,
getStoreKey: getQuotaCredentialStoreKey,
buildLoadingState: (file) => ({
status: 'loading',
windows: [],
observedAtMs: null,
plan: null,
planStartMs: null,
planEndMs: null,
...buildQuotaCredentialIdentity(file),
}),
buildSuccessState: (data, file) => ({
status: 'success',
windows: data.windows,
observedAtMs: data.observedAtMs,
plan: data.plan,
planStartMs: data.planStartMs,
planEndMs: data.planEndMs,
...buildQuotaCredentialIdentity(file),
fetchedAtMs: data.observedAtMs ?? Date.now(),
}),
buildErrorState: (message, status, file) => ({
status: 'error',
windows: [],
observedAtMs: null,
plan: null,
planStartMs: null,
planEndMs: null,
error: message,
errorStatus: status,
...buildQuotaCredentialIdentity(file),
failedAtMs: Date.now(),
}),
scopeState: scopeCredentialQuotaState,
};

Loading
Loading