26 KiB
OpenAI 手机号接码 MaDao 统一接入与侧边栏样式重构开发方案
1. 文档定位
本文用于指导后续重新实现 PR #288 相关能力,并同时收敛侧边栏里文本框、按钮、接码 provider 显隐和无用保存按钮问题。目标不是照搬 PR,而是在现有项目真实结构上重新设计一次,保证 OpenAI 手机号注册、后置手机号验证、provider 接码生命周期、设置持久化和侧边栏 UI 一致落地。
本文只是一份开发方案,不直接修改功能代码。后续实现时应按本文的阶段清单逐段开发、逐段自检,发现现有代码与本文冲突时,先修正方案或明确取舍,再改代码。
2. 分析基线
已确认的当前工程基线:
- 当前扩展是 Chrome MV3,
manifest.json的后台入口是background.js,侧边栏入口是sidepanel/sidepanel.html。 - OpenAI flow 定义在
flows/openai/index.js和flows/openai/workflow.js,并声明supportsPhoneSignup: true、supportsPhoneVerificationSettings: true。 - Kiro/Grok 当前不支持手机号注册和接码设置,
flows/kiro/index.js、flows/grok/index.js均为supportsPhoneSignup: false、supportsPhoneVerificationSettings: false。 - 手机接码目前在架构上仍是 OpenAI 私有能力。
docs/多注册流程架构边界.md明确指出 HeroSMS / 5sim / NexSMS、取号、复用、轮询、换号、释放、手机号注册和后置 add-phone 暂不进入 core 通用服务。 - 当前 provider 注册表是
phone-sms/providers/registry.js,已有hero-sms、5sim、nexsms。 - 当前接码主编排是
background/phone-verification-flow.js,实际运行还要同步考虑background.js内联后的运行入口。 - 当前侧边栏已有统一表单布局基础:
--data-label-width: 76px、--data-field-height: 34px、.data-inline作为右侧弹性控制区、.btn和.data-input/.data-select共用高度。 tests/sidepanel-form-layout.test.js已保护“每个.data-row只有 label + 一个控制区”“按钮/输入框高度统一”“不再出现icon-action-btn”等约束。
PR #288 的已知结论:
- PR 标题为“接入 MaDao 统一接码并收敛 provider 换号链路”。
- PR 增加了
phone-sms/providers/madao.js,并在 provider registry 中注册 MaDao。 - PR 的 MaDao 适配层包含
acquireActivation、pollActivation、releaseActivation、rotateActivation、replaceRoutingActivation,核心 API 为/api/acquire、/api/poll、/api/release、/api/routing/replace。 - PR 中值得保留的是 MaDao provider 模块边界、
routing_plan/direct两种模式、路由换号/api/routing/replace的行为。 - PR 中不应照搬的是主流程里 MaDao 特例函数、sidepanel 里散落的 MaDao 专用行和 GitHub 图标按钮,以及任何绕过 provider adapter 契约的判断。
3. 需求与硬边界
必须满足的需求:
- 重新实现 MaDao 接码接入,不直接复制 PR #288 的堆叠式 UI 和主流程特例。
- 不留旧的无用代码。被新 provider 契约、统一 UI descriptor、自动保存机制取代的分支、按钮、样式和测试夹具都要清理干净。
- 文本框与按钮高度、边框、宽度体系统一;按钮不需要图标。
- 表单布局采用“固定 label 宽度 + 右侧控制区占剩余宽度 + 可选按钮固定最小宽度”的模型,而不是固定文本框宽度。
- 即使某些文本框右侧新增按钮,也不能挤乱同一组布局;输入框应继续占剩余宽度。
- 项目地址必须正确:CPA 为
https://github.com/router-for-me/CLIProxyAPI,sub2api 为https://github.com/Wei-Shaw/sub2api。 - GitHub 按钮使用普通文字按钮并纳入统一按钮样式,不做图标按钮。
- 自动保存已经存在时,纯“保存设置”按钮应删除;但查询价格、查余额、刷新列表、清空、记录运行时号码等有明确动作语义的按钮可以保留。
- OpenAI 手机号注册模式必须和后置 add-phone 区分,不能混用状态字段。
不能突破的边界:
- MaDao 只接入 OpenAI 手机接码能力,不把接码提升为 core 通用服务。
- Kiro/Grok 不显示 OpenAI 接码、Plus、平台绑定相关配置。
- 主流程不得写 MaDao 专用大分支;新增能力应通过 provider registry 和 provider adapter 暴露。
- 不能因为接入 MaDao 破坏现有 HeroSMS、5sim、NexSMS 行为和存量配置。
- 不能只修改
background/phone-verification-flow.js而忘记实际加载的background.js,也不能只改background.js导致模块测试失真。
4. 当前真实实现现状
4.1 OpenAI 手机号注册模式
OpenAI flow 当前不是单一注册路径,而是多个 variant:
normal:邮箱注册 -> 邮箱验证码 -> 登录验证码 -> 后置手机号验证 -> OAuth -> 平台回调。normalPhone:手机号注册 -> 手机验证码 -> 登录验证码 -> 绑定邮箱 -> 绑定邮箱验证码 -> OAuth -> 平台回调。normalPhoneRelogin:手机号注册并绑定邮箱后,切入绑定邮箱重登链路。
因此“手机号注册”和“后置手机号验证”虽然都依赖接码 provider,但状态槽位不同:
- 手机号注册使用
signupPhoneNumber、signupPhoneActivation、signupPhoneCompletedActivation。 - 后置 add-phone 使用
currentPhoneActivation。
后续 MaDao 接入必须同时覆盖这两条链路,并在日志、换号、释放、成功完成时保持状态字段不串线。
4.2 provider 当前模型
当前 provider 顺序为 hero-sms、5sim、nexsms。DEFAULT_PHONE_SMS_PROVIDER_ORDER 和相关 normalize 函数会按 provider 数量截断,所以接入 MaDao 时必须同步扩展 provider 常量、顺序、registry、测试 fixture,否则 UI 选中了 MaDao 也可能被 normalize 回退或截断。
当前 background/phone-verification-flow.js 仍有较多 provider 内联逻辑。后续应把 MaDao 做成 adapter,并逐步收敛公共生命周期:
- acquire:取号。
- poll:轮询短信。
- release:cancel / ban / finish。
- rotate:失败换号,允许 provider 自己决定是先 release 再 acquire,还是走路由替换。
- normalize:把 provider 返回值转成统一 activation。
4.3 侧边栏 UI 当前模型
侧边栏接码区已经存在 HeroSMS、5sim、NexSMS 的配置行,且很多字段复用了 HeroSMS 命名或布局类。后续实现不应继续在 sidepanel.js 里追加大量 if provider === ... 片段,而应引入 provider UI descriptor 或至少集中式字段矩阵,让“显示哪些行、保存哪些字段、切换 provider 时保留哪些值”有统一来源。
当前布局已有正确方向:
.data-row负责一行。.data-label固定 label 宽度。.data-inline作为右侧 control area,flex: 1 1 0。.data-input、.data-select、.btn统一高度。.data-inline-btn用固定最小宽度承接右侧动作按钮。
需要避免的是:
- 直接在
.data-row里放多个并列控制元素,导致 label 后布局不可预测。 - 单独给某些按钮做无边框、特殊高度、图标按钮或内联 style。
- 为某个 provider 写独立布局,造成切换 provider 后高度、宽度、边框不一致。
5. PR #288 取舍
5.1 保留的设计
保留 MaDao 作为独立 provider 模块的方向。建议文件为 phone-sms/providers/madao.js,暴露 createProvider(),并返回统一方法:
acquireActivation(state, options, deps)pollActivation(state, activation, deps)releaseActivation(state, activation, action, deps)rotateActivation(state, activation, options, deps)replaceRoutingActivation(state, activation, options, deps)
保留 MaDao 默认配置:
provider id:madaolabel:MaDaobaseUrl默认http://127.0.0.1:7822service默认openai- HTTP Secret 通过
Authorization: Bearer <secret>传递
保留两种模式:
routing_plan:使用madaoRoutingPlanId,取号只提交routing_plan_id和service,失败换号优先走/api/routing/replace。direct:使用madaoProviderId、madaoCountry、madaoAutoPickCountry、madaoReusePhone、madaoMinPrice、madaoMaxPrice。
5.2 不照搬的内容
不照搬主流程里的 MaDao 专用函数,例如 requestMaDaoActivation、getMaDaoProviderForState 这类把 provider 逻辑重新塞回编排层的写法。
不照搬 sidepanel 中大量散落的 MaDao row/handler。MaDao 字段应通过 provider UI descriptor 或集中显隐矩阵接入:
- provider 选择变更只触发一套
applyPhoneSmsProviderUi(provider, state)。 - 保存 payload 只走一套
collectPhoneSmsProviderSettings(provider)。 - 恢复 UI 只走一套
restorePhoneSmsProviderSettings(state)。
不增加 btn-open-madao-github。MaDao 本地服务不是当前目标项目地址入口,GitHub 入口只保留已有项目来源按钮,且按钮样式应统一为普通文字按钮。
6. 最终设计
6.1 provider 契约
新增或收敛 provider adapter 契约:
{
id,
label,
defaultProduct,
acquireActivation(state, options, deps),
pollActivation(state, activation, deps),
releaseActivation(state, activation, action, deps),
rotateActivation(state, activation, options, deps)
}
编排层只依赖契约,不依赖 provider 私有字段。activation 可以携带 provider 私有字段,但编排层只把它们原样保留和回传,最多读取统一字段:
activationIdphoneNumberproviderserviceCodecountryIdcountryLabel
MaDao 私有字段例如 madaoRoutingPlanId、madaoRoutingItemId、madaoAcquirePath、madaoStatus 只由 MaDao adapter 或展示层使用。
6.2 MaDao 设置字段
新增设置字段建议如下:
madaoBaseUrlmadaoHttpSecretmadaoMode:routing_plan或directmadaoRoutingPlanIdmadaoProviderIdmadaoCountrymadaoAutoPickCountrymadaoReusePhonemadaoMinPricemadaoMaxPrice
madaoServiceName 不建议作为普通可编辑项显示。OpenAI flow 下 service 固定为 openai 更符合当前边界,也能减少用户误配。如果确实需要保留兼容字段,可以内部默认和持久化,但 UI 只显示只读说明或不显示。
这些字段必须进入:
- 默认 state。
- 导入导出和最新设置合并 key。
- sidepanel 恢复、保存、消息更新。
- background 模块与实际
background.js同步入口。 - 相关单元测试 fixture。
6.3 MaDao 模式显隐
MaDao 选中时显示:
- Base URL。
- HTTP Secret。
- 模式选择。
routing_plan 模式显示:
- 路由方案选择或路由方案 ID。
- 刷新路由方案按钮,如果 MaDao 后端提供列表接口;如果没有列表接口,只保留 ID 输入框,不做假刷新按钮。
routing_plan 模式隐藏:
- direct provider。
- country。
- auto pick country。
- reuse phone。
- min/max price。
direct 模式显示:
- MaDao provider。
- country。
- auto pick country。
- reuse phone。
- min/max price。
direct 模式隐藏:
- routing plan 字段。
- routing replace 相关交互。
6.4 其他 provider 显隐矩阵
HeroSMS 显示:
- API Key。
- 国家优先级。
- 生效顺序。
- 拿号优先级。
- 运营商。
- 价格区间:min、max、preferred。
- 号码复用。
- 白嫖复用。
- 查询价格。
- 查余额。
5sim 显示:
- API Key。
- 国家优先级。
- 生效顺序。
- 运营商。
- 产品代码。
- 价格区间:min、max。
- 号码复用。
5sim 不显示:
- preferred price。
- HeroSMS 价格档位查询。
- 白嫖复用。
NexSMS 显示:
- API Key。
- 国家优先级。
- 生效顺序。
- 服务代码。
NexSMS 不显示:
- preferred price。
- operator。
- product。
- 号码复用。
- 白嫖复用。
MaDao 按 6.3 显隐,不复用 HeroSMS 的价格预览区,不显示无意义的国家多选和 provider 顺序内的 HeroSMS 专属说明。
6.5 换号与释放
步骤 9 和手机号注册验证码链路中的失败换号都应走统一 provider 方法:
- provider 有
rotateActivation时优先调用。 - MaDao
routing_plan且 activation 带madaoRoutingPlanId时,rotateActivation内部走/api/routing/replace并返回nextActivation。 - MaDao
direct或没有可替换路由信息时,先 release 当前 ticket,再让编排层按 provider 顺序重新 acquire。 - HeroSMS、5sim、NexSMS 可以先维持现状,但调用入口要向统一契约靠拢。
编排层不应关心 MaDao 的 /api/routing/replace endpoint,只应理解 rotateActivation 的返回:
{
currentTicketId,
currentTicketRelease,
nextActivation
}
6.6 OpenAI 手机号注册状态
后续实现必须分别覆盖:
- Step 2 手机号注册取号和填手机号。
- Step 4 手机注册验证码轮询和提交。
- Step 8 登录验证码、绑定邮箱状态分支。
- Step 9 后置 add-phone 取号、轮询、失败换号、成功释放或保留。
关键约束:
signupPhoneActivation不写入currentPhoneActivation。currentPhoneActivation不覆盖signupPhoneActivation。signupPhoneCompletedActivation用于手机号注册完成后的记录,不用于后置 add-phone 的当前订单。- 页面已经在等手机验证码但 state 没有 activation 时,应给出明确错误,不自动构造虚假订单。
6.7 按钮与文本框统一设计
采用固定 label 宽度,不固定文本框宽度:
| 76px label | flex:1 控制区 |
控制区规则:
- 普通单输入:
input.data-input直接作为第二个子元素,宽度占满剩余。 - 输入 + 按钮:使用
div.data-inline包裹,输入flex: 1 1 0,按钮使用.data-inline-btn。 - 多按钮动作组:仍放入一个
.data-inline,按钮高度统一,必要时允许换行,但不破坏 label + control 的两列结构。 - 密码显示按钮属于输入框内部交互,保留
input-with-icon,但不使用 GitHub 图标或 provider 图标。
按钮规则:
- 所有普通按钮使用
.btn基础类,必须有border: 1px solid var(--border)和min-height: var(--data-field-height)。 - 小按钮可以用
btn-sm/btn-xs调整字体和 padding,但高度仍应由统一变量约束。 - 行内动作按钮使用
.data-inline-btn,统一最小宽度,不按文案临时写 style。 - 不再新增
icon-action-btn,已有图标按钮若不是密码显隐这种输入内部控制,应改成文字按钮。 - GitHub 按钮显示为
GitHub文本,使用btn btn-outline btn-sm data-inline-btn。
删除按钮规则:
- 删除纯保存设置按钮,因为当前
saveSettings({ silent: true })和 autosave 已覆盖设置变更。 - 保留“记录”“清除”“查询价格”“查余额”“拉取”“下一条”“检测出口”等命令按钮,因为它们触发的不是单纯保存。
- 删除按钮时必须同步删除 DOM 引用、事件监听、CSS、测试断言和无用 helper。
6.8 项目 GitHub 按钮
项目地址入口只保留一套:
- CPA:
https://github.com/router-for-me/CLIProxyAPI - sub2api:
https://github.com/Wei-Shaw/sub2api
按钮不做图标,不使用 SVG,不新增 MaDao GitHub 入口。tests/sidepanel-flow-source-registry.test.js 需要继续保护 URL 和按钮 class。
7. 方案自检
7.1 是否符合需求
符合。方案明确处理了 PR #288 的重新实现、MaDao provider 接入、OpenAI 手机号注册模式、不同 provider 显隐、文本框和按钮统一、GitHub 按钮去图标化、无用保存按钮删除、旧代码清理等要求。
7.2 是否完善
基本完善。方案覆盖后台 provider 生命周期、侧边栏显示、设置持久化、自动保存、测试和实际运行入口。需要在实现阶段继续用代码验证的点是 MaDao 后端是否提供路由方案列表接口;如果没有,则 UI 不能设计“刷新路由方案”按钮,只能提供 ID 输入。
7.3 是否完整
完整性满足本次开发目标。方案没有只看 sidepanel,也覆盖了 OpenAI workflow、Step 2/4/8/9、provider registry、settings schema、background.js 实际入口和测试。未纳入范围的是把整个接码系统抽成 core 服务,因为这与现有架构边界冲突。
7.4 是否正确
方向正确。MaDao 被设计为 OpenAI 接码 provider,不污染 Kiro/Grok;routing replace 被封装在 provider adapter 内,不让主流程理解 MaDao endpoint;手机号注册和后置 add-phone 状态分离,避免订单串线。
7.5 是否规范一致
一致。UI 沿用当前 .data-row、.data-label、.data-inline、.btn、.data-inline-btn 体系;provider 沿用 phone-sms/providers/registry.js;测试沿用 node --test tests/*.test.js;中文文档风格与 md 目录已有方案保持一致。
7.6 是否存在设计冲突
已识别并规避以下冲突:
- “接码通用化”与现有架构边界冲突:本方案不通用化到 core。
- “固定文本框宽度”与行内按钮扩展冲突:本方案固定 label 和按钮最小宽度,让输入框占剩余。
- “MaDao routing_plan”与 direct 参数冲突:两种模式显隐互斥,payload 也互斥。
- “自动保存”与保存按钮冲突:纯保存按钮删除,命令按钮保留。
- “PR #288 直接 diff”与当前本地 UI 改动冲突:只吸收 provider 行为,不照搬 sidepanel 和主流程特例。
- “模块测试文件”与
background.js实际入口冲突:实现阶段必须同步两边或使用现有生成/同步方式验证。
7.7 方案自身缺陷和风险
仍需在实现阶段验证的风险:
- MaDao 后端接口返回字段可能和 PR 样例不完全一致,需要 provider 单测覆盖异常 payload、空 ticket、空 phone、HTTP 错误和超时。
- 当前
background/phone-verification-flow.jsprovider 内联较多,完全一次性抽象所有 provider 风险较高。建议本次只为 MaDao 建立统一入口,并把会影响 MaDao 的 acquire/poll/release/rotate 入口收敛,不做无关大重构。 - sidepanel 当前文件较大,集中 descriptor 改造要控制范围。优先让接码设置区 descriptor 化,不顺手重构 Plus、代理、邮箱等其他区域。
- 删除按钮时容易误删命令按钮。判断标准必须是“是否只保存当前设置”,不是“按钮文案里是否有保存/记录”。
- provider 顺序扩展到 4 个后,测试 fixture 中硬编码 3 个 provider 的地方较多,必须全局搜索更新。
8. 分阶段开发清单
阶段 1:基线保护与差异确认
开发内容:
- 确认当前分支状态,记录本地 ahead commit,不回退已有改动。
- 对比 PR #288,只提取 MaDao provider、routing replace 行为和测试意图。
- 运行现有定向测试,建立失败/通过基线。
- 全局搜索旧图标按钮、保存按钮、provider 顺序硬编码、MaDao 残留。
阶段自检:
- 确认没有改动功能代码。
- 确认 CPA / sub2api GitHub URL 未被误改。
- 确认没有把 PR #288 中删除大量无关文件的改动纳入本次范围。
- 确认终端和文档无乱码。
阶段 2:MaDao provider 模块与 registry
开发内容:
- 新增
phone-sms/providers/madao.js。 - 在
phone-sms/providers/registry.js注册madao。 - 扩展
DEFAULT_PHONE_SMS_PROVIDER_ORDER为 4 个 provider。 - 更新 provider normalize、label、moduleKey、provider ids 测试。
阶段自检:
- MaDao 未加载时错误信息明确。
- provider order 不截断 MaDao。
- HeroSMS、5sim、NexSMS normalize 行为不变。
- 单测覆盖未知 provider 回退默认 provider。
- 检查新文件 UTF-8 中文错误信息无乱码。
阶段 3:接码编排层接入统一 rotate
开发内容:
- 在
background/phone-verification-flow.js中接入 MaDao adapter。 - 收敛 acquire/poll/release/rotate 的调用入口,让 MaDao 走 provider 契约。
- Step 9 换号优先调用
rotateActivation,routing plan 返回nextActivation时直接继续使用新号。 - direct 模式或没有
nextActivation时走现有释放后重新取号流程。 - 同步实际运行入口
background.js。
阶段自检:
- 手机号注册 Step 2/4 使用
signupPhoneActivation。 - 后置 add-phone Step 9 使用
currentPhoneActivation。 - 失败换号不会把 signup activation 写入 current activation。
- MaDao routing replace 的 cancel/ban action 传参正确。
- HeroSMS、5sim、NexSMS 原有换号、释放、成功完成行为不回退。
阶段 4:设置默认值、导入导出与状态同步
开发内容:
- 新增 MaDao 设置默认值。
- 更新 settings schema、最新设置 key、导入导出、消息保存 payload。
- 更新 sidepanel restore 和后台 state merge。
- 为
madaoMode、madaoBaseUrl、madaoHttpSecret、madaoRoutingPlanId、direct 字段加 normalize。
阶段自检:
- 空配置下 MaDao 使用默认
http://127.0.0.1:7822。 routing_plan不提交 direct 字段。direct不提交 routing plan 字段。- 导入旧配置不会丢 HeroSMS / 5sim / NexSMS 设置。
- 自动保存不会在用户输入数字半成品时强行格式化造成体验问题。
阶段 5:侧边栏 provider UI descriptor
开发内容:
- 建立接码 provider 字段矩阵或 descriptor。
- 将 HeroSMS、5sim、NexSMS、MaDao 的行显隐集中到一处。
- provider 切换时保存当前 provider 独立字段,再恢复目标 provider 字段。
- MaDao mode 切换时刷新 routing/direct 显隐。
- 删除散落的 provider 专用重复判断。
阶段自检:
- HeroSMS 只显示 HeroSMS 相关字段。
- 5sim 不显示 preferred price 和白嫖复用。
- NexSMS 不显示 operator/product/复用。
- MaDao routing plan 不显示 direct 字段。
- MaDao direct 不显示 routing plan 字段。
- 切换 provider 不丢失其他 provider 已填 API key 和价格字段。
- Kiro/Grok 下不显示接码设置。
阶段 6:文本框和按钮样式统一
开发内容:
- 清理接码区和项目地址区不一致按钮样式。
- 删除无用纯保存按钮及对应 JS/CSS/测试。
- 所有行改为 label + 单一 control area。
- 有右侧按钮的文本框统一使用
.data-inline+.data-inline-btn。 - GitHub 按钮保持文字按钮,不使用图标。
阶段自检:
tests/sidepanel-form-layout.test.js通过。- 全局不存在
icon-action-btn。 .data-row没有超过两个直接子元素。.btn、.data-input、.data-select高度一致。- 按钮都有边框,除输入框内部密码显隐按钮外不出现无边框图标按钮。
- 文案较长按钮不撑破布局,必要时按统一规则换行。
阶段 7:测试完善
开发内容:
- 增加 MaDao provider 单测:acquire、poll、release、routing replace、direct fallback、超时、HTTP 错误。
- 增加 provider registry 测试:MaDao 注册、顺序、label、moduleKey。
- 增加 phone verification flow 测试:Step 9 routing replace 成功、routing replace 返回无效 next ticket、direct 模式释放后重新取号。
- 增加 sidepanel 测试:MaDao 字段显隐、mode 切换、保存 payload、provider 切换字段保留。
- 更新现有 provider order 和 settings schema 测试。
阶段自检:
- 定向测试全部通过。
- 全量
npm test通过。 - 没有只为测试通过而保留旧死代码。
- 测试名称准确描述行为,不写和实现不符的宽泛断言。
阶段 8:最终清理与人工核验
开发内容:
- 全局搜索 MaDao 旧函数名、旧按钮 id、旧 icon 类、无用 CSS。
- 全局搜索 provider 顺序硬编码的 3 provider 残留。
- 检查 sidepanel 渲染效果,确认按钮、文本框、select 高度和边框一致。
- 检查 OpenAI / Kiro / Grok 各 flow 显隐。
- 检查 CPA / sub2api 项目地址按钮。
阶段自检:
rg -n "requestMaDaoActivation|getMaDaoProviderForState|btn-open-madao-github|icon-action-btn" .无结果。rg -n "hero-sms.*5sim.*nexsms" tests sidepanel background phone-sms中需要 4 provider 的地方已包含 MaDao。- 文档、源码、测试无乱码字符;乱码样本不要写进方案正文,避免检查命令命中自身。
git diff中没有无关删除、无关格式化或用户未要求的重构。- 最终运行全量测试并记录结果。
9. 验证命令
建议按阶段使用以下命令:
node --test tests/phone-sms-provider-registry.test.js
node --test tests/phone-verification-flow.test.js
node --test tests/sidepanel-phone-verification-settings.test.js
node --test tests/sidepanel-form-layout.test.js
node --test tests/sidepanel-flow-source-registry.test.js
npm test
建议的清理检查:
rg -n "requestMaDaoActivation|getMaDaoProviderForState|btn-open-madao-github|icon-action-btn" .
$staleMarkers = @('T' + 'ODO', '待' + '补', '以后' + '再说', '占' + '位') -join '|'
rg -n $staleMarkers md sidepanel background phone-sms tests
git status --short --branch
git diff --check
10. 最终结论
本次应按“OpenAI 私有接码 provider 扩展 + 侧边栏 provider descriptor + 表单统一布局”三条线并行收敛。MaDao 的价值在于统一接码后端和 routing replace,不应把它变成主流程里的新特例;UI 的价值在于固定 label、固定按钮最小宽度、输入框占剩余,而不是继续给每个 provider 单独堆宽高和按钮风格。
后续实现完成的标准是:MaDao 能在手机号注册和后置 add-phone 两条链路中稳定取号、轮询、释放、换号;不同 provider 只显示自己需要的字段;按钮和文本框视觉一致;自动保存下没有多余保存按钮;旧的 MaDao 特例和图标按钮代码完全清理。