796 lines
41 KiB
Markdown
796 lines
41 KiB
Markdown
# Bot 转发通道完整实现计划
|
||
|
||
本文用于把工作分配给多个 Agent 分步实现。本文是设计及任务约束,不代表功能已经实现。
|
||
|
||
工作区根目录:`/home/wupeng/Project/mf_v3`。
|
||
|
||
## 1. 目标与边界
|
||
|
||
用户在 Web 请求连接某个 Bot 的转发通道,主服务器鉴权并确认 Node 在线后,命令 Node 连接转发服务器。Node 成功入房并准备好请求处理后,主服务器返回 Web 连接地址与 Web 专用凭证。Web 经转发服务器查询状态、订阅事件及执行白名单交互。
|
||
|
||
必须满足:
|
||
|
||
- 任意 `bot_status` 均允许申请转发通道,包括 `offline`、`ready`、`connecting`、`online`、`disconnecting`、`reconnecting`。
|
||
- 不存在 BotContext 也允许建立通道,查询结果为 `offline`、`context_exists: false`。
|
||
- Node 必须是主服务器当前已认证、在线且能接收命令的节点会话。
|
||
- 建立或恢复转发连接不得调用 `start_bot_context()`,不得重置 Minecraft 自动重连次数。
|
||
- `stop_bot` 只销毁 BotContext,转发通道保持,前端收到 `offline`。
|
||
- 再次启动 Bot 后,通道自动绑定新 BotContext,无需重新连接 Web Socket。
|
||
- Node 和 Web 使用不同角色凭证;Web 不能伪装 Node,不能向其他 Web 广播。
|
||
- 命令响应只返回请求方;只允许白名单事件和业务方法。
|
||
- 每一个连接、入房、请求及关闭过程都有超时、取消及身份检查。
|
||
- 本次实现统一升级协议,不增加旧协议兼容分支。
|
||
- Bot 游戏状态、Node 在线状态、转发连接状态分别维护,禁止互相覆盖。
|
||
|
||
首版转发支持:快照、日志读取、事件订阅、取消订阅、在线聊天。启动、停止、配置修改继续走主服务器现有接口,不在转发层复制一套生命周期入口。
|
||
|
||
## 2. 当前源码问题与处理归属
|
||
|
||
以下是设计时确认的源码问题,实施前应重新核对文件现状和行号。
|
||
|
||
| 问题 | 位置 | 归属任务 |
|
||
| --- | --- | --- |
|
||
| handler 参数 `socket` 与局部变量重复,缺少 `io` 导入,动态加载可能导致 Node 启动失败 | `node_server/event_handler/bot/forward_bot.ts` | D |
|
||
| 分发器忽略所有 `forward_` 开头事件,导致 `forward_bot` 被静默丢弃 | `node_server/event_handler/init.ts` | D |
|
||
| HTTP 转发路由缺少开头 `/`,校验后没有响应及命令流程 | `main_server/router/node/action.ts` | E |
|
||
| 转发房间不区分 Node/Web,任意事件广播给所有其他成员 | `forward_server/index.ts` | B |
|
||
| 将原始 ACK 函数传给房间广播,实际变成广播 ACK,语义和超时错误 | `forward_server/index.ts` | B |
|
||
| token 只有 `node_id`、`bot_id`,没有角色、有效期及会话作用域 | `forward_server/types.ts` 和 token 工具 | A、B、E |
|
||
| 把转发服务启动 ID 当作执行 Node ID,内置服务 `-1` 与实际节点不匹配 | `forward_server/index.ts`、`main_server/index.ts` | B、G |
|
||
| 重复加入新房间后没有离开旧房间 | `forward_server/index.ts` | B |
|
||
| 服务单例并发初始化、监听端口错误、关闭清理和单例复位不完整 | `forward_server/index.ts` | G |
|
||
| 转发服务注册表不清理死连接,重复注册可能断开共享 Node 控制 Socket | `main_server/runtime/forward_server/socket.ts` | G |
|
||
| BotContext 注册表缺少查询、创建、移除通知;直接绑定一个 Bot 实例无法跨重建保持 | `node_server/bot/instance/index.ts` | C |
|
||
| `BotContext.onAny()` 没有对应解绑入口;原始事件可能包含完整 Bot 对象 | `node_server/bot/instance/bot_instance_init.ts` | C、D |
|
||
| 跨域、公开地址、TLS 和反向代理未形成明确配置 | 转发服务启动配置 | G、F |
|
||
|
||
AES-GCM 解密已有完整性校验,不应把问题误写成“token 没有验签”。问题是缺少声明验证、角色隔离、到期和撤销机制。没有证据说明当前公开 HTTP DTO 已泄漏转发密钥,新接口仍必须显式投影公开字段。
|
||
|
||
## 3. 推荐端到端时序
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant W as Web
|
||
participant M as Main
|
||
participant N as Node
|
||
participant F as Forward
|
||
W->>M: POST /api/user/node/forward_bot {bot_id}
|
||
M->>M: 用户/Bot归属/节点与转发权限/当前Node会话
|
||
M->>F: forward_open_session
|
||
F-->>M: 控制ACK
|
||
M->>N: forward_bot(作用域、地址、Node凭证、截止时间)
|
||
N->>F: Socket.IO connect + join_room(node)
|
||
F-->>N: join ACK
|
||
N->>N: 注册请求处理及Bot上下文订阅
|
||
N-->>M: joined:true ACK
|
||
M->>M: 再次核对当前Node会话及Bot归属/分配
|
||
M-->>W: 公开URL/path/namespace + Web凭证
|
||
W->>F: connect + join_room(web)
|
||
F-->>W: join ACK + node_ready
|
||
W->>F: relay_request(bot.snapshot)
|
||
F->>N: relay_request(内部关联ID)
|
||
N-->>F: 定向ACK
|
||
F-->>W: 定向ACK
|
||
N-->>F: bot_event
|
||
F-->>W: 已授权且已订阅的Web
|
||
```
|
||
|
||
`forward_open_session` 由已经认证的主服务器与转发服务控制通道发送。不能由 Web Socket 调用。
|
||
|
||
## 4. 任务 A:协议约定与各项目本地实现清单
|
||
|
||
### 4.1 文件所有权
|
||
|
||
不新增根目录共享协议目录或公共包,也不要求各项目跨目录引用类型、校验器或 token 工具。每个项目使用自己的类型、工具和测试目录,沿用现有结构。
|
||
|
||
本文件是多 Agent 协作时的通信协议约定,不是运行时依赖。相同协议类型允许在各项目本地定义,但事件名、字段、错误码、时间单位和验证行为必须一致。
|
||
|
||
建议落点及文件所有权:
|
||
|
||
| 项目 | 本地类型与校验 | 凭证工具 | 实现 owner |
|
||
| --- | --- | --- | --- |
|
||
| `forward_server` | 沿用 `types.ts`,校验与常量放本项目工具目录 | 沿用 `utils/token_utils.ts`,负责验证 | B;启动校验由 G 接入 |
|
||
| `node_server` | 在现有 `types/`、`utils/` 中定义节点命令、ACK 和事件 DTO | 节点转发客户端只使用 Main 下发的 token,不为远程转发服务签发凭证 | D;C 提供观察事件接口 |
|
||
| `main_server` | 在现有 `types/`、`utils/` 中定义控制协议和 HTTP DTO | 沿用 `utils/token_utils.ts`,负责签发 | E;控制接入由 G 负责 |
|
||
| `main_server_web` | 在现有类型/API目录中定义浏览器所需类型和响应检查 | 不包含密钥、签发或服务端解密工具 | F |
|
||
|
||
A 只整理并冻结文档中的协议、字段归属、校验规则及测试向量,不提前创建或占用 B/D/E/F 负责的生产文件。各 Agent 只实现本项目实际使用的部分,不必复制无关服务端类型。
|
||
|
||
不得为此引入跨项目源码别名、新 workspace 包、代码生成或改变项目构建结构。协议校验不依赖数据库、BotContext 或 UI 框架;服务端密钥工具禁止进入前端 bundle。
|
||
|
||
协议变更先更新本文件并通知受影响的 owner,再分别同步各项目本地实现。H 通过共同的合法/非法消息样例、token 测试向量及跨服务联调验证一致性,不能仅凭本地 TypeScript 类型检查判断网络协议兼容。
|
||
|
||
### 4.2 身份与时间约定
|
||
|
||
| 字段 | 定义 |
|
||
| --- | --- |
|
||
| `forward_id` | 转发服务 ID,非负安全整数,内置服务为 `0` |
|
||
| `node_id`、`bot_id`、`user_id` | 正安全整数 |
|
||
| `node_session_id` | Main 当前认证的 Node 会话标识,不由浏览器提供 |
|
||
| `forward_session_id` | Main 分配的转发通道 UUID,独立于 Socket.IO `socket.id` |
|
||
| `grant_id` | 单个浏览器授权的 UUID,不同标签页独立 |
|
||
| `request_id` | 一次业务请求的 UUID |
|
||
| `context_generation` | 每次 BotContext 创建的新 UUID;无上下文时为 `null` |
|
||
| `stream_id` | 节点事件流 UUID;Node 重启或流重建时改变 |
|
||
| `seq` | 同一 `stream_id` 内递增的安全整数 |
|
||
| `*_at`、`*_before` | Unix 毫秒时间戳 |
|
||
|
||
Bot 状态类型不包含 `disposed`。销毁是内部终止标记,公开状态为 `offline`。
|
||
|
||
### 4.3 Socket ACK
|
||
|
||
```ts
|
||
type ForwardAck<T> =
|
||
| {status: 'success'; data: T}
|
||
| {status: 'error'; data: {
|
||
code: ForwardErrorCode;
|
||
message: string;
|
||
retryable: boolean;
|
||
}};
|
||
|
||
type ForwardErrorCode =
|
||
| 'INVALID_REQUEST' | 'UNAUTHORIZED' | 'FORBIDDEN'
|
||
| 'NODE_OFFLINE' | 'RELAY_UNAVAILABLE' | 'SESSION_STALE'
|
||
| 'TOKEN_EXPIRED' | 'TIMEOUT' | 'CANCELLED'
|
||
| 'NO_CONTEXT' | 'BOT_NOT_ONLINE' | 'RATE_LIMITED'
|
||
| 'RESYNC_REQUIRED' | 'INTERNAL_ERROR';
|
||
```
|
||
|
||
转发业务统一采用这个 ACK;现有 `register_node` 等控制协议不在 A 中整体重写。HTTP 层沿用项目响应包装,并显式映射错误,不调用只适配旧数字 `data` 的辅助函数来解析新 ACK。
|
||
|
||
### 4.4 Main → Node 命令
|
||
|
||
事件 `forward_bot`:
|
||
|
||
```ts
|
||
interface ForwardBotCommand {
|
||
request_id: string;
|
||
forward_session_id: string;
|
||
node_session_id: string;
|
||
forward_id: number;
|
||
node_id: number;
|
||
bot_id: number;
|
||
user_id: number;
|
||
deadline_at: number;
|
||
relay: {
|
||
url: string;
|
||
path: string;
|
||
namespace: string;
|
||
token: string;
|
||
};
|
||
}
|
||
|
||
interface ForwardBotReady {
|
||
request_id: string;
|
||
forward_session_id: string;
|
||
node_session_id: string;
|
||
forward_id: number;
|
||
node_id: number;
|
||
bot_id: number;
|
||
joined: true;
|
||
}
|
||
```
|
||
|
||
`ForwardAck<ForwardBotReady>` 成功表示 Node 已入房、业务请求处理器已安装、上下文观察已建立;不要求存在 BotContext,也不代表 Minecraft 在线。
|
||
|
||
### 4.5 入房及续期
|
||
|
||
```ts
|
||
interface JoinRoomRequest {token: string}
|
||
|
||
interface JoinRoomReady {
|
||
forward_session_id: string;
|
||
forward_id: number;
|
||
node_id: number;
|
||
bot_id: number;
|
||
role: 'node' | 'web';
|
||
node_ready: boolean;
|
||
expires_at: number;
|
||
}
|
||
```
|
||
|
||
事件 `join_room` 使用 `ForwardAck<JoinRoomReady>`。作用域全部从受保护 token 取得,不相信客户端另传的房间名、角色和 Bot ID。
|
||
|
||
事件 `reauth` 接收 `{token: string}`,返回同一作用域的更新凭证结果。续期不得改变角色、Bot、Node、会话或 Web `grant_id`;变更这些字段必须重新建立授权。
|
||
|
||
### 4.6 Token 声明
|
||
|
||
```ts
|
||
interface RelayClaims {
|
||
v: 1;
|
||
forward_id: number;
|
||
forward_session_id: string;
|
||
node_session_id: string;
|
||
node_id: number;
|
||
bot_id: number;
|
||
role: 'node' | 'web';
|
||
user_id?: number;
|
||
grant_id?: string;
|
||
permissions: RelayMethod[];
|
||
issued_at: number;
|
||
join_before: number;
|
||
expires_at: number;
|
||
jti: string;
|
||
}
|
||
```
|
||
|
||
默认策略:新 token 在 60 秒内可用于入房或 reauth,连接授权最长 5 分钟,到期前 60 秒续期。时间参数集中定义,可配置;所有端使用相同毫秒单位,允许有限时钟偏差。
|
||
|
||
验证顺序:大小与格式 → GCM 完整性 → JSON 字段 → 版本/服务 audience → 时间 → 控制通道登记的有效会话 → 角色/权限/浏览器 grant。
|
||
|
||
Node token 不带 Web grant;Web token 必须带 `user_id`、`grant_id`。Main 与指定转发服务共享服务端密钥,密钥不得进入 Node 命令、公开响应或日志;Node 只获得受限 token,不获得转发密钥。Node 自己提供内置转发服务时,只能持有它本来配置的本地服务密钥,不能借此取得其他转发服务密钥。Node 不能仅通过解码把 token 当成已验证身份,最终有效性由转发服务 ACK 确认。
|
||
|
||
### 4.7 业务 RPC
|
||
|
||
```ts
|
||
type RelayMethod =
|
||
| 'bot.snapshot' | 'bot.logs'
|
||
| 'bot.subscribe' | 'bot.unsubscribe' | 'bot.chat';
|
||
|
||
interface RelayRequest {
|
||
request_id: string;
|
||
method: RelayMethod;
|
||
payload: unknown;
|
||
}
|
||
```
|
||
|
||
Web 发送 `relay_request` 并等待 ACK。转发服务为它分配内部关联 ID,只对当前 Node Socket 发单目标 `emitWithAck`;Node 的响应由转发服务校验后返回原 Web ACK。禁止把 Web 的 ACK 函数传进房间广播。
|
||
|
||
每个内部关联记录绑定 Web Socket、grant、Node Socket 版本及超时。Web 的 `request_id` 仅在对应 grant 内唯一,不直接作为全局 Map 键。
|
||
|
||
`bot.subscribe` 参数为 `{events: BotEventName[]}`,整体替换当前 Web 的订阅集;重复请求幂等。`bot.unsubscribe` 删除给定事件,空数组不影响其他事件。订阅默认空,Web 入房后显式设置。
|
||
|
||
`bot.logs` 参数为 `{stream_id?: string, after_seq?: number, limit: number}`,限制 1 到 200;传 after_seq 时必须携带 stream_id。流已更换或缓存不覆盖请求区间时返回 `RESYNC_REQUIRED` 或明确 `truncated: true`,不得伪装完整记录。响应包含本次 stream ID、读取水位、记录及是否截断。
|
||
|
||
`bot.chat` 参数为 `{message: string}`,限制为非空字符串和可配置长度。Node 再次检查上下文及当前实例在线;不自动重放。
|
||
|
||
### 4.8 快照及事件
|
||
|
||
```ts
|
||
interface BotSnapshot {
|
||
bot_id: number;
|
||
bot_status: BotStatus;
|
||
context_exists: boolean;
|
||
context_generation: string | null;
|
||
stream_id: string;
|
||
seq: number;
|
||
captured_at: number;
|
||
}
|
||
|
||
type BotEventName = 'status_update' | 'log' | 'message' | 'bot_error';
|
||
|
||
interface BotEvent {
|
||
forward_session_id: string;
|
||
bot_id: number;
|
||
context_generation: string | null;
|
||
stream_id: string;
|
||
seq: number;
|
||
emitted_at: number;
|
||
name: BotEventName;
|
||
payload: unknown;
|
||
}
|
||
```
|
||
|
||
`bot_event` 只允许从 Node 输入,转发给已授权、订阅相应事件的 Web。每种 `payload` 定义具体 DTO,不保留最终的任意 `unknown` 实现。
|
||
|
||
- 状态:`{status: BotStatus, context_exists: boolean}`。
|
||
- 日志:保留项目日志 ID、时间戳和样式 DTO,限制批次数及总字节数。
|
||
- 消息:文本、位置及必要的有界 JSON,禁止直接发送 ChatMessage 类实例。
|
||
- 错误:`{code?: string, message: string}`,生产环境不传完整堆栈和敏感配置。
|
||
|
||
`relay_status` 由转发服务发给 Web,包含 `node_ready` 和原因,不改变 `bot_status`。节点通道未准备好时可允许 Web 入房,但业务请求返回 `NODE_OFFLINE`,不能返回虚假成功。
|
||
|
||
### 4.9 控制通道事件
|
||
|
||
Main 与转发服务器的已认证控制通道支持:
|
||
|
||
- `forward_open_session`:登记/更新作用域、当前 Node 会话及租约,严格幂等。
|
||
- `forward_authorize_grant`:登记/延长浏览器 grant、用户身份、权限和有效期,必须在签发 Web token 并返回前完成。
|
||
- `forward_revoke_session`:关闭指定转发会话,撤销 Node/Web,失败所有等待请求。
|
||
- `forward_revoke_grant`:撤销指定浏览器授权,不关闭其他浏览器。
|
||
- `forward_session_status`:转发服务上报会话就绪/失联信息,绑定当前控制会话。
|
||
|
||
控制 payload 和 ACK 类型在 A 中一并冻结。open/renew 不得覆盖不同 Node 会话的旧作用域而不先撤销旧会话。
|
||
|
||
会话租约上限不得由数据面自行延长;Main 根据仍有效的 grant 续租。转发服务重启丢失内存授权后,Main 先重新登记 session/grant,再允许 Node/Web 恢复入房。
|
||
|
||
### 4.10 A 的验收
|
||
|
||
- 文档明确非法 ID、错误角色、过期 token、错误 audience、缺字段及超大输入的预期结果。
|
||
- 提供无生产密钥的固定 token 测试向量和篡改/跨作用域失败样例,由 B/E 在各项目测试中分别验证。
|
||
- 浏览器 bundle 不包含密钥及 Node token 工具。
|
||
- 所有 Agent 获得事件名、payload、错误码、时间单位与版本的固定清单。
|
||
- 不新增根目录共享协议包,不引入跨项目源码依赖;本地类型和校验的 owner 已明确。
|
||
|
||
## 5. 任务 B:实现转发服务器的数据路由与鉴权
|
||
|
||
### 5.1 文件所有权与依赖
|
||
|
||
依赖 A;与 G 在接口冻结后并行。
|
||
|
||
B 独占 `forward_server` 新增的 room/session/router/auth 模块及相关测试。B 不直接改启动入口;向 G 提供 `install_relay_routes(io, session_store)` 和对应清理函数,由 G 接入。
|
||
|
||
已有 `types.ts` 的旧声明由 B 按 A 冻结的文档约定更新为本项目本地类型;不得保留两套含义不同的 token 类型,也不从其他项目导入协议实现。
|
||
|
||
### 5.2 会话存储
|
||
|
||
按 `forward_session_id` 存储:
|
||
|
||
- 固定 `forward_id / node_id / bot_id / node_session_id`。
|
||
- 当前有效 Node Socket 及本地连接 generation。
|
||
- Web Socket 与 grant 的映射、订阅集。
|
||
- 会话及每个 Socket 的授权截止时间。
|
||
- 有界 pending RPC 表。
|
||
- 首个 Web 到达前、最后 Web 离开后的回收定时器。
|
||
|
||
房间名由服务端生成,建议包含 Node、Bot、会话;禁止客户端任意指定 room。可以使用独立 Node/Web 子房间,但 RPC 必须仍按单 Socket 定向。
|
||
|
||
### 5.3 入房
|
||
|
||
1. 连接后启动 10 秒未鉴权截止定时器。
|
||
2. 要求有效 ACK 回调,校验 token 和登记会话。
|
||
3. 同一 Socket 只能绑定一个不可变作用域;相同入房请求幂等返回,不累积其他房间。
|
||
4. Node 同作用域最多一条有效上行连接。新连接入房成功后才替换旧连接,并递增 generation。
|
||
5. 旧连接断开回调只能清理自己拥有的记录,不能清空新连接。
|
||
6. Web grant 和权限写入服务端 `socket.data`,不相信每次消息中的身份字段。
|
||
7. `await socket.join()` 成功后才 ACK。
|
||
8. 成功或断开时清理未鉴权定时器。
|
||
|
||
Node 尚未 ready 时 Web 可入房并收到 `node_ready: false`;HTTP 初次建立仍必须先等 Node ready。此设计处理 HTTP 返回后到 Web 入房之间 Node 又掉线的竞态。
|
||
|
||
### 5.4 RPC 路由
|
||
|
||
1. Web 必须已鉴权,检查 method 权限和对应 payload。
|
||
2. `bot.subscribe/unsubscribe` 在转发服务处理,仅修改本 Web 订阅集。
|
||
3. 其他 method 选择该会话唯一当前 Node Socket。
|
||
4. 分配内部关联 ID,保存请求方和 Node generation。
|
||
5. 对 Node 单目标调用,设置明确 timeout;Node 必须返回完整 `ForwardAck`。
|
||
6. 校验当前 Node 所有权仍一致后,把结果回给原 Web,ACK 只调用一次。
|
||
7. 超时、Web 离开、Node 替换、会话撤销时清理记录,拒绝迟到结果。
|
||
|
||
默认 RPC timeout 5 秒;限制每个 Web 的 pending 数量及速率。请求 ID 去重缓存只保留有界窗口,不能宣称跨进程“恰好一次”。有副作用请求断线后不得自动重发。
|
||
|
||
### 5.5 事件推送
|
||
|
||
- 只接受当前 Node Socket 的 `bot_event`。
|
||
- 校验 Bot、会话、事件白名单、大小和单流递增序号。
|
||
- 发给匹配订阅及权限的 Web,不广播给 Node 或其他房间。
|
||
- 非当前 Node、Web 伪造 `bot_event`、任意未知事件全部拒绝。
|
||
- 不使用 `error` 作为 Bot 业务事件名,避免与 Socket.IO 控制错误混淆。
|
||
|
||
### 5.6 授权与回收
|
||
|
||
- token 到期计时器真正断开已有 Socket;不能只在入房时检查。
|
||
- `reauth` 仅允许延长同一作用域与 grant 的授权,替换到期计时器。
|
||
- 会话撤销及 grant 撤销分别清理对应资源。
|
||
- 初次 Node ready 后 60 秒没有任何 Web 加入,回收未使用会话。
|
||
- 最后一个 Web 离开后保留 30 秒宽限期,再向 Node 通知释放并清理会话。
|
||
- 回收操作核对 generation,不能回收并发建立的新会话。
|
||
|
||
### 5.7 B 的验收
|
||
|
||
- Web A 请求不会被 Web B 接收,响应只给 A。
|
||
- Web 无法伪造 Node、越权换 Bot、调用控制事件。
|
||
- 两个 Web 使用相同 request ID 不冲突。
|
||
- Node 替换后旧 ACK、旧事件和旧 disconnect 不影响新连接。
|
||
- 重复入房不累积房间;过期、断开及回收后无遗留 timer/pending。
|
||
- 默认同步 adapter 和模拟异步 `join` 均在真实入房后 ACK。
|
||
|
||
## 6. 任务 C:节点 BotContext 注册表观察接口
|
||
|
||
### 6.1 文件所有权与依赖
|
||
|
||
依赖 A,可与 B、G 并行。
|
||
|
||
C 独占:
|
||
|
||
- `node_server/bot/instance/index.ts`。
|
||
- `node_server/bot/instance/bot_instance_init.ts` 中注册表观察所需的最小改动。
|
||
- 新增节点 Bot 快照/事件序列化模块。
|
||
- 对应测试。
|
||
|
||
不重写现有 Bot 生命周期、不修改 Minecraft 自动重连插件,不让 D 在这些文件重复实现另一套观察机制。
|
||
|
||
### 6.2 注册表 API
|
||
|
||
建议暴露:
|
||
|
||
```ts
|
||
get_bot_context(bot_id: number): bot_instance_context<any> | undefined;
|
||
observe_bot_context(bot_id: number, listener: ContextObserver): () => void;
|
||
get_bot_snapshot(bot_id: number): BotSnapshot;
|
||
```
|
||
|
||
`observe_bot_context` 注册时应提供当前上下文快照,之后提供创建、替换、状态更新及移除通知;每次通知包含 generation。
|
||
|
||
明确线性化点:创建通知在上下文可查询且状态上报绑定完成后、实际连接前发出;移除通知在该代次最终 `offline` 可观察后发出。初始化失败的短暂上下文也必须解绑,不留下幽灵订阅。
|
||
|
||
可以返回一个订阅对象同时含初始快照和 dispose,避免“先查询后注册”之间漏事件。具体 API 由 C 提前冻结给 D,不得让调用方自己轮询私有 Map。
|
||
|
||
### 6.3 事件桥
|
||
|
||
- 对稳定的 BotContext 订阅 `status_update/log/message/error`,不对某个 mineflayer Bot 长期持有引用。
|
||
- 使用明确事件名及 `off` 解绑;若使用 `onAny`,必须增加匹配的 `offAny` 或 disposer。
|
||
- 不把 `instance_created`、完整 Bot、插件状态对象、配置密钥发往转发层。
|
||
- 新上下文使用新 generation;旧代次回调立即失效。
|
||
- Node 级事件流维护 stream ID、seq 和有界日志缓存,BotContext 销毁不丢失最后 offline 事件。
|
||
- 旧日志明确标注历史 generation;状态事件不得用旧代次覆盖当前状态。
|
||
- 无上下文快照为 `offline/context_exists:false/context_generation:null`,不创建 Bot 来获取日志。
|
||
|
||
### 6.4 C 的验收
|
||
|
||
- 先订阅后启动、先启动后订阅均收到一致快照和后续事件。
|
||
- stop/start 跨上下文替换后订阅自动转移。
|
||
- Minecraft 实例重建不重复绑定、不丢失稳定上下文事件。
|
||
- 解绑后监听器计数恢复;旧回调不修改新 generation。
|
||
- JSON 序列化不会遍历 Bot、循环对象或泄漏代理密码。
|
||
- snapshot 的 seq 与事件水位一致,可供 F 解决快照竞态。
|
||
|
||
## 7. 任务 D:节点转发连接管理器与 forward_bot handler
|
||
|
||
### 7.1 文件所有权与依赖
|
||
|
||
依赖 A、C 的接口,以及 B 的入房/RPC 协议;允许先对协议桩开发。
|
||
|
||
D 独占:
|
||
|
||
- `node_server/event_handler/bot/forward_bot.ts`。
|
||
- `node_server/event_handler/init.ts` 的精确分发规则。
|
||
- 新增 `node_server/runtime/forward/` 或等效独立管理目录。
|
||
- 节点转发 RPC 处理器与测试。
|
||
|
||
`node_server/index.ts` 由 G 独占,D 提供控制连接状态 hook,由 G 调用。不要在 handler 每次执行时创建不受管理的 Socket。
|
||
|
||
### 7.2 管理器接口
|
||
|
||
```ts
|
||
ensure_connected(command: ForwardBotCommand): Promise<ForwardBotReady>;
|
||
release_session(session_id: string, reason: string): Promise<void>;
|
||
on_main_registered(node_session_id: string): Promise<void>;
|
||
on_main_disconnected(): void;
|
||
close_all(): Promise<void>;
|
||
```
|
||
|
||
按 `(forward_id,node_id,bot_id)` 去重,记录当前 forward session、连接代次、pending ensure、Socket、context disposer、定时器和租约。
|
||
|
||
会话状态:`idle / connecting / joining / ready / retry_wait / closed`,不得写入 `bot_status`。
|
||
|
||
### 7.3 ensure_connected
|
||
|
||
1. 校验命令、URL scheme/path、当前 Node ID/会话和截止时间。
|
||
2. 来源必须是主服务器当前已注册控制连接;拒绝旧连接迟到命令。
|
||
3. 同作用域同会话 ready 时幂等返回;若 token 更新,先 reauth 成功再 ACK。
|
||
4. 同会话正在初始化时共享同一个建立任务,各请求保留自己的等待截止时间。
|
||
5. 新会话替代旧会话时取消旧任务、解绑旧观察、关闭旧 Socket。
|
||
6. 创建 Socket 使用 `autoConnect:false`,先安装所有监听器,再 connect。
|
||
7. 每次 `connect` 都发送 `join_room` 并等待 ACK。
|
||
8. 校验 ACK 作用域后安装/确认 RPC 和 C 的观察桥,标记 ready。
|
||
9. 向 Main 返回对应 request ID 的成功 ACK。
|
||
10. 失败路径标准化错误,只执行一次 ACK,清理仅由本会话拥有的资源。
|
||
|
||
多个并发申请共享通道,某一个调用者超时不能直接关闭仍被其他有效申请/授权使用的通道。请求截止与会话租约分别管理,控制租约过期才能回收孤立结果。
|
||
|
||
### 7.4 Node RPC
|
||
|
||
- `bot.snapshot`:从 C 获取一致快照,Bot 离线也成功。
|
||
- `bot.logs`:读取 C 的有界日志缓存;没有上下文时仍可返回已有历史或空列表。
|
||
- `bot.chat`:校验权限和字符串,临执行前核对当前上下文 generation、实例身份和 `online`;否则返回 `NO_CONTEXT/BOT_NOT_ONLINE`。
|
||
- 未知 method 拒绝,禁止根据字符串任意调用 context 方法。
|
||
- 业务事件通过 serializer 后使用 `bot_event` 发送。
|
||
- 主服务器断开期间不接受新的有副作用操作;已有只读订阅可在租约内继续。
|
||
|
||
### 7.5 重连
|
||
|
||
- 转发连接重连独立于主服务器重连和 Minecraft 自动重连插件。
|
||
- 默认指数退避 1 秒到 30 秒,加入随机抖动,最多 8 次;参数集中配置。
|
||
- 只有入房 ACK 成功才重置次数,不以 TCP/Socket.IO connect 为准。
|
||
- 意外 `io server disconnect` 可重试;通过明确的撤销/过期/旧会话错误停止旧凭证重试。
|
||
- 每次重连必须重新入房;不依赖服务端恢复自动恢复权限。
|
||
- token 过期时等待 Main 下发新 token,不能使用旧凭证无限重试。
|
||
- 不缓存并重放 chat;状态恢复靠快照,日志按序补偿。
|
||
- 关闭/替换时先递增连接代次,使排队回调失效,再清理 timer、监听器、观察桥和 Socket。
|
||
|
||
### 7.6 handler 与分发修复
|
||
|
||
- 主控制 Socket 命名为 `main_socket`,转发客户端为 `relay_socket`。
|
||
- 修复重复声明并导入正确的 `io`。
|
||
- 将广泛的 `startsWith('forward_')` 忽略改为明确的控制事件路由,确保 `forward_bot` 可执行。
|
||
- 转发数据 Socket 使用独立白名单 handler,不把它接进主服务器命令的全量 dispatcher。
|
||
- 保持 Node 启动时所有 handler 可正常导入。
|
||
|
||
### 7.7 D 的验收
|
||
|
||
- 所有 Bot 状态及无上下文均能建立转发通道,不产生 Minecraft 连接动作。
|
||
- 两个并发 ensure 只创建一个 Socket,超时调用者不误关闭共享会话。
|
||
- 重连时重新入房但不重复绑定上下文事件。
|
||
- stop/start 只改变 Bot 快照,转发连接保持。
|
||
- 旧命令、旧 ACK、旧重试回调均不能污染新连接。
|
||
- 超时、租约到期、手动释放和进程关闭无监听器或定时器泄漏。
|
||
|
||
## 8. 任务 E:主服务器 HTTP 编排、授权、续期与撤销
|
||
|
||
### 8.1 文件所有权与依赖
|
||
|
||
依赖 A;B、D 协议冻结后可并行开发,最终集成依赖 G 的健康注册表。
|
||
|
||
E 独占:
|
||
|
||
- `main_server/router/node/action.ts`。
|
||
- 新增主服务器转发业务 service、会话与 grant 存储。
|
||
- 相关权限 helper 的必要提取及测试。
|
||
- HTTP 续期和释放接口。
|
||
|
||
E 不直接修改 G 所有的转发注册表及启动入口,使用 G 暴露的健康连接及控制命令 API。
|
||
|
||
### 8.2 初次申请
|
||
|
||
接口:`POST /api/user/node/forward_bot`,body 严格为 `{bot_id}`。
|
||
|
||
1. 检查用户会话、账号有效性和请求数据。
|
||
2. 用 `query_bot_info(user_id,bot_id)` 或等效逻辑检查 Bot 归属。
|
||
3. 检查对应 Node/团队/转发资源权限,但不检查 Bot 游戏状态、版本、代理可用性或启动队列。
|
||
4. 使用 `get_node_server_socket()` 获取当前可命令 Node,不仅看缓存 ONLINE。
|
||
5. 按 `(forward_id,node_id,bot_id,node_session_id)` 查找/创建通道,合并建立任务。
|
||
6. 分配浏览器独立 grant,不让不同标签页互相覆盖。
|
||
7. 经 G 的控制通道调用 `forward_open_session`。
|
||
8. 签发 Node token,发送 `forward_bot`,等待完整 ready ACK。
|
||
9. ACK 前后核对相同 Node 当前会话;再次检查 Bot 归属、节点/转发分配及配置版本。
|
||
10. 经控制通道登记该浏览器 grant,成功后签发 Web token,构造公开 DTO 返回。
|
||
|
||
不得把资源授权 helper 返回的完整实体序列化给浏览器,其中可能包含转发密钥。
|
||
|
||
公开 DTO:
|
||
|
||
```ts
|
||
interface ForwardAccess {
|
||
bot_id: number;
|
||
node_id: number;
|
||
forward_id: number;
|
||
forward_session_id: string;
|
||
grant_id: string;
|
||
url: string; // 浏览器可访问的公开地址
|
||
path: string;
|
||
namespace: string;
|
||
token: string; // 仅 Web 角色
|
||
expires_at: number;
|
||
}
|
||
```
|
||
|
||
### 8.3 续期与释放
|
||
|
||
- `POST /api/user/node/forward_bot/renew`,body `{bot_id,forward_session_id,grant_id}`。
|
||
- `POST /api/user/node/forward_bot/release`,body `{bot_id,forward_session_id,grant_id}`。
|
||
- 两者都验证登录会话、Bot 归属、grant 所有权及当前资源分配,不能仅凭 grant ID 操作。
|
||
- renew 先延长控制会话,再对 Node ensure/reauth 成功,登记更新后的 grant,最后签发 Web 新 token。
|
||
- renew 若发现 Node 会话/转发分配变化,返回 `SESSION_STALE`,前端重新初次申请。
|
||
- release 幂等撤销本 grant,立即通知转发层;不关闭其他 grant 使用的通道。
|
||
- 主服务器可依据有效 grant 延长 Node 会话租约,但不得绕过账号/资源复核。
|
||
- 浏览器异常关闭无法保证 release 到达,仍由租约和 B 的空闲回收兜底。
|
||
|
||
用户退出、权限撤销、Bot 删除、节点迁移、Node 控制会话替换时撤销对应 grant 或通道。首次实现只要求覆盖项目已有这些操作的入口,避免创建一个永不调用的撤销 API。
|
||
|
||
### 8.4 超时、幂等与失败
|
||
|
||
- Node 建立总预算 8 秒,Main 等待 10 秒,HTTP 总预算 12 秒,前端约 15 秒。
|
||
- 所有等待包含排队时间,不逐阶段无限叠加 timeout。
|
||
- 在 HTTP 超时后不返回凭证。迟到成功只能保留在有效租约/其他申请仍使用的共享通道内。
|
||
- 不把转发建立加入持久化的离线 Bot 停止队列。
|
||
- Node 离线与转发不可用使用不同错误。
|
||
- 沿用当前 HTTP 响应 envelope,错误码映射由 E 明确写测试并向 F 发布。
|
||
- 进程重启不假装恢复内存会话:旧租约过期/撤销,Web 重新申请。
|
||
|
||
### 8.5 E 的验收
|
||
|
||
- foreign Bot、无权限 Node、离线 Node 不能获取凭证。
|
||
- offline Bot 和无运行上下文不阻止申请。
|
||
- 非当前 Node 的成功 ACK 不被采纳。
|
||
- 等待期间 Bot 被迁移/删除或权限撤销不会返回可用旧凭证。
|
||
- 并发标签页共用上行但各有独立 grant,释放一个不影响另一个。
|
||
- 公开响应没有 Node token、密钥、内部地址或数据库实体泄漏。
|
||
|
||
## 9. 任务 F:前端转发客户端与页面接入
|
||
|
||
### 9.1 文件所有权与依赖
|
||
|
||
依赖 A、E 的 HTTP 约定及 B 的 Socket 协议。F 独占 `main_server_web` 中新增转发 API、连接管理模块、状态展示和相关测试。
|
||
|
||
不要把现有 Main Socket 和转发 Socket 混成同一个全局变量,也不要修改 Minecraft Bot 状态来表达转发断线。
|
||
|
||
### 9.2 客户端生命周期
|
||
|
||
1. 用户打开 Bot 交互页或显式连接时申请 ForwardAccess。
|
||
2. 保存页面/账号/Bot 的请求 generation,丢弃迟到的旧响应。
|
||
3. 用返回的 URL/path/namespace 创建 Socket,先安装监听器。
|
||
4. connect 后 join_room,成功后才启用交互操作。
|
||
5. 设置事件订阅,再请求 snapshot,同步完成前缓冲实时事件。
|
||
6. 账号退出、切换 Bot、离开页面时取消 pending、移除监听器、关闭 Socket,尽力 release grant。
|
||
|
||
连接状态建议:`idle / requesting / connecting / joining / syncing / ready / retrying / expired / error`。
|
||
|
||
同页多个组件共用一个会话客户端,组件卸载采用引用计数,不各建一条 Socket。不同标签页使用独立 grant。
|
||
|
||
### 9.3 快照与事件顺序
|
||
|
||
- 订阅后暂存事件,再请求快照,防止入房前首次状态丢失。
|
||
- 快照携带 stream ID 和 seq 水位,先应用快照,再应用同流中 seq 更大的缓冲事件。
|
||
- 流改变时丢弃旧流缓冲,重新同步,不能跨流比较 seq。
|
||
- context generation 改变时重置当前上下文视图,历史日志仍可按 generation 显示。
|
||
- seq 用于去重与快照水位,按事件订阅过滤后不保证连续,不能把自然跳号误判成丢包。由服务端显式 resync 通知、日志缓存截断或 `RESYNC_REQUIRED` 触发快照/日志重新同步。
|
||
- UI 不把 `node_ready:false` 显示成 Bot 已 offline,分别展示通道状态和 Bot 状态。
|
||
|
||
### 9.4 重连与凭证
|
||
|
||
- 网络断线采用有限退避,connect 后必须重新 join。
|
||
- 凭证在 expires_at 前 60 秒 renew,成功后调用 reauth,不必断开整个 Socket。
|
||
- 过期、SESSION_STALE 时重新走 HTTP 初次申请,不使用旧 token 无限重试。
|
||
- 服务端明确撤销授权时停止自动重试并提示重新授权,不能无条件重连绕过撤销。
|
||
- snapshot、日志读取可显式重试;chat 不能在 ACK 超时后自动重发。
|
||
- 切换 Bot 后旧 ACK、旧事件、旧 HTTP 响应不能更新新页面。
|
||
|
||
### 9.5 F 的验收
|
||
|
||
- Bot 离线页面可连接并展示 `context_exists:false`。
|
||
- 多标签页互不收到对方命令内容或私有响应。
|
||
- 停止/再次启动 Bot 后无需重连页面,即可显示新状态。
|
||
- 短断线、token 续期、主服务器重新分配转发地址均可恢复。
|
||
- 页面快速切换、重复挂载卸载不增加 Socket/监听器数量。
|
||
- 保持现有设计系统,桌面和移动端可用,不为此重做无关页面。
|
||
|
||
## 10. 任务 G:服务启动、控制注册表与部署配置
|
||
|
||
### 10.1 文件所有权与依赖
|
||
|
||
依赖 A,与 B/C 并行。G 是以下共享入口的唯一修改者:
|
||
|
||
- `forward_server/index.ts` 和现有控制 runtime 入口。
|
||
- `main_server/index.ts`。
|
||
- `main_server/runtime/forward_server/socket.ts` 及控制注册 handler。
|
||
- `node_server/index.ts` 中与控制认证会话及进程关闭相关的集成。
|
||
- 所需配置、配置校验和生命周期测试。
|
||
|
||
注意:`node_server/forward_server`、`main_server/forward_server` 可能引用同一份共享源码。实施前确认实际路径,不把别名当成独立文件让不同 Agent 同时编辑。
|
||
|
||
### 10.2 转发服务启动/关闭
|
||
|
||
- 使用共享初始化 Promise,避免 await 前检查单例造成并发启动。
|
||
- 等待 owned HTTP server 的 listening,处理端口占用与启动失败。
|
||
- 明确 HTTP server 所有权:内置服务借用 Main 的 HTTP server,停止转发功能不能意外关闭主站。
|
||
- 显式 stop API 清理 B 的会话、pending、监听器、定时器,再释放自有服务。
|
||
- 停止后复位单例和初始化状态,允许受控重启。
|
||
- 不依赖未保证存在的 Engine.IO server `close` 事件作为唯一清理入口。
|
||
- 启动参数明确为 forward ID,不继续使用 `-1` 充当执行 Node 身份。
|
||
- 密钥缺失时启动失败,取消已知字符串兜底。
|
||
|
||
### 10.3 Main 注册表
|
||
|
||
- 同一当前连接重复注册同一转发服务幂等成功。
|
||
- 注册准备完成后才加入健康表并 ACK,初始化失败必须返回失败。
|
||
- 保存 cleanup disposer;断开时仅删除仍由该连接持有的记录。
|
||
- 健康查询不返回已断开的 Socket。
|
||
- origin 1 借用 Node 控制 Socket,移除转发登记不能直接 disconnect 整个 Node。
|
||
- origin 0 的 EventEmitter 不能调用不存在的 disconnect。
|
||
- 替代时间戳猜测,使用明确注册 generation/节点会话所有权。
|
||
- 暴露供 E 使用的当前转发健康查询、控制命令及撤销方法。
|
||
|
||
### 10.4 控制链路恢复
|
||
|
||
- Main/Node 控制连接成功认证后,通知 D 当前 node_session_id。
|
||
- 主服务器短断线时,已有转发只读通道可存活到租约到期,禁止新有副作用请求。
|
||
- Main 重新认证产生新 Node 会话时,旧转发会话被替换/撤销,Web 重新申请。
|
||
- 内置转发使用进程内 EventEmitter 也必须遵守相同控制协议、ACK 和清理契约。
|
||
- 外部控制连接必须先认证,数据 Socket 不得调用控制事件。
|
||
|
||
Node 自带转发服务时,共用的 Main-Node 控制 Socket 需要同时路由 Node 命令和本地转发控制事件。G 与 D 采用明确事件表及独立 disposer,不得让修复 `forward_` 前缀过滤后,同一个控制事件被两套 handler 重复执行。Main 内置 EventEmitter 使用相同 request/ACK 适配,但不依赖 Socket.IO 才有的 timeout/disconnect 方法。
|
||
|
||
### 10.5 地址和部署
|
||
|
||
每个转发服务配置分别包含:
|
||
|
||
- `node_url`:Node 可访问地址。
|
||
- `public_url`:浏览器可访问地址。
|
||
- `path`、`namespace`。
|
||
- 明确允许的 Web Origin。
|
||
- TLS/反向代理配置及载荷限制。
|
||
|
||
HTTPS 页面必须使用可访问的 HTTPS/WSS 入口;Socket.IO 客户端传 HTTP(S) URL,不把 path 拼成错误 namespace。默认 polling 与 WebSocket 都应通过代理,不能以强制 WebSocket 掩盖未配置的跨域问题。
|
||
|
||
首版限定每个转发实例单进程。未来多进程需要共享唯一 Node 所有权、会话、pending 路由及 adapter;只加 Redis 房间广播不等于完成横向扩展。
|
||
|
||
### 10.6 G 的验收
|
||
|
||
- 并发启动只创建一个服务,端口占用不返回成功。
|
||
- 关闭再启动可用,借用 Main HTTP server 时不误关主站。
|
||
- 重复注册不踢掉 Node;旧 disconnect 不删除新注册。
|
||
- 内置与外部转发使用相同作用域规则。
|
||
- Node 初始化过程中 `forward_bot` handler 可正常导入。
|
||
- 浏览器默认连接方式能通过配置的公开域名和代理连接。
|
||
|
||
## 11. 任务 H:集成测试、故障注入与交付核对
|
||
|
||
### 11.1 文件所有权
|
||
|
||
H 独占跨服务集成测试目录及测试运行说明。生产文件修改归原 owner,H 发现问题后给证据和复现,不跨范围修复同一文件。
|
||
|
||
建议使用可控 Main、真实 Socket.IO relay 和模拟 BotContext,避免依赖公网 Minecraft 服务。时间相关使用可控时钟,额外保留至少一组真实网络连接测试。
|
||
|
||
### 11.2 必测矩阵
|
||
|
||
| 类别 | 场景 | 期望 |
|
||
| --- | --- | --- |
|
||
| Bot 状态 | 六种状态及无上下文 | 均允许申请,状态真实,不触发 start |
|
||
| 权限 | 未登录、他人 Bot、无 Node/转发资源权限 | 拒绝,不签发有效凭证 |
|
||
| Node | 离线、会话替换、等待期间断开 | 不返回旧连接成功 |
|
||
| 角色 | Web 伪造 Node、伪造事件、控制消息 | 拒绝 |
|
||
| 作用域 | 跨 Bot、跨 Node、跨 relay、旧 session token | 拒绝 |
|
||
| 入房 | 重复、不同 room、异步 join | 幂等或明确拒绝,ACK 时已入房 |
|
||
| RPC | 两 Web 相同请求 ID、超时、迟到 ACK | 不串响应,不泄漏 pending |
|
||
| RPC | Node 在执行期间替换 | 旧响应失效,有副作用请求不自动重放 |
|
||
| 生命周期 | Bot stop/start、实例 Minecraft 重连 | 通道保持,订阅跟随新上下文 |
|
||
| 事件 | 首次状态、快照期间事件、序号缺口 | 一致同步,不让旧状态覆盖新状态 |
|
||
| 重连 | Node-relay、Web-relay、Main-Node 分别断开 | 独立恢复,重新入房,无重复监听 |
|
||
| 凭证 | 到期前续期、已连接后到期、撤销 | 正确续期或断开,不能永久授权 |
|
||
| 并发 | 两标签页同时申请、一个超时/关闭 | 一条上行,各自授权,不误关共享连接 |
|
||
| 回收 | 浏览器从未到达、最后浏览器离开、进程退出 | timer/Socket/listener/pending 回收 |
|
||
| 部署 | 内置 relay、外部 relay、HTTPS、跨域 polling | 全流程可用 |
|
||
| 容量 | 日志洪峰、慢客户端、恶意 pending | 限流/截断明确,内存有界 |
|
||
|
||
### 11.3 检查与交付
|
||
|
||
- 各服务类型检查通过,前端构建通过。
|
||
- 单元测试、Socket.IO 集成测试通过。
|
||
- 每个 Agent 列出修改文件、协议变化、执行的命令及未覆盖风险。
|
||
- 明确区分“transport connected”“joined”“node ready”“Bot online”。
|
||
- 不把 mock 通过描述成真实生产部署已验证。
|
||
- 验证全过程不输出密钥、token、代理密码或完整用户配置。
|
||
|
||
## 12. 执行依赖与分工顺序
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[A 协议约定冻结] --> B[B 转发数据面]
|
||
A --> C[C Bot注册表观察]
|
||
A --> G[G 启动与控制注册]
|
||
A --> E[E Main业务编排]
|
||
C --> D[D Node转发管理]
|
||
B --> D
|
||
G --> E
|
||
D --> E
|
||
E --> F[F Web接入]
|
||
B --> F
|
||
B --> H[H 集成验收]
|
||
C --> H
|
||
D --> H
|
||
E --> H
|
||
F --> H
|
||
G --> H
|
||
```
|
||
|
||
推荐批次:
|
||
|
||
1. A 先冻结协议,明确全部类型、错误和事件;B/C/G 提前检查接口是否可实现。
|
||
2. B、C、G 并行实现;E/F 可按已冻结协议开发本地桩,不自行变更契约。
|
||
3. C 的观察 API 完成后 D 实现 Node 管理器;B/G 提供真实 relay 联调。
|
||
4. E 接通授权、会话及 HTTP 全流程;F 接入真实 API。
|
||
5. H 执行故障注入和完整验收,原 owner 修复各自模块。
|
||
|
||
不要让 E 和 G 同时修改主服务器启动/注册表,也不要让 C 和 D 同时修改 BotContext 生命周期。
|
||
|
||
## 13. 可直接附给各 Agent 的工作指令
|
||
|
||
```text
|
||
以 FORWARD_IMPLEMENTATION_PLAN.md 为协议和任务边界来源。
|
||
只实现分配给你的任务及文件,不顺手重构其他模块。
|
||
先核对当前源码,保留已有用户修改。
|
||
共享 forward_server 路径可能为别名,先确认真实文件归属。
|
||
不自行更改事件名、字段、时间单位、角色、错误码和权限语义。
|
||
不新增根目录共享协议包,不跨项目引用协议源码;在自己负责的项目内定义必要类型和校验。
|
||
契约有问题时给出具体冲突,由协调 Agent 更新本文,再由受影响 owner 同步本地实现。
|
||
所有异步操作考虑超时、取消、旧会话和回收。
|
||
提供真实验收证据,不以 Socket connect 代替入房成功。
|
||
不得把转发重连实现成重新启动 Bot。
|
||
完成后报告:修改文件、接口、测试、依赖、未完成项和联调注意事项。
|
||
不要提交 Git commit,除非用户另有明确要求。
|
||
```
|
||
|
||
协调 Agent 负责协议冻结、文件所有权、集成顺序和最终验证;各 Agent 的局部测试通过不自动代表端到端交付完成。
|