Skip to content

feat(mobile): 任务菜单显示 Claude、SuperGrok 订阅额度与 ChatGPT credits - #5367

Merged
MagicLizi merged 4 commits into
mainfrom
dash/mobile-subscription-quota
Oct 2, 2026
Merged

MagicLizi merged 4 commits into
mainfrom
dash/mobile-subscription-quota

Conversation

@dashhuang

Copy link
Copy Markdown
Member

这次改了什么

摘要

手机任务菜单的额度卡此前只读 ChatGPT:Claude、SuperGrok 订阅任务一律显示「暂未获取账号配额」,ChatGPT 的 credits 余额也不显示。原因是手机端早于被控端开放 maker:usage:claude-subscription / maker:usage:xai-subscription(#3979 早于 #3789 合入),之后没有接上。

本 PR 让手机端读取被控端已有的只读快照接口,补齐所有订阅家族,并加防漏机制,避免以后新增订阅时再漏掉手机端:

  • Claude 订阅:5 小时、周限额、当前模型的分模型周限额(如 Opus),附套餐名。
  • SuperGrok:本周额度与已购余额;快照过期时只保留套餐名,不显示旧百分比(与桌面同一新鲜度规则)。
  • ChatGPT credits:余额 / 不限 / 已耗尽 / 可用,判断顺序与桌面额度卡一致;Codex 任务与 chatgpt/ 桥接任务(读 web 槽)都显示。
  • 未选供应商的 Claude Code 任务:按被控端 proxy 观察到的计费路由(maker:claude-session-route:get)归属为订阅或 Cindy AI;没有观察值或老被控端时保持不归属,不按登录状态猜测。
  • 共用规则:Claude 分模型窗口匹配与 SuperGrok 新鲜度判定从 desktop shared 移到 @cindy/maker-shared/subscription-usage,桌面原路径改为 re-export,行为不变。
  • 防漏:
    • 订阅家族收敛为 model-providers 的 NATIVE_SUBSCRIPTION_AUTHS(auth.native 类型同源),手机端的读取函数、快照 channel、展示来源、默认账号 id 都以它为键,漏接任何一处即编译失败(已用临时加入的 gemini 验证会报 7 处错误)。
    • 测试守护:被控端 allowlist 中所有 maker:usage:*-subscription channel 必须都被手机端接入;每个订阅来源在五种语言里都有名称。

变更类型

  • feat 新功能
  • fix 缺陷修复
  • refactor / perf 重构或性能优化
  • docs / test / chore 文档、测试或工程维护
  • 其他:

范围

  • 关联 Issue / 需求:手机任务菜单 Anthropic 订阅显示「暂未获取账号配额」
  • 本 PR 包含:手机端订阅额度读取与展示(Claude / SuperGrok / ChatGPT credits)、默认路由 Claude Code 任务归属、共享判定迁到 maker-shared、订阅家族防漏类型与测试
  • 明确不包含:被控端协议改动(三个 channel 均已存在并在 allowlist);chatgpt/ 桥接任务的重置次数展示;桌面端行为改动;feat(mobile): 复用电脑订阅授权并新增额度小组件(iOS优先) #5252 的桌面小组件
  • 用户可见变化:手机任务菜单的额度卡对 Claude / SuperGrok 订阅任务显示真实额度;ChatGPT 任务多一行 Credits
  • 是否存在 breaking change:无

UI 变化

手机任务菜单额度卡新增数据行(窗口行、Credits 行),复用卡片既有的额度行组件与样式,未新增样式或布局。未附截图(见「未执行的验证」)。

  • 引用的设计规范:不涉及新视觉:复用 SessionUsageSummary 既有额度行(label / value / warning 语义 token,Light / Dark 由既有 themed 样式实现);新增文案按 i18n/GLOSSARY.md 的 credits 条目保留第三方原生叫法「Credits」,状态用词对齐桌面 todaySpend.codex.*。

怎么验证的

自动验证

pnpm test:unit:related
结果:apps/desktop、apps/mobile、maker-core、maker-shared、model-providers、orca-workflow、lizi-mcps 全部 PASS(EXIT=0)

pnpm --filter mobile / desktop / maker-shared / model-providers typecheck
结果:均无错误

pnpm check:i18n && pnpm check:i18n-glossary
结果:通过,无新增违规

pnpm check:dco
结果:通过

新增测试覆盖:Claude 三类窗口与过期 / 畸形数据、独立账号按 id 读取、SuperGrok 周额度 / 余额 / 过期快照、桥接模型不错误归属、默认路由三种观察值与老被控端、老被控端缺 channel 时报读取失败、ChatGPT credits 五种状态(含 web 槽)、新家族防漏(每个家族路由到自己的来源、allowlist channel 全覆盖、五语言来源名称)。

手工验证

未在真机 / 模拟器上手工验证。

未执行的验证

  • 手机实机 / 模拟器目检(含 Light / Dark):未执行,额度卡复用既有行样式;需连接有 Claude / SuperGrok 订阅的被控端实测。
  • 整仓 pnpm test:unit:按仓库规则以 test:unit:related 定向验证,完整单测由 CI 兜底。

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:

影响与回滚

  • 影响范围:只读调用被控端已有 channel,无新协议。老被控端返回 CHANNEL_NOT_ALLOWED 时,订阅快照读取按失败处理,卡片保留原有「暂未获取账号配额」;路由读取失败时任务不归属任何订阅。独立账号读取要求回包回显 providerId,否则按旧被控端拒绝,不会显示默认账号的额度。不涉及原生层与指纹,可 OTA。
  • 回滚 / 降级方式:直接 revert 本 PR,手机端回到原有「暂未获取」展示。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s,见 DCO)
  • UI 改动已在「UI 变化」注明引用的设计规范章节(不涉及 UI 则跳过)
  • 未提交凭证、令牌或授权文件
  • 已核对受影响的文档,行为变化涉及的旧结论已同步修订(不涉及则无需修改文档)
  • 已确认测试结果或说明未执行原因

手机任务菜单原先只读 ChatGPT 额度,Claude 与 SuperGrok 订阅一律显示
「暂未获取账号配额」,ChatGPT 的 credits 余额也不显示。

- 复用被控端已有的 maker:usage:claude-subscription / xai-subscription
  只读接口;未选供应商的 Claude Code 任务按被控端观察到的计费路由归属。
- Claude 窗口匹配与 SuperGrok 新鲜度判定移到 maker-shared,桌面与手机共用。
- 订阅家族收敛为 NATIVE_SUBSCRIPTION_AUTHS,手机端各映射以它为键,新增
  家族漏接即编译失败;另有测试守护被控端开放的订阅快照 channel 均已接入。

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@dashhuang
dashhuang requested a review from a team as a code owner October 2, 2026 02:30
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-02T03:17:36.432113Z 8e40aa9 New commits
🔒 Security Review ✅ Completed 2026-10-02T03:17:57.656336Z 8e40aa9 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0a3d51a09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Medium risk] Adds subscription quota display to mobile task menu.

暂不宜合并:正常 Codex 读取路径缺失 Credits,且过期的 SuperGrok 余额会被展示为当前余额。

Findings

  1. P1 Codex Credits 未显示 ▶
  2. P1 过期余额仍被展示 ▶
Fix with agent prompt
### Issue 1
apps/mobile/src/session/readSessionMenuAccountUsage.ts:403
正常读取新版被控端的 `getCodexRateLimits` 时,这里收到的限额快照不含 `credits`,因此 Codex 任务不会显示 Credits;只有回退到旧的 `getAccountUsage` 时才可能显示。被控端在生成正常回包时已去掉该字段,需要让这条正常读取路径也能取得账号 Credits。

### Issue 2
apps/mobile/src/session/readSessionMenuAccountUsage.ts:309-313
当 SuperGrok 快照超过 30 分钟未更新或周窗口已经重置时,周额度会被隐藏,但这里仍展示快照中的已购余额。刷新失败后,手机可能把已经变化的旧余额显示为当前余额;桌面额度卡会同时隐藏这两项。

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary

本 PR 为手机任务菜单接入 Claude、SuperGrok 订阅额度及 ChatGPT Credits,并将跨端共用的快照判定移至 maker-shared。

  • 增加订阅家族映射、远端读取、路由归属和多语言展示。
  • 正常 Codex 额度回包未携带 Credits,且手机端会展示过期的 SuperGrok 已购余额。
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  M[手机任务菜单] --> R{任务额度来源}
  R -->|Codex| C[限额控制面回包]
  R -->|ChatGPT 桥接| W[Web 快照]
  R -->|Claude| A[Claude 订阅快照]
  R -->|SuperGrok| X[SuperGrok 快照]
  C --> P[额度行投影]
  W --> P
  A --> P
  X --> P
Loading

Reviews (1) · Last reviewed commit: "feat(mobile): 任务菜单显示 Claude、SuperGrok 订阅..."

Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
Comment thread packages/maker-shared/src/subscriptionUsage.ts Fixed
- SuperGrok 已购余额与周额度一起按快照新鲜度判断,过期不再显示旧余额。
- ChatGPT credits 同时保留余额与已耗尽状态,与桌面额度卡一致。
- Codex 任务的官方读取不带 credits,改从被控端账号快照读取(桌面额度卡
  同源);读取失败只隐藏该行,不影响额度。
- claudeModelFamily 去后缀改为线性实现,结果与原正则一致(CodeQL)。

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ff9862ca4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
被控端 proxy 只按模型前缀把这类请求送进订阅直连,桌面额度卡也按默认订阅
账号展示;手机端此前判为未确认来源而不显示。明确选择了其他家族账号的任务
仍不归属。

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b85984c99a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mobile/src/session/readSessionMenuAccountUsage.ts Outdated
路由查询只在老被控端 CHANNEL_NOT_ALLOWED 时视为未知,其它失败照常报错;
credits 补读失败也不再静默隐藏。两者都让菜单保留上次的完整额度并标记过期,
不会把已有额度刷成空。

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@MagicLizi MagicLizi added status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) labels Oct 2, 2026

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #5367 独立代码审查报告(auto / standard 档)

  • head: 8e40aa99a5368034bcfaee82e085609f7906fc3f
  • base: bade9ff80335c4125ad8179621ea63595455d853(main)
  • diffHash: a006b5c6ffcbf4c32014e5b39e0d26b92d1c12c4b866c8a91bc83b7f36266aa5
  • reviewEvidence: head/base/baseRefName/diffHash 见上(与 context evidence 一致)

Findings

没有 P0/P1。

(已核对过的非阻断观察,不发作者:bot 已解决 thread 中的两条 P1 意见——「正常 Codex 读取路径缺失 Credits」「过期 SuperGrok 余额被展示为当前余额」——在当前 head 均已落实并有测试覆盖,见 readSessionMenuAccountUsage.test.ts「ChatGPT credits」与 readXaiAccount 的 current 守卫。)

Rule coverage — 读取的规则文件及逐条结论

  • AGENTS.md / docs/dev-rules/development-workflow.md:PR 模板三段齐整、验证段如实(明确写了未执行的实机目检);DCO 4/4 commit 带签名且与 author 一致;无凭证入库。
  • docs/dev-rules/architecture-invariants.md(共享 package 依赖方向):
    1. packages/maker-shared/src/subscriptionUsage.ts 纯函数、零 import,不依赖 render/main ✔;
    2. 无 main 进程动态 import ✔;
      3/4. 不涉及布局树 ✔。desktop shared → @cindy/maker-shared 为既有依赖方向(apps/desktop/package.json 已声明),maker-shared 未反向依赖任何端。
  • docs/dev-rules/mobile-development.md「冷更边界」:本 PR 只改 TS 源码与 workspace package 的 export map,未触碰 app.json / app.config.js / eas.json / apps/mobile/package.json / plugins/ / modules/ 等 fingerprint 输入,不触发冷更,可 OTA ✔(PR 风险段已写明)。
  • docs/dev-rules/remote-and-mobile-adaptation.md(新 IPC channel / 手机入口):
    1. 不读 workdir/agent/会话数据文件,快照读取全走 device-link 到被控端,remoteHostId 会话直接返回 unavailable(有测试)✔;
    2. 三个 channel 在 packages/device-link/src/allowlist.ts 的 REMOTE_INVOKE_ALLOWLIST 早已登记(被控端 #3979/#3789 已上线),本 PR 只把它们登记进移动端契约 MOBILE_REMOTE_INVOKE_CHANNELS,且有防漏测试强制两端清单对齐 ✔;
    3. 手机版入口/UI 即本 PR 本体 ✔。
      PR 风险段以「协议兼容 + 老被控端降级行为」给出了各形态结论(三选一实质已答:不涉及 SSH workdir、channel 已登记、手机 UI 本 PR 交付)。
  • docs/dev-rules/protocol-compatibility.md Review 清单:
    1. 跨端 wire protocol 为加通道的兼容演进:新手机+老被控端 CHANNEL_NOT_ALLOWED → 保留「暂未获取」/不归属(有测试),老手机+新被控端无感,无需协调窗口 ✔;
    2. 不涉及两仓本地协议 package ✔;
    3. 业务代码放在 maker-shared(非协议 package)✔;
    4. 未绕过 packages/device-link 自造协议 ✔。
  • UI(DESIGN.md / design-system):无新样式、无布局变更;额度行复用 SessionUsageSummary 既有行组件与语义 token(label/value/warning),diff 中无硬编码颜色。Light/Dark 由既有 themed 样式覆盖,未实机目检(PR 已如实声明)。UI 证据缺失按非阻断提醒规则处理。
  • i18n 术语(i18n/GLOSSARY.md):Credits 保留第三方原生叫法,符合 credits 条目裁决(第三方原生 credits 走 alsoAllowed);zh 用「剩余/不限/已耗尽/可用」,未触「额度」禁用词。
  • 产品语义:订阅家族收敛为 NATIVE_SUBSCRIPTION_AUTHS(Record 约束漏接即编译失败)+ allowlist channel 全覆盖测试 + 五语言来源名测试,防漏机制真实存在且被验证(PR 声称的「临时加 gemini 报 7 处错」属一次性验证,未复跑)。

共享符号/调用方/错误路径核查

  • claudeSubscriptionUsage.ts / xaiSubscriptionUsage.ts 的类型与 matchScopedWindowForModel / claudeModelFamily / isXaiWeeklyUsageCurrent 迁至 maker-shared 后 desktop 原路径 re-export,desktop 既有消费方(todaySpendChip / QuotaHoverCard / main usage 刷新链)回归测试全绿,行为不变;scopedWindowBelongsToFamily 供 desktop legacy 兜底去重与 matcher 共用一份口径的注释与实现相符。
  • 正则→线性扫描的 stripTrailingBracketSuffix(CodeQL 多项式回溯)对合法 model id 行为等价,附带 20 万 [ 的计时测试;仅在畸形括号尾巴上有极小语义差异(更彻底地剥掉畸形后缀),不影响任何真实 id 形态。
  • 独立账号 scoped 读取的 providerId 回显校验与被控端 dispatch.ts 现状({ ...snapshot, providerId } 回显)一致;不回显按旧被控端拒绝,绝不显示默认账号额度——失败面收敛为「暂未获取」。
  • 错误路径:CHANNEL_NOT_ALLOWED(消息或 code)→ 按旧被控端降级;瞬时错误(NOT_CONNECTED / timeout)→ reject 交给 useSessionMenuUsage 保留上次结果并标 stale(accountFailed 不清 account,仅 PRECONDITION_FAILED 清空)——与最新 fix commit「临时失败保留上次结果」一致,有测试。
  • 默认 cc 任务归属严格跟 maker:claude-session-route:get 的被控端观察值,无观察值/老被控端不归属、不按登录状态猜测;桥接前缀 (chatgpt/、xai/) 不会错归属到其它家族的已选账号(均有测试)。
  • credits 投影顺序(balance → unlimited → depleted → available)与桌面 usageCardModel.buildCodexUsageCard 一致;过期/重置过的窗口一律跳过不臆造额度。

Verification — 实际运行的命令、结果、未执行项及原因

在审查 worktree(head=8e40aa99)内执行,全部退出码 0:

命令 结果
pnpm --filter @cindy/model-providers run typecheck PASS
pnpm --filter @cindy/maker-shared run typecheck PASS
pnpm --filter mobile run typecheck PASS
pnpm --filter desktop run typecheck PASS
pnpm --filter mobile exec vitest run mobileMakerTransport / readSessionMenuAccountUsage / sessionUsagePresentation / useSessionMenuUsage 4 files / 134 tests PASS
pnpm --filter @cindy/maker-shared exec vitest run src/__tests__/subscriptionUsage.test.ts 9 tests PASS
pnpm --filter desktop exec vitest run shared/xaiSubscriptionUsage + main/usage/{claude,xai}SubscriptionUsage{,Refresh} + subscriptionAccountUsage + todaySpendChip + QuotaHoverCard 7 files / 142 tests PASS(迁移行为不变的回归)
pnpm check:i18n PASS(11117 key 五语言一致)
pnpm check:i18n-glossary PASS(无新增违规)
git log DCO trailers 核对 4/4 commit Signed-off-by 与 author 一致

未执行:

  • security-scan.mjs:standard 档不强制(context security 扫描 0 hard / 0 soft 命中、无新增依赖,heavyReasons 为空)。
  • 手机实机 / 模拟器目检(含 Light / Dark):未执行,PR 已声明;复用既有行样式,属非阻断证据缺失。
  • 全量 pnpm test:unit:定向测试覆盖本次改动的全部测试面,完整单测由 CI 兜底(CI 全绿,见 gate.ci)。
  • 「临时加入 gemini 报 7 处编译错」的一次性验证:未复跑(非测试代码,类型约束由 Record 约束真实存在)。

Overall — pass

没有 P0/P1。PR 描述与 diff 完全吻合(feat/fix 主题即手机订阅额度补齐 + 共享判定迁移 + 防漏约束),无夹带私货;无维护者确认门讨论 issue,被解决的 bot thread 意见在当前 head 均已核实落实。结论:通过,进入同轮 guarded Approve + Merge(squash)。

@MagicLizi
MagicLizi merged commit 8426052 into main Oct 2, 2026
18 checks passed
@MagicLizi MagicLizi removed the status:awaiting-bot-review 等外部审查机器人表态(review-pr 自动维护,仅展示) label Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants