1198 lines
34 KiB
Markdown
1198 lines
34 KiB
Markdown
# 多Flow根治性统一重构方案
|
|
|
|
## 1. 背景
|
|
|
|
当前项目已经完成过多轮从单一 OpenAI 注册链路向多 flow 架构的重构,但现在的状态仍然属于“骨架已多 flow 化,核心 contract 仍保留 `openai + kiro` 双分支”。
|
|
|
|
这会带来三个持续性问题:
|
|
|
|
- 每新增一个 flow,都需要继续修改 core 语义,而不是只新增 flow 自己的模块。
|
|
- 文件命名、状态命名、配置命名仍带有明显历史负担,读代码和改代码都累。
|
|
- 每次重构都只能修表层,无法保证第三个 flow 接入时不再次爆炸。
|
|
|
|
本方案的目标不是“再修一轮兼容”,而是一次性把多 flow 架构收口成稳定合同,后续新增 flow 时不再改 core 语义。
|
|
|
|
## 2. 总目标
|
|
|
|
本次重构完成后,项目必须达到以下目标:
|
|
|
|
- 新增一个 flow 时,只新增该 flow 目录和注册项,不再修改 core 的配置合同、运行态合同和侧栏核心语义。
|
|
- 所有 flow 都使用同一套配置结构、同一套运行态结构、同一套 source/driver 注册模型。
|
|
- OpenAI 与 Kiro 的代码组织、文件命名、步骤命名、source 命名、driver 命名全部统一到同一规范。
|
|
- 删除长期存在的历史别名和双轨字段,避免后续维护继续被旧命名拖住。
|
|
- 旧配置不再作为运行时输入;旧数据只允许通过导入转换器映射到新 canonical 结构后进入系统。
|
|
|
|
## 3. 当前根问题
|
|
|
|
### 3.1 配置模型仍然是双轨
|
|
|
|
当前 `settings-schema` 只内建 `flows.openai` 和 `flows.kiro` 两套显式结构,同时继续派生:
|
|
|
|
- `openaiIntegrationTargetId`
|
|
- `kiroTargetId`
|
|
- `panelMode`
|
|
|
|
这不是多 flow 通用合同,而是两个 flow 的并排硬编码。第三个 flow 接入时,只能继续增加第三套特判。
|
|
|
|
### 3.2 运行态模型是裂开的
|
|
|
|
当前运行态存在两条体系:
|
|
|
|
- OpenAI 使用 `runtimeState.flowState.openai`
|
|
- Kiro 使用独立 `kiroRuntime`
|
|
|
|
这意味着“flow 私有运行态放哪里”没有统一答案。后续新增 flow 时,要么复制第三套运行态入口,要么继续在 core 写例外分支。
|
|
|
|
### 3.3 source / driver 仍未彻底注册化
|
|
|
|
虽然已经有 `flow-registry` 与 `source-registry`,但 core 里仍直接识别:
|
|
|
|
- OpenAI host
|
|
- Kiro host
|
|
- OpenAI / Kiro source family
|
|
|
|
这说明 source 系统还不是“flow 自带定义,core 只消费注册表”,而是“core 知道两个 flow 的页面事实”。
|
|
|
|
### 3.4 sidepanel 还是默认 flow 分支思维
|
|
|
|
当前 sidepanel 很多判断仍然是:
|
|
|
|
- 默认 flow 视为 OpenAI
|
|
- 非默认 flow 基本按 Kiro 处理
|
|
|
|
例如 target 读取、target 持久化、贡献页 target 解析、flow 切换后的字段同步,都带着明显的 `openai / kiro` 条件分支。
|
|
|
|
### 3.5 “按 flow 执行范围”表面通用,内部仍是双 flow 特判
|
|
|
|
`stepExecutionRangeByFlow` 在 UI 侧已经接近通用,但写回持久配置时仍只处理:
|
|
|
|
- `openai`
|
|
- `kiro`
|
|
|
|
这类设计最危险,因为它会制造“表面支持多 flow,实际只有两个 flow 真能落盘”的假通用。
|
|
|
|
### 3.6 文件和命名仍带历史语义
|
|
|
|
当前仍大量存在下列混合命名:
|
|
|
|
- `signup-page`
|
|
- `open-chatgpt`
|
|
- `platform-verify`
|
|
- `plus-checkout`
|
|
- `kiro-*`
|
|
- `vps-panel`
|
|
|
|
这些名字有的看起来像通用名,实际是 OpenAI 专属;有的则直接带品牌。继续保留会让后续架构再度滑回历史分支。
|
|
|
|
## 4. 重构原则
|
|
|
|
### 4.1 不做旧配置兼容,只做导入转换
|
|
|
|
本次不保留“先兼容着跑”的中间态。新系统上线后,运行时、持久化读写、sidepanel 消息、background 内部状态全部只认新合同。
|
|
|
|
原则是:
|
|
|
|
- 旧配置、旧账号记录、旧 flow 产物只能通过导入器转换
|
|
- 导入器是单向转换器,不是长期桥接层
|
|
- 导入完成后的数据必须完全符合新合同
|
|
- 除导入器外,任何模块都不再直接读写 `panelMode`、`openaiIntegrationTargetId`、`kiroTargetId`、`kiroRuntime` 等旧字段
|
|
|
|
### 4.2 通用层只负责“怎么跑一个 flow”
|
|
|
|
core 只解决这些问题:
|
|
|
|
- flow 注册
|
|
- source 注册
|
|
- driver 注册
|
|
- workflow 运行
|
|
- 状态存储
|
|
- sidepanel 动态渲染
|
|
- 通用服务接入
|
|
|
|
core 不再知道任何 OpenAI 或 Kiro 业务步骤语义。
|
|
|
|
### 4.3 flow 私有能力留在 flow 内部
|
|
|
|
以下能力继续保留为 flow 私有:
|
|
|
|
- OpenAI 的 OAuth、Plus、接码、平台绑定
|
|
- Kiro 的 Builder ID、桌面授权、`kiro.rs` 上传
|
|
- 任意新 flow 的站点特有页面状态机、验证码规则、成功判定和产物结构
|
|
|
|
### 4.4 命名必须先统一,再谈长期可维护性
|
|
|
|
如果 contract 抽象了,但目录和文件名还保留历史语义,后续阅读成本依然很高。本次重构必须把命名一并统一。
|
|
|
|
## 5. 第一层功能边界:公共能力与私有能力
|
|
|
|
这一层只回答一个问题:哪些能力应该是扩展级公共能力,哪些能力必须收回到各 flow 自己内部。
|
|
|
|
本层结论确定后,后续所有 contract、目录结构和配置模型都必须服从这条边界,不允许再反向把 flow 私有语义塞回公共层。
|
|
|
|
### 5.1 扩展级公共能力
|
|
|
|
当前项目真正应保留为全局公共能力的只有四块:
|
|
|
|
- 项目壳层
|
|
- 邮箱服务
|
|
- 账户密码
|
|
- IP 代理
|
|
|
|
其中:
|
|
|
|
- `项目壳层` 只包括顶部容器、flow 切换、开始/停止/重试、日志与运行态展示这些外层承载能力。
|
|
- `邮箱服务` 是跨 flow 的身份与收件基础设施。
|
|
- `账户密码` 指侧栏中的“账户密码”文本框,它的语义是“注册目标账号时使用的共享密码”。
|
|
- `IP 代理` 是扩展级环境能力,不属于任何单独 flow。
|
|
|
|
### 5.2 邮箱服务需要继续重构统一
|
|
|
|
邮箱服务值得保留为公共层,但必须从历史 OpenAI 语义中继续剥离。
|
|
|
|
它在功能上只应该负责三类事情:
|
|
|
|
- 生成注册邮箱
|
|
- 提供收件与轮询能力
|
|
- 维护当前轮次的邮箱身份
|
|
|
|
邮箱服务不应该继续承接这些内容:
|
|
|
|
- 某个 flow 的验证码命中规则
|
|
- 某个 flow 的页面跳转语义
|
|
- 某个 flow 的身份保留分支
|
|
- 某个 flow 的注册成功或失败判断
|
|
|
|
因此邮箱层应拆成两部分:
|
|
|
|
- `公共邮箱服务`
|
|
负责邮箱生成、收件、轮询、当前邮箱身份维护
|
|
- `flow 私有邮件规则`
|
|
负责某个 flow 在某一步认哪封邮件、提取什么内容、何时算命中
|
|
|
|
结论:
|
|
|
|
- 邮箱服务是公共能力
|
|
- 邮件规则不是公共能力
|
|
|
|
### 5.3 “账户密码”是共享注册密码,不是公共凭据服务
|
|
|
|
当前侧栏的“账户密码”文本框,其真实产品语义已经确认:
|
|
|
|
- 它不是平台后台登录密码
|
|
- 它不是某个管理接口凭据
|
|
- 它不是统一的凭据中心配置
|
|
- 它只是“注册出来的目标账号要设置成什么密码”
|
|
|
|
因此这里不应再抽象出“公共凭据服务”。
|
|
|
|
正确做法是:
|
|
|
|
- 保留一个全局公共的 `共享注册密码`
|
|
- 各 flow 自己决定是否使用这份密码
|
|
- 各 flow 自己决定在哪一步使用
|
|
- 如果某个 flow 没有设置密码步骤,则直接忽略
|
|
|
|
这意味着:
|
|
|
|
- `账户密码` 是公共输入能力
|
|
- `凭据结构` 不是公共能力
|
|
- `凭据产物字段` 不是公共能力
|
|
|
|
### 5.4 凭据与账号产物必须保持 flow 私有
|
|
|
|
虽然不做公共凭据服务,但每个 flow 仍然会生成自己的账号产物。
|
|
|
|
例如:
|
|
|
|
- OpenAI 可能产出邮箱、密码、session、OAuth 结果、平台接入结果
|
|
- Kiro 可能产出邮箱、密码、refresh token、clientId、clientSecret、上传结果
|
|
|
|
这里允许公共的只有“外层展示容器”或“记录壳层”,不允许公共化的内容包括:
|
|
|
|
- 主身份字段
|
|
- token 字段
|
|
- 上传字段
|
|
- 绑定字段
|
|
- 各类平台回调字段
|
|
|
|
结论:
|
|
|
|
- 账号产物展示容器可以公共
|
|
- 账号产物字段结构必须 flow 私有
|
|
|
|
### 5.5 IP 代理属于扩展级环境能力
|
|
|
|
IP 代理应直接定义为:
|
|
|
|
- 扩展级公共能力
|
|
- 与 flow 无关
|
|
- 由 flow 声明“可用/必需/禁用”,但不拥有它
|
|
|
|
flow 最多只能声明:
|
|
|
|
- 当前 flow 是否允许代理
|
|
- 当前 flow 的哪些页面需要代理约束
|
|
- 当前 flow 是否需要代理检测或 fail-close 策略
|
|
|
|
但代理配置、切换、应用、检测、诊断,都不属于 flow 私有模型。
|
|
|
|
### 5.6 第一层最终边界
|
|
|
|
本次重构在功能边界上最终固定为:
|
|
|
|
#### 全局公共能力
|
|
|
|
- 项目壳层
|
|
- 邮箱服务
|
|
- 共享注册密码
|
|
- IP 代理
|
|
|
|
#### 仅允许公共容器,不允许公共字段语义
|
|
|
|
- 账号记录容器
|
|
- 产物展示容器
|
|
|
|
#### flow 私有能力
|
|
|
|
- 账号主身份模型
|
|
- 邮件命中规则
|
|
- 验证码规则
|
|
- 注册步骤
|
|
- 登录步骤
|
|
- OAuth / callback
|
|
- 支付
|
|
- 上传
|
|
- flow 最终凭据与产物字段结构
|
|
|
|
后续所有重构如果与这条边界冲突,以这条边界为准,不允许再为了省事把 flow 私有字段上提为公共模型。
|
|
|
|
## 6. 第二层产品模型:flow 与 target
|
|
|
|
这一层只回答两个问题:
|
|
|
|
- flow 在产品上到底是什么
|
|
- target 在产品上到底是什么
|
|
|
|
如果这一层不先定死,后面配置模型、侧栏模型和运行态模型就会继续在 `panelMode / integrationTarget / targetId` 之间摇摆。
|
|
|
|
### 6.1 flow 的产品定义
|
|
|
|
每个 flow 都应被定义为一条独立的“账号生产链路”。
|
|
|
|
它至少具备以下特征:
|
|
|
|
- 有独立入口
|
|
- 有独立步骤顺序
|
|
- 有独立成功判定
|
|
- 有独立最终产物
|
|
- 只按需消费公共能力,例如邮箱、共享注册密码、IP 代理
|
|
|
|
因此,flow 不是“几步流程的组合”,而是一个完整产品单元。
|
|
|
|
结论:
|
|
|
|
- `openai` 是一个完整 flow
|
|
- `kiro` 是一个完整 flow
|
|
- 未来新站点也必须是完整 flow
|
|
- 不允许再把新站点业务塞进现有 flow 里做条件分支
|
|
|
|
### 6.2 target 的产品定义
|
|
|
|
target 不应继续被理解为历史意义上的 `panelMode`。
|
|
|
|
正确的产品语义应该是:
|
|
|
|
- target 是这个 flow 最终产物的去向
|
|
- target 是这个 flow 最终服务的目标系统
|
|
|
|
例如:
|
|
|
|
- OpenAI flow 的 target 可以是 `CPA / SUB2API / Codex2API`
|
|
- Kiro flow 的 target 可以是 `kiro-rs`
|
|
|
|
因此:
|
|
|
|
- `flow` 回答“怎么产出账号或产物”
|
|
- `target` 回答“产出后要交给谁使用”
|
|
|
|
这两个概念必须严格分层,不允许再混用。
|
|
|
|
### 6.3 每个 flow 都必须自带 target 模型
|
|
|
|
以后不再允许:
|
|
|
|
- 只有 OpenAI flow 有 target
|
|
- Kiro flow 走另一套特殊 target 字段
|
|
- 默认 flow 使用 `panelMode`,其他 flow 使用 `targetId`
|
|
|
|
统一要求如下:
|
|
|
|
- 每个 flow 都必须有 `selectedTarget`
|
|
- 每个 flow 都必须有 `targets`
|
|
- 单 target flow 只是“只有一个 target”,不是“没有 target 概念”
|
|
|
|
即使某个 flow 当前只有一个 target,模型里也必须保留 target 层,只是在 UI 上可以隐藏选择器。
|
|
|
|
这样做的原因是:
|
|
|
|
- 未来该 flow 如果新增第二个 target,不需要再次改核心模型
|
|
- sidepanel 和 settings 不需要区分“哪个 flow 才有 target”
|
|
|
|
### 6.4 flow 的产品结构
|
|
|
|
从功能角度,每个 flow 都应至少包含以下部分:
|
|
|
|
- flow 基本信息
|
|
- flow 对公共能力的依赖声明
|
|
- flow 私有配置
|
|
- flow targets
|
|
- flow 产物定义
|
|
|
|
进一步展开:
|
|
|
|
- `flow 基本信息`
|
|
- 名称
|
|
- 说明
|
|
- 是否可自动化
|
|
- `公共能力依赖声明`
|
|
- 是否使用邮箱
|
|
- 是否使用共享注册密码
|
|
- 是否允许代理
|
|
- `flow 私有配置`
|
|
- 仅该 flow 自己理解的设置
|
|
- `flow targets`
|
|
- 一个或多个目标系统
|
|
- `flow 产物定义`
|
|
- 该 flow 最终生成什么结果
|
|
|
|
### 6.5 第二层最终结论
|
|
|
|
本次重构在产品模型上最终固定为:
|
|
|
|
- `flow = 独立账号生产产品线`
|
|
- `target = flow 产物去向`
|
|
- 每个 flow 都必须天然支持自己的 target 模型
|
|
- 全局只保留“当前选中的 flow”
|
|
- 当前 target 永远从当前 flow 自己内部读取
|
|
|
|
由此带来的直接结果是:
|
|
|
|
- `panelMode` 只允许存在于导入器输入映射里
|
|
- `openaiIntegrationTargetId / kiroTargetId` 不再是长期 canonical 配置
|
|
- sidepanel 不再需要围绕“默认 flow 是 OpenAI”建立逻辑
|
|
|
|
后续所有设计如果与这层产品模型冲突,以这层定义为准。
|
|
|
|
## 7. 第三层运行模型:统一节点承载,不统一阶段语义
|
|
|
|
这一层只回答一个问题:
|
|
|
|
- 多 flow 体系下,到底应该统一什么样的运行流程模型
|
|
|
|
本层最终结论是:
|
|
|
|
- 统一节点承载方式
|
|
- 不统一跨 flow 的阶段语义
|
|
|
|
也就是说,core 只负责“如何承载一个 flow 的内部流程”,不负责替每个 flow 规定必须长成同一种产品流程形状。
|
|
|
|
### 7.1 不强制统一阶段
|
|
|
|
本次重构不再要求所有 flow 都映射到一套固定阶段,例如:
|
|
|
|
- 准备
|
|
- 进入
|
|
- 验证
|
|
- 成型
|
|
- 接入
|
|
- 交付
|
|
|
|
这种抽象在文档上容易显得整齐,但对真实多 flow 来说约束过强,后续会重新形成“表面通用、实际不好用”的壳层。
|
|
|
|
因此:
|
|
|
|
- OpenAI 保持自己的内部流程形状
|
|
- Kiro 保持自己的内部流程形状
|
|
- 新 flow 也不需要被迫套进统一阶段模型
|
|
|
|
### 7.2 真正需要统一的是节点运行模型
|
|
|
|
虽然不统一阶段语义,但所有 flow 仍然必须共享同一套“节点承载方式”。
|
|
|
|
每个 flow 的内部流程都应被理解为:
|
|
|
|
- 一组有顺序的节点
|
|
- 节点之间存在前后关系
|
|
- 每个节点都有清晰输入和结果
|
|
- 节点可以被手动执行、自动执行、停止和重试
|
|
|
|
也就是说,core 只统一:
|
|
|
|
- 节点是什么
|
|
- 节点如何排序
|
|
- 节点如何连接
|
|
- 节点如何汇报状态
|
|
|
|
而不统一:
|
|
|
|
- 节点一定属于哪个阶段
|
|
- 某个数字步骤在所有 flow 里都代表什么
|
|
|
|
### 7.3 数字步骤只表示 flow 内部显示顺序
|
|
|
|
以后数字步骤只允许表达:
|
|
|
|
- 当前 flow 内部的展示顺序
|
|
|
|
不再允许表达:
|
|
|
|
- 跨 flow 的固定语义
|
|
- 全局共享的产品阶段
|
|
- 某个历史 OpenAI 10 步链路的编号意义
|
|
|
|
这意味着:
|
|
|
|
- `Step 4` 不再天然等于“验证码步骤”
|
|
- `Step 7` 不再天然等于“OAuth”
|
|
- `Step 9` 不再天然等于“平台验证”
|
|
|
|
这些语义都必须下沉为 flow 私有流程定义。
|
|
|
|
### 7.4 节点的最小公共合同
|
|
|
|
从产品功能角度,每个节点只需要满足以下最小公共合同:
|
|
|
|
- 有名称
|
|
- 有顺序
|
|
- 有前后关系
|
|
- 有明确成功结果
|
|
- 有明确失败结果
|
|
- 可以手动执行
|
|
- 可以自动执行
|
|
- 可以停止
|
|
- 可以重试
|
|
|
|
节点不应该再承载这些“假通用”要求:
|
|
|
|
- 必须属于固定阶段
|
|
- 必须服从跨 flow 的相同命名
|
|
- 必须让不同 flow 共享同一种页面语义
|
|
|
|
### 7.5 外层统一状态,不统一流程内容
|
|
|
|
扩展外层只需要理解统一运行状态,不需要理解每个 flow 的内部阶段。
|
|
|
|
建议外层只保留以下状态集合:
|
|
|
|
- 未开始
|
|
- 运行中
|
|
- 等待中
|
|
- 需人工处理
|
|
- 已停止
|
|
- 已失败
|
|
- 已完成
|
|
|
|
这些状态只服务于:
|
|
|
|
- 侧栏展示
|
|
- 自动运行控制
|
|
- 停止 / 重试入口
|
|
- 日志与记录
|
|
|
|
它们不应反过来要求 flow 把内部步骤硬映射成统一业务阶段。
|
|
|
|
### 7.6 执行范围绑定当前 flow 的节点顺序
|
|
|
|
`执行范围` 这个能力未来仍然保留,但其产品定义应明确为:
|
|
|
|
- 对当前 flow 可见节点顺序的执行限制
|
|
|
|
它不再代表:
|
|
|
|
- 全局统一步骤范围
|
|
- 跨 flow 的阶段范围
|
|
- OpenAI 历史编号的范围
|
|
|
|
也就是说,执行范围始终只作用于“当前 flow 自己的节点序列”。
|
|
|
|
### 7.7 第三层最终结论
|
|
|
|
本层最终固定为:
|
|
|
|
- 不统一所有 flow 的阶段语义
|
|
- 不统一所有 flow 的产品流程形状
|
|
- 每个 flow 自己定义内部流程
|
|
- core 只统一节点承载方式
|
|
- 数字步骤只代表当前 flow 的显示顺序
|
|
- 扩展外层只理解统一运行状态
|
|
- 执行范围只绑定当前 flow 的节点顺序
|
|
|
|
后续如果有设计要求把所有 flow 再次硬映射成一套跨 flow 固定阶段,以本层结论为准,默认不采纳。
|
|
|
|
## 8. 第四层界面分工:公共壳层与 flow 工作面
|
|
|
|
这一层只回答一个问题:
|
|
|
|
- sidepanel 到底哪些界面必须永远公共,哪些界面必须彻底交给 flow 自己
|
|
|
|
如果这层不先定死,后续所有 flow 接入都会继续把 `openai / kiro / new-flow` 的条件分支堆进侧栏主文件。
|
|
|
|
### 8.1 只保留两层界面
|
|
|
|
本次重构后,sidepanel 只保留两层界面:
|
|
|
|
- 公共壳层
|
|
- flow 工作面
|
|
|
|
不再增加第三层“伪通用业务面板”。
|
|
|
|
原因很简单:
|
|
|
|
- 公共壳层负责承载扩展级操作
|
|
- flow 工作面负责承载 flow 私有配置与流程内容
|
|
|
|
这样结构最稳,也最不容易重新膨胀。
|
|
|
|
### 8.2 公共壳层放什么
|
|
|
|
公共壳层只允许放扩展级公共入口与全局控制入口,包括:
|
|
|
|
- flow 选择
|
|
- target 选择
|
|
- 开始 / 停止 / 重试 / 自动
|
|
- 当前运行状态
|
|
- 日志区
|
|
- 账号记录入口
|
|
- 文档 / 引导 / 更新提示入口
|
|
- 贡献 / 使用教程按钮
|
|
- 公共能力入口
|
|
- 邮箱服务
|
|
- 共享注册密码
|
|
- IP 代理
|
|
|
|
这里的“贡献 / 使用教程”按钮属于公共壳层入口,但其功能逻辑必须按当前 flow 适配。
|
|
|
|
也就是说:
|
|
|
|
- 按钮入口位置是公共的
|
|
- 点击后的目标页面、说明内容、贡献适配逻辑由当前 flow 决定
|
|
|
|
不允许再把它写成某一个默认 flow 的固定行为。
|
|
|
|
### 8.3 flow 工作面放什么
|
|
|
|
flow 工作面只允许承载该 flow 自己的内容,包括:
|
|
|
|
- flow 私有配置
|
|
- flow 私有步骤列表
|
|
- flow 私有运行态展示
|
|
- flow 私有人工补位入口
|
|
- flow 私有产物展示字段
|
|
|
|
例如:
|
|
|
|
- OpenAI 的 Plus、OAuth、平台接入、手机验证,只能放在 OpenAI 工作面
|
|
- Kiro 的桌面授权、上传到 `kiro.rs`,只能放在 Kiro 工作面
|
|
|
|
未来新增 flow 也必须遵守同样规则。
|
|
|
|
### 8.4 步骤列表属于 flow 私有界面
|
|
|
|
步骤列表不属于公共界面。
|
|
|
|
公共壳层最多只负责:
|
|
|
|
- 放置步骤列表容器
|
|
- 提供统一骨架样式
|
|
- 提供统一按钮状态和颜色规则
|
|
|
|
但以下内容都必须由 flow 自己决定:
|
|
|
|
- 有哪些步骤
|
|
- 步骤叫什么
|
|
- 步骤显示什么说明
|
|
- 哪些步骤可执行
|
|
- 哪些步骤可跳过
|
|
- 哪些步骤需要人工补位
|
|
|
|
### 8.5 账号记录采用“公共入口 + 私有内容”
|
|
|
|
账号记录建议固定为:
|
|
|
|
- 公共入口
|
|
- flow 私有内容
|
|
|
|
也就是说:
|
|
|
|
- 记录页或记录弹层入口是公共的
|
|
- 分页、筛选、基础容器可以公共
|
|
- 每条记录里显示哪些字段,按当前 flow 决定
|
|
|
|
这样既保留统一入口,也避免为了统一记录展示而把所有 flow 的产物字段重新揉成一个假通用结构。
|
|
|
|
### 8.6 公共能力入口的边界
|
|
|
|
公共区可以保留三类公共能力入口:
|
|
|
|
- 邮箱服务
|
|
- 共享注册密码
|
|
- IP 代理
|
|
|
|
但这些公共入口只负责:
|
|
|
|
- 配置
|
|
- 当前状态展示
|
|
- 基础校验
|
|
|
|
它们不负责:
|
|
|
|
- 解释某个 flow 的业务步骤
|
|
- 解释某个 flow 的页面语义
|
|
- 承载某个 flow 的专属运行逻辑
|
|
|
|
这意味着:
|
|
|
|
- OpenAI 专属邮箱模式说明,应回到 OpenAI 工作面
|
|
- Kiro 专属密码说明,应回到 Kiro 工作面
|
|
- 某个 flow 的代理特殊策略,也应由该 flow 自己声明和解释
|
|
|
|
### 8.7 target 选择器仍属于公共壳层
|
|
|
|
target 虽然属于当前 flow 的内部模型,但从用户交互角度,它属于“开跑前的全局决策”。
|
|
|
|
因此:
|
|
|
|
- target 选择器放在公共壳层
|
|
- target 的可选项由当前 flow 决定
|
|
- target 的说明文案也由当前 flow 决定
|
|
|
|
这样用户能在统一入口完成“跑哪个 flow、产物交给谁”的全局决策。
|
|
|
|
### 8.8 第四层最终结论
|
|
|
|
本层最终固定为:
|
|
|
|
- sidepanel 只保留“公共壳层 + flow 工作面”两层
|
|
- 公共壳层承载扩展级入口和全局控制
|
|
- flow 工作面承载 flow 私有配置、步骤、运行态和产物
|
|
- 步骤列表属于 flow 私有界面
|
|
- 账号记录采用“公共入口 + 私有内容”
|
|
- 贡献 / 使用教程按钮属于公共壳层入口,但功能逻辑必须按当前 flow 适配
|
|
- 不允许再把任何 OpenAI / Kiro / 新 flow 的专属业务配置继续堆进公共区
|
|
|
|
## 9. 目标架构
|
|
|
|
建议收口为以下目录形态:
|
|
|
|
```txt
|
|
core/
|
|
flow-kernel/
|
|
flow-registry.js
|
|
source-registry.js
|
|
driver-registry.js
|
|
settings-schema.js
|
|
runtime-state.js
|
|
workflow-engine.js
|
|
step-registry.js
|
|
tab-runtime.js
|
|
logging-status.js
|
|
|
|
flows/
|
|
index.js
|
|
|
|
openai/
|
|
flow.js
|
|
settings.js
|
|
state.js
|
|
sources.js
|
|
drivers.js
|
|
steps/
|
|
content/
|
|
mail/
|
|
rules.js
|
|
contribution/
|
|
|
|
kiro/
|
|
flow.js
|
|
settings.js
|
|
state.js
|
|
sources.js
|
|
drivers.js
|
|
steps/
|
|
content/
|
|
contribution/
|
|
|
|
imports/
|
|
legacy/
|
|
settings-importer.js
|
|
account-records-importer.js
|
|
flow-artifacts/
|
|
openai.js
|
|
kiro.js
|
|
```
|
|
|
|
第一阶段可以不强制先物理移动到 `core/flow-kernel/`,但逻辑上必须先收成这套边界。
|
|
|
|
补充要求:
|
|
|
|
- `imports/legacy/` 是全仓库唯一允许理解旧字段、旧结构、旧命名的目录。
|
|
- `core/` 与 `flows/` 不再保留任何旧字段回写逻辑。
|
|
|
|
## 10. 统一合同
|
|
|
|
### 10.1 配置合同
|
|
|
|
唯一 canonical 配置结构:
|
|
|
|
```js
|
|
settingsState = {
|
|
schemaVersion,
|
|
activeFlowId,
|
|
services: {
|
|
account,
|
|
email,
|
|
proxy,
|
|
},
|
|
flows: {
|
|
[flowId]: {
|
|
selectedTargetId,
|
|
targets: {
|
|
[targetId]: {}
|
|
},
|
|
autoRun: {
|
|
stepExecutionRange,
|
|
},
|
|
ui: {},
|
|
features: {},
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
要求:
|
|
|
|
- `selectedTargetId + targets[targetId]` 是唯一 target 入口。
|
|
- 不再以 `openaiIntegrationTargetId`、`kiroTargetId` 作为 canonical 字段。
|
|
- `panelMode` 不再作为内部真实配置语义,也不再出现在 sidepanel payload、background 持久化写入路径和运行时配置读取路径中。
|
|
- 每个 flow 都必须使用 `selectedTargetId + targets[targetId]` 组合。
|
|
- target 专属字段只能挂在对应 `targets[targetId]` 下,不再允许提升到 flow 顶层或全局顶层。
|
|
- 旧配置文件不能被直接加载运行,只能先经过导入转换器。
|
|
|
|
### 10.2 运行态合同
|
|
|
|
唯一 canonical 运行态结构:
|
|
|
|
```js
|
|
runtimeState = {
|
|
activeFlowId,
|
|
activeRunId,
|
|
currentNodeId,
|
|
nodeStatuses,
|
|
sharedState: {},
|
|
serviceState: {
|
|
account: {},
|
|
email: {},
|
|
proxy: {},
|
|
},
|
|
flowState: {
|
|
[flowId]: {
|
|
session: {},
|
|
nodes: {},
|
|
artifacts: {},
|
|
ui: {},
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
要求:
|
|
|
|
- 删除独立 `kiroRuntime` 作为长期入口。
|
|
- OpenAI、Kiro、未来新 flow 的私有运行态全部进入 `runtimeState.flowState[flowId]`。
|
|
- 顶层不再持久化任何 flow 私有扁平字段。
|
|
- 运行态不做旧快照导入;导入只处理持久配置与持久产物,导入完成后从新运行态起跑。
|
|
- 如需便捷读取视图,只能从 canonical `flowState` 派生,不能再反向写出独立运行态入口。
|
|
|
|
### 10.3 flow 定义合同
|
|
|
|
每个 flow 统一导出:
|
|
|
|
```js
|
|
{
|
|
id,
|
|
label,
|
|
services,
|
|
capabilities,
|
|
settingsGroups,
|
|
targets,
|
|
settingsShape,
|
|
runtimeStateShape,
|
|
sources,
|
|
drivers,
|
|
workflow,
|
|
artifactSchema,
|
|
importers,
|
|
contributionAdapters,
|
|
}
|
|
```
|
|
|
|
要求:
|
|
|
|
- `flow-registry` 只合并 flow 定义。
|
|
- `settings-schema`、`source-registry`、`driver-registry`、`step-registry` 都只消费 flow 导出的定义。
|
|
- flow 私有导入转换规则也由 flow 自己提供,core 只负责分发到对应 importer。
|
|
- core 不再直接声明某个 flow 的 target、source、driver。
|
|
|
|
### 10.4 source 合同
|
|
|
|
每个 source 至少声明:
|
|
|
|
- `id`
|
|
- `flowId`
|
|
- `kind`
|
|
- `label`
|
|
- `hostPatterns`
|
|
- `familyMatcher`
|
|
- `injectFiles`
|
|
- `readyPolicy`
|
|
- `cleanupScopes`
|
|
- `tabReusePolicy`
|
|
|
|
要求:
|
|
|
|
- host 判断由 flow source 定义驱动。
|
|
- `unknown-source` 仅做诊断,不自动回退到任意业务 source。
|
|
- callback cleanup 必须由 `cleanupScope -> ownerSource` 注册表驱动。
|
|
|
|
### 10.5 driver 合同
|
|
|
|
每个 driver 至少声明:
|
|
|
|
- `id`
|
|
- `sourceId`
|
|
- `commands`
|
|
- `injectFiles`
|
|
|
|
要求:
|
|
|
|
- driver 负责“页面能做什么”
|
|
- source 负责“页面是什么、如何识别、如何复用、如何清理”
|
|
|
|
### 10.6 step 合同
|
|
|
|
每个 step 统一使用:
|
|
|
|
- `id`
|
|
- `order`
|
|
- `key`
|
|
- `title`
|
|
- `sourceId`
|
|
- `driverId`
|
|
- `command`
|
|
- `mailRuleId`
|
|
|
|
要求:
|
|
|
|
- `step key` 只表达 flow 内语义,不再混入历史平台词和伪通用词。
|
|
- `background/steps/*.js` 这种共享目录最终要消失,改由各 flow 自己维护 `steps/`。
|
|
|
|
## 11. 命名统一方案
|
|
|
|
### 11.1 flow 目录命名
|
|
|
|
- `flows/openai/`
|
|
- `flows/kiro/`
|
|
|
|
未来新增 flow 一律使用 `flows/<flow-id>/`
|
|
|
|
### 11.2 source 命名
|
|
|
|
统一格式:
|
|
|
|
```txt
|
|
<flow-id>-<page-role>
|
|
mail-<provider>
|
|
panel-<target>
|
|
```
|
|
|
|
例如:
|
|
|
|
- `openai-auth`
|
|
- `openai-entry`
|
|
- `openai-checkout`
|
|
- `openai-paypal`
|
|
- `openai-gopay`
|
|
- `kiro-register`
|
|
- `kiro-desktop-authorize`
|
|
- `panel-sub2api`
|
|
- `panel-cpa`
|
|
- `mail-gmail`
|
|
|
|
### 11.3 driver 命名
|
|
|
|
统一格式:
|
|
|
|
```txt
|
|
flows/<flow-id>/content/<page-role>.js
|
|
flows/<flow-id>/steps/<step-role>.js
|
|
```
|
|
|
|
不再使用历史伪通用名作为全局 driver 语义。
|
|
|
|
### 11.4 OpenAI 文件重命名建议
|
|
|
|
以下文件建议统一迁移:
|
|
|
|
- `flows/openai/content/openai-auth.js` -> `flows/openai/content/openai-auth.js`
|
|
- `flows/openai/content/plus-checkout.js` -> `flows/openai/content/checkout-page.js`
|
|
- `flows/openai/content/paypal-flow.js` -> `flows/openai/content/paypal-page.js`
|
|
- `flows/openai/content/gopay-flow.js` -> `flows/openai/content/gopay-page.js`
|
|
- `flows/openai/content/sub2api-panel.js` -> `flows/openai/content/sub2api-panel-page.js`
|
|
- `flows/openai/content/vps-panel.js` -> `flows/openai/content/cpa-panel-page.js`
|
|
|
|
- `flows/openai/background/steps/open-chatgpt.js` -> `flows/openai/steps/open-entry.js`
|
|
- `flows/openai/background/steps/submit-signup-email.js` -> `flows/openai/steps/submit-identifier.js`
|
|
- `flows/openai/background/steps/fill-password.js` -> `flows/openai/steps/submit-password.js`
|
|
- `flows/openai/background/steps/fetch-signup-code.js` -> `flows/openai/steps/submit-signup-code.js`
|
|
- `flows/openai/background/steps/fill-profile.js` -> `flows/openai/steps/submit-profile.js`
|
|
- `flows/openai/background/steps/wait-registration-success.js` -> `flows/openai/steps/wait-register-complete.js`
|
|
- `flows/openai/background/steps/oauth-login.js` -> `flows/openai/steps/start-oauth-login.js`
|
|
- `flows/openai/background/steps/fetch-login-code.js` -> `flows/openai/steps/submit-login-code.js`
|
|
- `flows/openai/background/steps/confirm-oauth.js` -> `flows/openai/steps/confirm-oauth-consent.js`
|
|
- `flows/openai/background/steps/platform-verify.js` -> `flows/openai/steps/complete-platform-bind.js`
|
|
|
|
### 11.5 Kiro 文件重命名建议
|
|
|
|
以下文件建议统一迁移:
|
|
|
|
- `flows/kiro/background/register-runner.js` -> `flows/kiro/steps/register-flow.js`
|
|
- `flows/kiro/background/desktop-authorize-runner.js` -> `flows/kiro/steps/desktop-authorize-flow.js`
|
|
- `flows/kiro/background/publisher-kiro-rs.js` -> `flows/kiro/steps/upload-credential.js`
|
|
- `flows/kiro/background/state.js` -> `flows/kiro/state.js`
|
|
- `flows/kiro/content/register-page.js` -> `flows/kiro/content/register-page.js`
|
|
- `flows/kiro/content/desktop-authorize-page.js` -> `flows/kiro/content/desktop-authorize-page.js`
|
|
|
|
## 12. 替换式升级与导入转换策略
|
|
|
|
### 阶段 1:先定 canonical contract 与最终目录边界
|
|
|
|
目标:
|
|
|
|
- 定义统一的 settings、runtime、flow、source、driver、step 合同
|
|
- 定义 `core/`、`flows/`、`imports/legacy/` 三层边界
|
|
- 明确旧字段只允许出现在导入器中
|
|
|
|
产出:
|
|
|
|
- 更新设计文档
|
|
- 明确迁移边界
|
|
|
|
完成标准:
|
|
|
|
- 不再允许出现“新 flow 以后再看放哪”这种模糊点
|
|
|
|
### 阶段 2:统一配置模型
|
|
|
|
目标:
|
|
|
|
- 让所有 flow 都走 `settingsState.flows[flowId]`
|
|
- 停止所有新代码对旧配置字段的直接读写
|
|
|
|
动作:
|
|
|
|
- 重写 `core/flow-kernel/settings-schema.js`
|
|
- 把 `selectedTargetId` 作为统一 target 入口
|
|
- 改写 `background.js` 中 `buildSettingsStatePatchFromFlatUpdates`、`buildAutoRunFreshResetSettingsState`、`buildFreshAutoRunKeepState`
|
|
- 改写 `background/message-router.js` 与 `sidepanel/sidepanel.js` 的设置写入路径,只提交 canonical patch
|
|
- 将 `panelMode / openaiIntegrationTargetId / kiroTargetId` 从运行时和持久化写入路径移除
|
|
|
|
完成标准:
|
|
|
|
- 任意 flow 都可通过相同 API 读取当前 target 和 flow 设置
|
|
- 正常保存、导出、恢复流程里不再出现旧 target 字段
|
|
|
|
### 阶段 3:统一运行态模型
|
|
|
|
目标:
|
|
|
|
- 把 `kiroRuntime` 并入 `runtimeState.flowState.kiro`
|
|
- 让 OpenAI 与 Kiro 都按同一种 flow 私有运行态承载方式工作
|
|
|
|
动作:
|
|
|
|
- 重写 `core/flow-kernel/runtime-state.js`
|
|
- 把 `flows/kiro/background/state.js` 合并或迁入 `flows/kiro/state.js`
|
|
- 给 OpenAI 与 Kiro 都定义 flow 私有状态 shape 与 reset 规则
|
|
- 删除独立 Kiro 运行态主入口
|
|
- 停止持久化所有 flow 私有顶层扁平字段
|
|
|
|
完成标准:
|
|
|
|
- core 不再区分“OpenAI 私有状态”与“Kiro 私有状态”的存储方式
|
|
- 自动运行、fresh reset、日志回写都只消费统一运行态结构
|
|
|
|
### 阶段 4:建立单向导入转换器
|
|
|
|
目标:
|
|
|
|
- 让旧数据只能通过导入器进入新系统
|
|
- 明确“导入”与“运行时兼容”是两件不同的事
|
|
|
|
动作:
|
|
|
|
- 新建 `imports/legacy/settings-importer.js`
|
|
- 新建 `imports/legacy/account-records-importer.js`
|
|
- 按需新增 `flows/openai/importers/*` 与 `flows/kiro/importers/*` 用于旧产物字段映射
|
|
- 导入器负责识别 `panelMode`、`openaiIntegrationTargetId`、`kiroTargetId`、`stepExecutionRangeByFlow`、`kiroRuntime` 以及旧账号记录结构
|
|
- 导入结果统一输出为新 `settingsState`、新账号记录结构、新 flow 产物结构
|
|
- 明确不导入旧运行态快照
|
|
|
|
完成标准:
|
|
|
|
- 旧配置文件只能通过“导入”按钮进入系统,不能被直接加载运行
|
|
- 导入完成后,系统内部不再保留旧字段副本
|
|
|
|
### 阶段 5:统一 flow 注册与 source/driver 注册
|
|
|
|
目标:
|
|
|
|
- 让 flow 目录自带 source、driver、workflow、state、settings 定义
|
|
|
|
动作:
|
|
|
|
- 新建 `flows/index.js`
|
|
- 把 flow 相关定义从 `core/flow-kernel/flow-registry.js`、`core/flow-kernel/source-registry.js`、`core/flow-kernel/flow-capabilities.js`、`data/step-definitions.js`、`core/flow-kernel/step-registry.js` 拆到各 flow 内
|
|
- `source-registry` 改为只做合并与查询
|
|
- `workflow-engine` 与 step registry 改为只消费 flow 导出定义
|
|
|
|
完成标准:
|
|
|
|
- 新增 flow 时只新增 flow 定义,不改 core host 判断语义
|
|
|
|
### 阶段 6:统一 sidepanel 驱动方式
|
|
|
|
目标:
|
|
|
|
- sidepanel 完全按 registry 驱动,而不是按 `openai / kiro` 条件分支
|
|
|
|
动作:
|
|
|
|
- 重写 `sidepanel/sidepanel.js`
|
|
- 调整 `sidepanel/contribution-mode.js`、`sidepanel/account-records-manager.js`、相关 flow 私有展示逻辑
|
|
- flow selector、target selector、visible groups、capability 全部从 registry 派生
|
|
- `stepExecutionRange` 改成真正按当前 flow 通用读写
|
|
- 账号记录区改成“公共列表壳层 + flow 私有渲染器”
|
|
|
|
完成标准:
|
|
|
|
- sidepanel 不再依赖默认 flow 是 OpenAI 的假设
|
|
- sidepanel 不再直接处理 `panelMode` 与 `kiroTargetId` 两套并列写法
|
|
|
|
### 阶段 7:统一目录与文件命名
|
|
|
|
目标:
|
|
|
|
- 把 OpenAI 与 Kiro 都迁入 `flows/<flow-id>/`
|
|
|
|
动作:
|
|
|
|
- 重命名文件
|
|
- 更新所有 import / `importScripts` / 注入列表 / 测试引用
|
|
- 删除历史伪通用文件名
|
|
- 将 `content/*.js`、`background/steps/*.js`、`background/kiro/*` 分别迁入对应 flow 目录
|
|
|
|
完成标准:
|
|
|
|
- 新人看目录时能立即分清 core 与 flow 私有实现
|
|
|
|
### 阶段 8:删除旧兼容层与旧字段路径
|
|
|
|
目标:
|
|
|
|
- 删除所有只为迁移存在的旧字段、旧别名、旧路径和旧命名
|
|
|
|
动作:
|
|
|
|
- 删除 `signup-page -> openai-auth` 长期别名
|
|
- 删除 `kiroRuntime` 独立入口
|
|
- 删除 `panelMode` 作为内部真实 target 语义
|
|
- 删除 `background.js`、`background/message-router.js`、`background/navigation-utils.js`、`background/auto-run-controller.js` 里所有核心旧字段桥接逻辑
|
|
- 删除所有 `activeFlowId === 'kiro'` / `activeFlowId === DEFAULT_ACTIVE_FLOW_ID` 的核心结构分支
|
|
- 用新的 canonical contract 测试替换旧兼容写回测试;旧字段只保留导入器测试
|
|
|
|
完成标准:
|
|
|
|
- 仓库里只有 `imports/legacy/` 与其测试还认识旧字段
|
|
- core 只理解“某个已注册 flow”,不理解“OpenAI 还是 Kiro”
|
|
|
|
## 13. 实施顺序要求
|
|
|
|
为了避免第三次半重构,本次必须按顺序推进:
|
|
|
|
1. 先收口 contract
|
|
2. 再统一 settings
|
|
3. 再统一 runtime
|
|
4. 再建立导入转换器
|
|
5. 再拆 flow registry/source/driver
|
|
6. 再统一 sidepanel
|
|
7. 再迁目录和文件名
|
|
8. 最后删旧字段与旧桥接逻辑
|
|
|
|
禁止的做法:
|
|
|
|
- 先新增第三个 flow,再回头修 core
|
|
- 先重命名文件,但 contract 仍旧双轨
|
|
- 为了快,继续在 sidepanel 或 background 增加新的 `openai / kiro / new-flow` 三分支
|
|
- 一边写 canonical 结构,一边继续保留旧字段双写
|
|
- 让旧配置在启动时被直接读取并“尽量凑合可用”
|
|
|
|
## 14. 完成判定
|
|
|
|
本次重构只有在满足以下条件时才算完成:
|
|
|
|
- 新增一个新 flow 时,不需要修改 `settings-schema` 核心结构。
|
|
- 新增一个新 flow 时,不需要修改 `runtime-state` 核心结构。
|
|
- 新增一个新 flow 时,不需要在 sidepanel 主逻辑中增加 flow 名称判断分支。
|
|
- 新增一个新 flow 时,不需要在 `source-registry` core 里写新 host 判断。
|
|
- OpenAI 与 Kiro 都已经迁入统一命名体系。
|
|
- `background.js`、`background/message-router.js`、`sidepanel/sidepanel.js` 的正常运行路径不再读写 `panelMode`、`openaiIntegrationTargetId`、`kiroTargetId`、`kiroRuntime`。
|
|
- 旧配置文件不能直接运行,只能通过导入转换器进入新结构。
|
|
- 旧运行态快照不再支持恢复。
|
|
- 历史旧字段只允许存在于 `imports/legacy/` 及其测试中。
|
|
|
|
## 15. 非目标
|
|
|
|
本方案当前不解决:
|
|
|
|
- 新增具体第三个 flow 的业务实现
|
|
- OpenAI 私有流程本身的业务优化
|
|
- Kiro 私有流程本身的业务优化
|
|
- 所有公共工具立即物理迁移到 `core/` 目录
|
|
- 旧配置的自动无感兼容启动
|
|
- 旧运行态快照的兼容恢复
|
|
|
|
本方案只解决“以后再加 flow 时,不要再从根上出结构问题”。
|
|
|
|
## 16. 最终结论
|
|
|
|
这次重构必须被当成一次“彻底替换式升级”,不是普通功能开发。
|
|
|
|
如果继续在现有 `openai + kiro` 双轨基础上补第三个 flow,后续仍会再次进入:
|
|
|
|
- core 继续膨胀
|
|
- 命名继续污染
|
|
- 兼容层继续叠加
|
|
- 每次改动都更累
|
|
|
|
因此本次必须一次性完成:
|
|
|
|
- 统一 contract
|
|
- 统一命名
|
|
- 统一目录边界
|
|
- 删除长期双轨
|
|
- 取消旧配置运行时兼容
|
|
- 只保留单向导入转换器
|
|
|
|
完成后,后续 flow 才能真正变成“新增模块”,而不是“继续改核心”;旧世界也只能通过导入器进入新世界,而不能再反向定义新系统的结构。
|
|
|