114 lines
11 KiB
Markdown
114 lines
11 KiB
Markdown
# RainyToken 二开:功能设计(FEATURE-PLAN)
|
||
|
||
> 状态:已实现 + 多轮独立审计定稿(v1.0 · 2026-09-11)
|
||
> 依据:用户需求 + 实测调研(Sub2API / Trae / WorkBuddy 三家接口均经真实登录态实测,字段与口径已定稿;见 §5)。
|
||
|
||
---
|
||
|
||
## 0. 需求清单(用户原话提炼)
|
||
|
||
1. **新增供应商**:Trae、WorkBuddy(腾讯)、sub2api(自托管)
|
||
2. **DeepSeek 支持充值**:App 内 WebView 打开官方充值页
|
||
3. **首页仅显示已配置的服务**(有凭据就显示)
|
||
4. **新增「API 管理」页**:按供应商集中展示/管理已保存的 API Key(含状态、新增/编辑/删除/测试)
|
||
5. **用量单独一页**:独立的用量统计页(不塞进 API 管理页)
|
||
6. 约束:**任何人**都能用 sub2api(配置各自的实例地址+凭据),不只是本机;全程遵守 taste.md(独立审计→同代理复审→通过才收尾;实测优先;凭据仅实测不落码;不擅自提交推送)。
|
||
|
||
---
|
||
|
||
## 1. 现有扩展点(改前理解结论)
|
||
|
||
| 层 | 文件 | 新增服务需改动 |
|
||
|---|---|---|
|
||
| 服务枚举 | `app/src/main/java/com/rainy/token/domain/service/ServiceType.kt` | 加枚举项(storageKey 稳定) |
|
||
| 服务配置 | `app/src/main/java/com/rainy/token/domain/service/ServiceConfigProvider.kt` | 加 config;`FetchMethod` 视情况扩枚举(如自托管 REST) |
|
||
| 凭据模型 | `app/src/main/java/com/rainy/token/domain/model/Credential.kt` | 密封类加子类 |
|
||
| 凭据指纹 | `data/repository/CredentialRepository.kt`(`cacheIdentityFingerprint` / `credentialFingerprint` 两处 `when`) | 密封类新增子类后**编译器强制**补分支(无 else 的 when) |
|
||
| 刷新用例 | `domain/usecase/RefreshBalanceUseCase.kt`(硬编码 `when(service)` + `Provider<XxxRepository>`) | 加分支 + 注入新仓库 |
|
||
| DI | `di/NetworkModule.kt`(@Provides) | 加 `@Provides` 显式构造(规避 KSP 2.x 跨文件误报) |
|
||
| 凭据表单 | `ui/settings/CredentialEditScreen.kt` + `CredentialEditViewModel.kt` | 为新凭据类型加表单分支 |
|
||
| 详情卡片 | `ui/servicedetail/ServiceDetailScreen.kt`(`when(service)` 分卡) | 加分支或抽象 |
|
||
| 图标 | `ui/components/ServiceIcon.kt` | 加分支 + drawable |
|
||
| 字符串 | `res/values/strings.xml`(en)+ `values-b+zh+Hans` + `values-b+zh+Hant` | 新增 key 三处同步 |
|
||
| 导航 | `ui/RainyTokenNavHost.kt`(Compact 单栈 + Expanded 双窗格两套) | 新页面两处都要接 |
|
||
|
||
---
|
||
|
||
## 2. 功能分期
|
||
|
||
### 阶段 P1(不依赖调研,立即做)
|
||
- **首页仅显示已配置**:`DashboardViewModel.loadFromCache()` / `refresh()` 由 `ServiceType.entries.map` 改为**过滤 `state != NOT_CONFIGURED`**;首页空态给引导文案(空列表 → 提示"请先在设置/API 管理里配置服务"+ 配置入口)。
|
||
- **DeepSeek 充值**:
|
||
- `ServiceConfig` 增加 `externalUrl`(DEEPSEEK = `https://platform.deepseek.com/top_up`)。
|
||
- 新增通用 `WebViewPageScreen`(URL 容器,复用 `WebViewLoginScreen` 的 AndroidView WebView 模式,BackHandler + 进度)。
|
||
- `ServiceDetailScreen` DS 详情加「充值」按钮 → 路由到 WebView 页;API 管理页同款按钮。
|
||
- **API 管理页**:新增 `ui/account/ApiManagementScreen` + ViewModel:列出全部服务(含未配置),各卡片显示图标/名称/状态 chip/Key 掩码/最后验证/操作(编辑→credentialEdit、删除、测试、充值 for DS)。入口:Dashboard 顶栏图标 + 设置页列表项。
|
||
- **用量页(独立)**:新增 `ui/usage/UsageStatScreen`:按配置的服务聚合缓存余额与用量指标(amount/unit/monthlySpent/totalQuota/nextResetAt/extras 摘要),可一键全部刷新;并保留既有用量详情/图表/热力入口作为二级页。入口:Dashboard 顶栏图标。
|
||
|
||
### 阶段 P2(依赖三方调研回报,统一落地)
|
||
- **Trae**(调研已回,2026-09-11):
|
||
- 取数凭据 = **`Cloud-IDE-JWT`**(RS256 JWT,~14 天有效期),请求头 `Authorization: Cloud-IDE-JWT <jwt>`;CN 需 `X-User-Region: CN` + `X-Device-Id` + 插件 UA;缺 device 绑定会触发 1001/9074 风控。
|
||
- 用户获取方式:浏览器登录 Trae 后从 DevTools Network / 授权回调链接复制 JWT(走 traework2api 同款 `/authorization` 回调粘贴流程)。
|
||
- 核心端点:
|
||
- CN 积分池:`POST https://api.trae.cn/trae/api/v2/pay/ide_user_ent_usage`(`user_entitlement_pack_list[].entitlement_base_info.quota.credits_limit − usage.credits_amount`)
|
||
- CN 套餐状态:`POST https://api.trae.cn/trae/api/v1/pay/ide_user_pay_status`
|
||
- 兑换 token:`POST https://api.trae.com.cn/cloudide/api/v3/trae/oauth/ExchangeToken`
|
||
- Intl:`https://grow-normal.trae.ai/trae/api/v1/pay/ide_user_ent_usage` 等(v1)
|
||
- 参考实现:Sliverkiss/traework2api · mmqz/cpa-multi-plugins · diegosouzapw/OmniRoute(trae.ts)
|
||
- 凭据模型:`Credential.TraeCredential(jwt, region)`(简化为单字段 JWT + 地区优化显示)。
|
||
- **WorkBuddy(腾讯)**(调研已回,2026-09-11):
|
||
- 产品=腾讯 AI 办公 Agent(`workbuddy.qq.com` → 301 → `www.codebuddy.cn/work/`),与 CodeBuddy 共用积分(Credits)体系;无公开 API。
|
||
- 取数 = **OAuth Bearer token 流程**(非 cookie):设备授权 `POST https://copilot.tencent.com/v2/plugin/auth/state?platform=CLI` → 微信/QQ 扫码 → `GET .../v2/plugin/auth/token?state=` 拿 `accessToken/refreshToken` → 保活刷新 `POST .../v2/plugin/auth/token/refresh`(头 `X-Refresh-Token`)。
|
||
- 余额接口:`POST https://www.codebuddy.cn/v2/billing/meter/get-user-resource`,`Authorization: Bearer <accessToken>`,体含 `"ProductCode":"p_tcaca"`,响应 `Accounts[].CycleCapacityRemain/Used/Size` 累加得可用/已用/总额。
|
||
- 凭据模型:复用 **Codex 的 OAuth 模式**(`accessToken/refreshToken`),新增 `Credential.WorkBuddyCredential`(含 refresh)。细节待真实账号实测回填。
|
||
- 参考实现:Sliverkiss/workbuddy2api · mmqz/cpa-multi-plugins(billing.go)。
|
||
- **Sub2API(自托管,任人可用)**(调研已回,2026-09-11,源码实读:`research-sub2api`,HEAD cdb5cfaf):
|
||
- 各上游订阅 = 后台「账号(Accounts)」,管理 API 全部在 `{实例}/api/v1/admin/*`,与对外 OpenAI 网关分离。
|
||
- 认证:`POST {base}/api/v1/auth/login`(`{"email","password"}`;可被 TOTP-2FA / 验证码 / backend-mode 拦;返 `access_token/refresh_token`);或 `x-api-key: <admin-api-key>`(免登录)。新版有**合规 423 闸门**:未 accept 时 `/admin/*` 全 423,需先 `POST /api/v1/admin/compliance/accept`。
|
||
- 查询序列(最小):`GET /admin/accounts`(列表/详情)→ `POST /admin/accounts/usage/batch`(`source=passive`,不打上游、带缓存,适合 App 轮询)→ 按平台打 `openai|grok|cn-providers/.../quota|balance`(实时余额)。
|
||
- 字段以 optional 防御式解析(项目近每日发版、响应字段多变)。
|
||
- 凭据模型:`Credential.Sub2ApiCredential(baseUrl, email, password, apiKey?)`;`ServiceConfig` 需支持自定义 baseUrl(`FetchMethod.SELF_HOSTED_REST`)。
|
||
- 新服务的**表单/测试/详情卡/图标/字符串**全链路补齐;三者的取数接口都用**真实凭据实测**后再定稿字段映射。
|
||
|
||
---
|
||
|
||
## 3. 关键设计决策
|
||
1. **“有凭据就显示”**:以 `CredentialStatus.State != NOT_CONFIGURED` 为准(任一凭据存在即算配置),不要求最近验证成功(用户已选)。
|
||
2. **充值交互**:App 内 WebView(用户已选);WebView 内完成登录+充值,返回键退出页面。
|
||
3. **用量页判据**:展示已配置服务的缓存用量(无网也可见);未配置服务不展示。
|
||
4. **API 管理与用量分离**:API 页只管 Key/凭据;用量单独一页(用户已选)。
|
||
5. **凭据安全**:任何新凭据只进 SecureStorage,指纹化展示;新子类强制补 `CredentialRepository` 指纹分支。
|
||
6. **实测优先**:新供应商接口以调研/实测回报为准回填,不臆造字段。
|
||
|
||
---
|
||
|
||
## 4. 测试与审计计划
|
||
- P1 每完成一块:`.\gradlew.bat :app:assembleDebug`(CI=true)编译验证。
|
||
- 代码修改后用**独立 subagent** 审计(无阻断 + 无 UX 问题),修复后**同 subagent 复审**,通过才收尾(taste.md 强制)。
|
||
- 不开 Commit/Push(user 未授权)。
|
||
- 新供应商接口回填后,用真实凭据实测(仅验证,不落码)。
|
||
|
||
## 5. 实施状态(2026 goal round 4)
|
||
- ✅ P1a 首页仅显示已配置(含空态引导)——独立审计 + 同代理复审通过
|
||
- ✅ P1b DeepSeek 充值(App 内 WebView)——审计修复 + 复审通过
|
||
- ✅ P1c API 管理页(集中管理/测试/删除/DS 充值入口)——[A] 修复确认 + 复审通过
|
||
- ✅ P1d 用量统计页(独立页面,含失败计数/防闪/extras 过滤三修)——随 P2 审计确认生效
|
||
- ✅ P2 数据/领域层:TraeRepository / WorkBuddyRepository / Sub2ApiRepository + 凭据子类
|
||
+ 指纹双 when + ServiceType/Config(FetchMethod.SELF_HOSTED_REST)/RefreshBalanceUseCase/NetworkModule
|
||
—— 独立审计**无阻断**;F1–F4 已修(缓存身份稳定化 / 负数钳制+数值放宽 / 423 透传 / Sub2Api 掩码改实例基址),F1–F4 复审通过
|
||
- ✅ P2 专用凭据表单(Trae JWT+区域 / WorkBuddy tokens / Sub2API 实例+认证二选一)三语
|
||
- ✅ Sub2API 实测(xxcsn.site,goal round 4):确认【普通用户用 sk- API Key + GET /v1/usage】即可查余额/用量(无需管理员)。
|
||
仓库从 admin 方向重写为**用户级**(Bearer sk- → /v1/usage,404 兜底 /api/v1/usage;remaining/balance/unit/isValid/usage.total.cost/model_stats/daily_usage 实测校准;login email/password 备选);
|
||
**独立审计通过(无阻断)+ 同代理复审通过**;3 条建议已落实(desc 用户级文案/acceptCompliance KDoc/清导入)
|
||
- ✅ 全量最终审计(55682c88):**无[阻断]、可收尾**;建议1(delete 清理表单字段)已修并复审通过;建议2(test 双击竞态)评估不改;提示项(gradle 本地开关/AGP 补丁、充值 WebView 无会话持久化)已记录。
|
||
- ✅ Trae / WorkBuddy 实测校准(goal round 5,经用户授权用 logged-in 浏览器调官方接口,全程不落凭据):
|
||
- Trae:POST api.trae.cn/trae/api/v2/pay/ide_user_ent_usage 仅 Authorization:Cloud-IDE-JWT(+Content-Type) 即 200;
|
||
权威口径 usage_summary.total_amount-consumed_amount;pack 用 display_desc/credits_limit(-1=∞)/usage.credits_amount;
|
||
→ TraeRepository 重写(去 X-Device-Id/Region 头、usage_summary 优先、包级兜底)
|
||
- WorkBuddy:POST www.workbuddy.cn/billing/meter/get-user-resource-summary → data.Packages[](Cycle{Total,Remain,Used,Frozen}Capacity+CapacityUnit);
|
||
→ WorkBuddyRepository 重写(主端点 workbuddy.cn + codebuddy.cn 兜底、refresh 轮换保留)
|
||
- ✅ 两仓库实测校准独立审计(924f04e0):**通过(无阻断)**;5 项建议落实(unit 定案 Credits 且生效化/空体 EMPTY_BODY/无数据 ParseError/清未用 import/语义保留)+ 同代理复审通过;微观察②(单包明细单位)修复后再次确认通过 —— **Trae 与 WorkBuddy 实测校准正式定稿**
|
||
- ✅ **收尾(goal round 5)**:三家新供应商(Sub2API/Trae/WorkBuddy)全部实测校准+审计+复审定稿;
|
||
原始二开目标 ①-④ 全部达成且审计闭环;`assembleDebug`/`assembleRelease` 均绿;
|
||
**未提交未推送**(用户授权前保持工作区本地状态)
|