feat: ship enterprise control and desktop governance

This commit is contained in:
AI Bot
2026-05-11 14:59:26 +08:00
parent 0757d07521
commit a311280238
285 changed files with 48574 additions and 2428 deletions

View File

@@ -0,0 +1,150 @@
# Boss To B 管理后台接入记录
更新时间:`2026-04-27`
## 目标
为 Boss To B 场景新增系统管理后台,供平台侧查看和管理不同客户公司的账号、设备、权限和风险状态,重点支持快速发现客户电脑 Codex 节点掉线、主 Agent 任务失败、线程上下文风险和运维故障。
## 技术选型
- 使用 `@refinedev/core` 作为管理后台资源抽象层。
- 使用 `antd` 原生组件作为后台 UI 组件库。
- 不使用 `@refinedev/antd`,原因是当前版本会传递引入 `@ant-design/pro-layout -> path-to-regexp@8.2.0` 高危 audit 链。
- 不直接接入 `ant-design-pro` 工程,避免把 Umi/Max 路由和权限体系引入现有 `Next.js 16 + App Router` 主工程。
## 企业级后台独立化方向
2026-04-30 起Boss 后台进入独立 PC 管理后台阶段。调研 `YunaiV/yudao-cloud` 后,当前策略是借鉴它的租户、用户、角色、菜单、日志和工作台信息架构,但不直接接入 YuDao 的 Java 微服务后端,避免把现有 `Next.js + 文件状态账本 + local-agent` 运行时拆碎。
第一批新增:
- `apps/boss-admin-web`:独立 Vue + Vite + Ant Design Vue 后台工程,面向平台侧运营和客户成功人员。
- `/api/v1/admin/backoffice`:企业后台 BFF把 Boss 当前账本聚合成 YuDao 风格的菜单、工作台、租户、账号、角色权限、资源授权、Skill 中心、风险和审计数据。
- `/enterprise-admin`Next 主站内的受保护入口,只允许 `highest_admin` 访问,并跳转到独立后台静态产物 `/admin-web/index.html`
- `admin:web:dev` / `admin:web:build` / `admin:web:publish`:根工程脚本入口。`admin:web:publish` 会把 Vue 构建产物写入 `public/admin-web`,随 Next standalone 的 `public` 一起发布。
边界:
- 现有 `/admin` 不删除,继续作为主站内 fallback。
- 独立后台只消费 Admin BFF不直接读取 `boss-state.json`
- 独立后台当前复用 Boss Cookie 登录态,后续再绑定 `admin.boss.hyzq.net` 的独立部署。
- `/api/v1/admin/backoffice` 仍只允许 `highest_admin`,并过滤 `passwordHash``mfaSecret` 和 session token。
## 当前落地范围
- 新增 `/admin` 页面。
- 新增 `/api/v1/admin/overview` 聚合接口。
- 新增 `/api/v1/admin/backoffice` 独立企业后台聚合接口。
- 新增 `/api/v1/admin/risks/actions` 风险处理动作接口。
- 新增 `/api/v1/admin/notifications/dispatch` 风险通知派发接口。
- 新增 `buildAdminOverview(state)` 纯函数,负责从当前文件状态聚合后台数据。
- 新增显式 `adminCompanies` 租户账本,支持把账号和设备直接绑定到客户公司,不再只能依赖账号邮箱域名推断。
当前页面已在 `2026-04-30` 升级为 PC To B 总后台结构,不再是简单的 3 个表格页签。新结构包含 4 个一级区:
- `平台运营驾驶舱`:平台全局健康、待处理风险、客户健康、节点健康、最近事件。
- `客户与账号`:客户公司、账号列表、设备归属和客户开通任务流。
- `授权工作台`:复用既有账号 / 设备 / 项目 / Skill 授权能力,但放在更清晰的权限上下文里。
- `风险与治理`风险战情室、SLA、负责人、修复工单以及 Skill 生命周期治理。
### 平台运营驾驶舱
- 展示今日待处理:客户公司、账号、在线设备、开放风险和风险通知。
- 展示客户健康排行:按开放风险和设备在线情况优先排列。
- 展示关键风险队列:只展示最值得处理的风险,完整队列进入风险战情室。
- 展示节点健康集中查看客户电脑、Codex GUI / CLI 和最近心跳。
- 展示最近事件:风险通知和风险时间线,避免平台侧漏跟进。
### 客户与账号
- 展示客户公司列表、健康状态、账号数、在线设备、开放风险和客户成功负责人。
- 展示客户开通任务流:创建客户公司、开通老板账号、绑定客户电脑、分配项目与 Skill 权限。
- 展示账号列表:账号、角色、公司、状态和最近登录。
- 展示客户设备设备状态、GUI / CLI 在线状态、风险数和最近心跳。
### 授权工作台
- 继续复用 `/api/v1/admin/access`
- 支持创建 / 更新子账号、公司管理、批量导入、账号归属、设备归属、权限模板、设备 / 项目 / Skill 授权和离职回收。
- 高危动作继续保留二次确认和审计记录。
### 风险与治理
- 风险战情室按严重程度、客户影响、负责人和 SLA 组织风险。
- 风险处理不再使用浏览器 `window.prompt`,改成页面内处理面板。
- 处理面板支持指派负责人、设置 SLA、确认、关闭和创建修复工单。
- 对暂不支持动作的风险类型保持只读提示,不假装处置成功。
- Skill 生命周期治理作为同一区域的第二页签,继续复用 `/api/v1/admin/skills/requests`
## 旧版落地范围记录
以下是第一版落地内容,仍保留作为能力来源说明:
### 总览
- 总览统计:公司数、账号数、在线设备、开放风险。
- 风险通知:展示由 SLA 扫描生成的超时通知,避免平台侧只看到风险列表、漏掉需要主动跟进的客户事项。
- 风险时间线:展示风险通知生成、派发、确认、关闭、负责人和 SLA 调整等最近事件。
- 关键风险:展示最高优先级风险。
- 风险表:离线设备、未关闭运维故障、线程上下文告警、失败主 Agent 任务。
- 风险动作:`ops_fault` 支持指派负责人、设置 SLA、确认、关闭和创建修复工单`thread_context_alert` 支持指派负责人、设置 SLA、确认和关闭暂不支持的风险类型会显式失败不假成功。
- 设备表设备在线状态、CLI/GUI 连接状态、最近心跳和风险数量。
- 公司表:优先使用显式 `adminCompanies`,账号和设备未绑定公司时才回退到账号域名或默认公司。
- 公司表补齐 To B 运营字段:套餐等级、合同到期时间、客户负责人和客户成功负责人。
- 账号表:展示账号、角色、公司、状态、创建/更新时间,不暴露 `passwordHash`
### 账号与授权
- 复用 `/api/v1/admin/access`,支持创建 / 更新 `member``admin` 子账号。
- 支持查看账号状态,并对非主账号执行启用 / 停用;停用账号会同步撤销该账号当前活跃会话。
- 支持公司管理、账号归属、设备归属和公司列表。
- 支持按公司批量导入成员账号,并支持先预览新增 / 更新 / 异常数量,预览不会写入状态账本。
- 支持 CSV 文件导入账号清单,表头为 `account,displayName,role,password`
- 支持对子账号开启 / 关闭 MFA后台 GET 不返回 `mfaSecret`,仅开启时在本次响应返回一次 `mfaSetupSecret` 供初始化。
- 支持最高管理员重置子账号密码;重置后会撤销该账号所有活跃会话,响应不暴露 `passwordHash`
- 支持停用 / 启用客户公司;停用公司会同步禁用该租户下的普通子账号并撤销活跃会话,不会波及平台最高管理员。
- 支持离职回收:停用账号、撤销活跃会话,并清理设备 / 项目 / Skill 授权。
- 公司停用 / 授权撤销 / 密码重置 / 离职回收等高危动作均在 PC 后台做二次确认。
- 支持套用内置权限模板。
- 支持设备、项目、Skill 三类授权。
- 支持撤销单条授权。
- 支持查看最近权限审计记录。
### Skill 治理
- 复用 `/api/v1/admin/skills/requests`,支持创建 `install / update / uninstall / rollback / version_lock` 请求。
- 设备端仍由 `local-agent` 按既有 lifecycle 链路认领和完成。
- 管理后台只负责下发治理请求与查看请求状态,不绕过设备端 allowlist、checksum、备份和回滚约束。
- 2026-04-30 起PC 总后台的 Skill 治理入口改为 `Skill 中心`:先展示 Skill 目录、详情、授权对象和执行轨迹,再通过右侧安装向导创建生命周期请求。
- `Skill 中心` 会优先使用 `/api/v1/admin/access` 返回的 `skillCatalog`,没有聚合目录时再由设备 Skill 清单前端兜底聚合,避免最高管理员必须记住每台电脑的原始 `skillId`
- 创建请求仍提交到 `/api/v1/admin/skills/requests`,只是把 `sourceUrl / trustedSourceId / checksum` 等字段放入向导步骤中,降低误操作和填表成本。
## 权限边界
- `/admin` 页面要求登录。
-`highest_admin` 只看到“仅最高管理员可用”提示。
- `/api/v1/admin/overview` 未登录返回 `401`,非最高管理员返回 `403`
- `/api/v1/admin/risks/actions` 未登录返回 `401`,非最高管理员返回 `403`
- `/api/v1/admin/risks/scan` 未登录返回 `401`,非最高管理员返回 `403`
- `/api/v1/admin/notifications/dispatch` 未登录返回 `401`,非最高管理员返回 `403`
- 后台 mutation 路由和认证 mutation 路由会拒绝显式跨站浏览器请求;原生 APP 请求通过 `x-boss-native-app: 1` 豁免浏览器 CSRF 检查。
- 后台 mutation 路由会把 `x-forwarded-for / x-real-ip / user-agent / x-request-id` 写入 `permissionAuditLogs`;高危动作会额外写入安全化 `beforeJson / afterJson` 快照,便于企业客户追责和回放。
## 数据来源
- `authAccounts`:账号与角色。
- `adminCompanies`:客户公司 / 租户实体。
- `devices`:电脑与 Codex CLI/GUI 能力状态。
- `projects`:项目与设备关联。
- `opsFaults`:未关闭运维故障。
- `threadContextAlerts`:未解决线程上下文告警。
- `masterAgentTasks`:失败任务。
- `accountDeviceGrants``accountProjectGrants``accountSkillGrants`:授权汇总和过期授权统计。
- `adminNotifications`:风险 SLA 超时通知账本,由 `/api/v1/admin/risks/scan` 幂等生成,并由 `/api/v1/admin/notifications/dispatch` 派发。
- `adminRiskTimeline`:风险处理时间线,记录通知生成、派发和人工处置动作。
## 后续扩展
- 下一期应接入企业微信 / 飞书 / 短信等更多通知渠道;当前 `BOSS_ADMIN_NOTIFICATION_MODE=email` 可走服务器 sendmail默认 `disabled` 只记录派发状态。
- PostgreSQL 切换仍建议先用 `scripts/boss-state-store-maintenance.mjs` 做备份、dry-run 迁移和回滚演练,再设置 `BOSS_STATE_STORE=postgres`

View File

@@ -19,10 +19,12 @@
2. `docs/architecture/repo_map_cn.md`
3. `docs/architecture/current_runtime_and_deploy_status_cn.md`
4. `docs/architecture/api_and_service_inventory_cn.md`
5. `docs/architecture/boss_server_connection_and_deploy_cn.md`
6. `docs/architecture/wechat_project_conversation_mapping_cn.md`
7. `docs/architecture/thread_context_budget_and_handoff_protocol_cn.md`
8. `prompts/codex_fullstack_build_and_deploy_prompt_cn.md`
5. `docs/architecture/rbac_skill_regression_matrix_cn.md`
6. `docs/architecture/boss_server_connection_and_deploy_cn.md`
7. `docs/architecture/wechat_project_conversation_mapping_cn.md`
8. `docs/architecture/thread_context_budget_and_handoff_protocol_cn.md`
9. `docs/architecture/dependency_security_audit_cn.md`
10. `prompts/codex_fullstack_build_and_deploy_prompt_cn.md`
## 3. 当前有效实现边界
@@ -58,6 +60,7 @@
- `android/app/src/main/java/com/hyzq/boss/AttachmentComposerState.java`:原生附件发送确认规则与待上传附件模型
- `android/app/src/main/java/com/hyzq/boss/BossWindowInsets.java`:原生顶部安全区处理,负责把状态栏 / 刘海区让出来
- `android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java`:原生设备详情与技能入口
- `android/app/src/main/java/com/hyzq/boss/AccessManagementActivity.java`:原生最高管理员用户与权限管理页
- `android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java`:原生 AI 账号管理页
- `android/app/src/main/java/com/hyzq/boss/OpsCenterActivity.java`:原生运维 / 审计中心
- `android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java`:原生微信式 surface contract
@@ -97,6 +100,7 @@
- `POST /api/auth/login` 正常,会写入 `boss_session`
- `boss_session` 当前默认保持 30 天
- `GET /api/auth/session` 正常
- `GET/POST /api/v1/auth/sessions` 正常,已支持基础跨端会话治理和单会话撤销
- `POST /api/auth/restore` 正常,原生 Android 客户端可用 `restore token` 自动恢复登录态
- `GET /api/v1/app-logs` 正常,可按登录态分页读取 APP 日志
- `POST /api/v1/projects/master-agent/messages` 正常,已验证通过 `local-agent -> codex exec -> complete` 返回真实主 Agent 回复
@@ -137,6 +141,9 @@
- 线程改名当前遵循微信最新逻辑:从聊天页右上角进入会话信息页,再进行改名
- 当前已支持从单线程会话发起独立群聊:原会话保留,新群聊自动命名并可在群资料页改名
- 当前群聊编排主链已经补到第一阶段:群聊消息先进入主 Agent主 Agent 生成推荐下发方案,用户确认后再创建执行单;执行完成后线程原始结果会回群,主 Agent 再追加汇总
- 当前 Boss APP 按“Codex 同一线程客户端”同步桌面记录APP 直连线程和主 Agent 托管线程都会把用户原文镜像进目标 Codex rollout供 Codex 桌面版打开/刷新该线程时看到同一段沟通记录;内部 prompt、调度字段和系统约束不得写入桌面可见记录
- 当前桌面实时性新增轻量刷新桥:镜像成功后 `local-agent` 会优先调用本机常驻 `Codex Desktop Bridge` endpoint再由 bridge 打开 `codex://threads/{threadId}` 目标线程深链并发送一次应用刷新快捷键,让 Codex 桌面版切到目标线程后重新感知线程更新endpoint 不可用时会回退到原命令式刷新。这条桥只做打开/刷新提示,不承担消息输入,失败也不能阻断主链。默认配置会在短暂失败时重试 2 次、间隔 120ms并保留 deep link 与尝试次数方便排查桌面端是否收到刷新提示。bridge 还提供本机 SSE`GET /api/v1/codex-desktop/events`,只广播安全元数据;`scripts/codex-desktop-event-consumer.mjs` 已作为 Desktop 插件/IPC 的消费样例
- 当前还新增 `scripts/codex-desktop-integration-probe.mjs` 与 bridge `GET /api/v1/codex-desktop/capabilities`:用于自动探测当前 Codex Desktop 是否支持 `codex://threads/{threadId}` 这类稳定入口,并明确禁止把“修改 Codex.app 签名包体”作为支持能力
- 当前设备导入主链已经补到第一阶段:设备 heartbeat 可上报真实候选线程,系统会生成导入草稿;用户勾选后可生成导入决议,并把选中的线程真正落成聊天窗口
- 当前设备导入草稿不会再被旧 `projects` 字段绕过;只有 `apply` 之后,候选线程才会真正变成聊天窗口
- 当前设备导入 `review` 已经会留下 `device_import_resolution` master task 轨迹,但决议内容仍是服务端 heuristic 版,尚未真正交给 `local-agent -> codex exec`
@@ -150,17 +157,21 @@
- 移动端 UI 已去掉假的状态栏与桌面预览壳;底部一级导航固定在视口底部,返回逻辑不会再把 APP 根页直接弹回桌面
- `项目目标` 支持用户编辑、主 Agent 复核、完成项自动划线
- `版本迭代记录` 只读,由主 Agent 汇总
- `我的` 根页当前保留 `账号与安全 / 设置 / 运维与修复 / AI 账号 / 技能 / 关于`
- `我的` 根页当前保留 `账号与安全 / 设置 / 运维与修复 / AI 账号 / 附件与存储 / Telegram 接入 / 技能 / 关于`,其中 `用户与权限` 仅最高管理员可见
- `我的 > 账号与安全` 已支持查看和撤销登录会话;最高管理员可管理全部活跃会话,子账号只能管理自己的会话
- `我的 > 用户与权限` 与 Web `/me/access` 共用 `/api/v1/admin/access`,可创建子账号、分配设备 / 项目 / Skill 权限,并查看同名 Skill 跨设备聚合PC `/admin` 已补公司停用、CSV/文本批量导入预览、重置密码、子账号 MFA、风险 SLA 通知派发、风险时间线和后台审计来源字段
- 多用户 / RBAC / Skill / 主 Agent 权限和多设备控制的集中状态、回归矩阵与缺口清单见 `docs/architecture/rbac_skill_regression_matrix_cn.md`
- `我的 > 主 Agent 提示词 / 记忆` 当前可编辑管理员全局主提示词、用户主提示词、当前对话附加提示词,以及用户通用记忆 / 项目记忆
- `我的 > AI 账号` 必须可查看和切换 `主 GPT / 备用 GPT / API 容灾`
- `我的 > 技能` 必须按绑定设备展示 Skill并支持一键复制调用语句
- Skill 远程治理第一版已经接通最高管理员后端入口和设备端执行:`GET/POST /api/v1/admin/skills/requests` 可创建和查看 `install / update / uninstall / rollback / version_lock` 请求local-agent 通过 `claim / complete` 认领执行并回写最新 Skill 清单。当前设备端已增加 source allowlist / trusted source、`checksum / expectedChecksum` sha256 校验、更新 / 卸载 / 回滚前备份和失败恢复;仍未做签名校验和依赖安装沙箱
- `设备` 页当前只允许出现生产设备,旧演示脏数据不能回流到正式视图
- 登录后必须形成最小会话,受保护页面和核心 `/api/v1/*` 接口不能再裸奔
- 必须保留登录、注册、忘记密码和验证码入口
## 6. 当前技术路线
- Web`Next.js 16.2.1 + React 19`
- Web`Next.js 16.2.4 + React 19`
- 数据:当前是文件型持久化 `data/boss-state.json`
- 状态写入:串行事务队列 + 原子写入 + `.bak` 备份恢复
- device-agent原生 Node HTTP 服务
@@ -168,7 +179,7 @@
- 邮件:`Postfix + Dovecot`
- Android`AppCompatActivity + 原生 XML 布局 + HttpURLConnection`
- 原生登录恢复:`SharedPreferences + restore token`
- 当前最新原生 APK`2.5.4``versionCode=17`
- 当前最新原生 APK`2.5.11``versionCode=24`
当前不要误判成已经用了:
@@ -187,7 +198,7 @@ npm install
npm run build
npm run lint
curl -sS http://127.0.0.1:3000/api/health
curl -sS -H 'Content-Type: application/json' -d '{"account":"17600003315","password":"boss123456","method":"password"}' http://127.0.0.1:3000/api/auth/login
curl -sS -H 'Content-Type: application/json' -d '{"account":"krisolo","password":"<admin-password>","method":"password"}' http://127.0.0.1:3000/api/auth/login
curl -sS http://127.0.0.1:3000/api/auth/session
curl -sS http://127.0.0.1:3000/api/v1/conversations
curl -sS http://127.0.0.1:3000/api/v1/projects/master-agent
@@ -211,20 +222,20 @@ npm run apk:debug
## 8. 当前已知未完成项
- 认证仍是 MVP 级别:虽然已有最小会话 Cookie,但还没有刷新令牌、跨端会话治理和 CSRF 防护
- 认证仍是 MVP 级别但已收紧:已有最小会话 Cookie、restore token 轮换、浏览器 CSRF 基础防护、子账号 MFA、基础跨端会话治理和后台高危动作审计临时免验证登录默认关闭只能通过 `BOSS_AUTH_AUTO_LOGIN=1/true/yes` 显式开启
- 当前已补“原生 restore token 自动恢复”,但这仍不是完整的多端会话系统
- 当前默认最高管理员账号是 `17600003315`,默认密码 `boss123456`,并已绑定本机 Codex 节点
- 当前默认最高管理员账号是 `krisolo`,默认密码由线上初始化配置管理,并已绑定本机 Codex 节点
- 主 Agent 实时回复当前依赖被绑定设备的 `local-agent` 在线,并能在本机跑通 `codex exec`
- API 容灾当前由用户在 APP 的 `我的 > AI 账号` 中自行配置 `OpenAI API` 账号
- 服务器默认固定验证码仍是 `000000`
- 服务器默认验证码模式仍是 fixed但验证码登录也必须先申请验证码不允许只靠固定码直接登录
- 服务器邮件栈已部署完成,应用内也已经支持 email 模式,但默认开关还没切到 email
- OTA 版本中心、检查更新、执行升级和 APK 包下载已接通,但当前仍是文件型状态驱动的 MVP
- APP 实时日志同步、主 Agent 日志镜像、SSE 自动刷新和 Skill 同步页已经接通,但日志检索、告警和远程 Skill 管理仍未做
- 设备导入主链当前已经具备后端闭环和 Web/Android 前台接线,后续重点改成继续细化导入筛选规则和主 Agent 理解策略,而不是再从 0 接页面
- 数据库尚未替代文件存储
- APP 实时日志同步、主 Agent 日志镜像、SSE 自动刷新和 Skill 同步页已经接通日志检索已有基础分页,风险 SLA 通知账本已接入,外部通知渠道仍未做
- 设备导入主链当前已经具备后端闭环和 Web/Android 前台接线;主 Agent 理解同步已经避免未接管状态下主动问线程,后续重点继续细化导入筛选规则和用户主动同步体验
- 数据库尚未替代文件存储;当前已补 `BOSS_STATE_STORE=postgres` 单行 JSONB 适配层、schema 和 `scripts/boss-state-store-maintenance.mjs` 备份 / 迁移 / 回滚工具,但生产仍默认文件状态
- 域名入口的代理 / 分裂 DNS 结构仍未完全摸清
- 当前只支持服务器文件存储和阿里 OSS尚未接更多对象存储或更丰富的附件详情页
- 认证有真实 session 和令牌吊销
- 认证有真实 session、restore token 轮换、单会话撤销、CSRF 基础防护和 MFA 开关,但还没有企业 SSO / IdP
## 9. 继续开发时的工作原则

View File

@@ -16,7 +16,18 @@
- 当前原生恢复态:`restore token + SharedPreferences`
- 当前执行底座:`src/lib/execution/`,已包含 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现
### 1.2 boss-android-native
### 1.2 boss-admin-web
- 形态:独立 PC 企业后台前端
- 工程目录:`apps/boss-admin-web`
- 技术栈:`Vue 3 + Vite + Ant Design Vue`
- 本地开发脚本:`npm run admin:web:dev`
- 构建脚本:`npm run admin:web:build`
- 数据入口:`GET /api/v1/admin/backoffice`
- 登录态:复用 `boss_session` HttpOnly Cookie
- 当前定位:平台侧 To B 总后台面向公司、账号、设备、项目、Skill、风险与审计治理现有 `/admin` 继续作为主站内 fallback
### 1.3 boss-android-native
- 形态:原生 Android 客户端
- 原生入口:`android/app/src/main/java/com/hyzq/boss/MainActivity.java`
@@ -39,8 +50,11 @@
- `DeviceEnrollmentActivity`
- `SkillInventoryActivity`
- `SecurityActivity`
- `AccessManagementActivity`
- `SettingsActivity`
- `StorageSettingsActivity`
- `AiAccountsActivity`
- `TelegramIntegrationActivity`
- `OpenAiOnboardingActivity`
- `OpsCenterActivity`
- `AboutActivity`
@@ -53,11 +67,13 @@
- 单线程会话支持按微信最新逻辑改线程名
- 当前已经支持从单线程会话发起独立群聊,群聊创建后作为新会话保留,原会话不升级
- 当前单线程会话已经支持打开 `线程状态` 只读页,查看主 Agent 当前掌握的线程状态文档和最近进展事件
- 当前已经支持微信式消息转发:长按消息可直接 `转发 / 多选 / 复制 / 删除`
- 当前已经支持微信式消息转发:长按消息可直接 `转发 / 多选 / 复制 / 删除`,其中删除会调用服务端账本删除接口并刷新会话预览
- 当前多选模式会切换成微信式 `取消 + 已选数量 + 底部转发` 状态
- 当前统一使用 `ForwardTargetActivity` 选择目标会话,替换旧的备注转发主链
- 当前已支持聊天附件主链:输入框左侧 `+` 会打开底部抽屉,支持图片 / 视频 / 文件发送;图片 / 视频先确认,文件直接发送
- 当前附件消息支持下载、原生打开、手动分析和自动分析状态展示
- 当前线程聊天消息会按该线程绑定的 Codex 电脑显示来源头像:单线程会话使用项目绑定设备头像,多设备 / 群聊消息会优先根据发送人里的设备名匹配对应电脑头像;主 Agent 总入口自身仍保留主 Agent 对话样式
- 当前已支持 `execution_progress` 执行进度卡:普通线程对话、主 Agent 托管线程和群聊目标线程执行时,会在对应聊天窗口显示“进度 / 分支详情 / 生成结果 / 后台智能体”结构化卡片;线程过程噪音仍走 `thread_process` 折叠
- `线程详情 / 运维调试` 仍保留对应原生活动页,但已退出主聊天面
- 当前已补上本地发送中气泡、发送按钮状态控制,以及“只有接近底部才自动滚到底”的消息流行为
- 当前根页导航:
@@ -74,17 +90,20 @@
- 保留版本与 OTA 操作
- 当前已补上 OTA 下载进度、失败重试、安装授权提示和返回关于页后的本地状态恢复
- 当前 `我的` 根页:
- 保留 `账号与安全 / 设置 / 运维与修复 / AI 账号 / 技能 / 关于`
- 已按登录角色过滤入口:`member` 只显示 `账号与安全 / 设置 / 技能 / 关于`
- `admin / highest_admin` 额外显示 `运维与修复 / AI 账号 / 附件与存储 / Telegram 接入`
- `用户与权限``highest_admin` 可见,用于创建子账号和分配设备 / 项目 / Skill 权限
- `运维与修复` 直接进入 `OpsCenterActivity`
- `技能` 入口会继续依赖服务端 Skill 授权过滤,不在客户端自行扩大可见范围
- 当前 `OpenAiOnboardingActivity`
- 会先自动打开 `OpenAI Platform` 登录页
- 支持继续打开 `API Keys` 页面
- 回 APP 后可直接粘贴 key并设为当前主控
- 登录成功后会直接给出 `测试主 Agent 对话` 入口
- 当前登录:临时免验证,点击登录直接创建最高管理员会话
- 当前登录:默认要求账号密码或验证码校验;临时开发兜底只允许通过显式环境变量开启
- 当前会话恢复:`SharedPreferences` 中保存 `boss_session / restore_token / account`
### 1.3 boss-local-agent
### 1.4 boss-local-agent
- 形态Node 原生 HTTP 服务
- 本地端口:默认 `4317`
@@ -94,21 +113,47 @@
- 当前新增职责:递归扫描本机 `~/.codex/skills` 并同步到设备 Skill 接口
- 当前完成回写:`conversation_reply / dispatch_execution` 会先标准化成统一远程执行结果,再调用 `/api/v1/master-agent/tasks/[taskId]/complete`
- 当前 `dispatch_execution` 会按 `orchestrationBackendId` 分流:默认走 `codex exec resume`,显式选择 `omx-team` 且本机配置可用时改走 `OMX Team Runtime` JSON 协议
- 当前 Codex 任务完成回写会附带 `executionProgress` 快照:包含 Git diff 简表、GitHub CLI 可用状态和从执行回复中提取的产物文件名,服务端更新同一张 `execution_progress` 卡片,不重复刷屏
- 当前 `RemoteRuntimeAdapter` 还负责拦截固定模式的线程内部环境提示;命中后会直接改写成失败,避免把只读/cwd 这类脏文本写进聊天记录
- 当前普通单线程 `conversation_reply` 在真正执行 `codex exec resume` 前,会先把 Boss 用户消息镜像进目标 Codex Desktop rollout定位优先走 `state_5.sqlite`,不可用时回退扫描 `~/.codex/sessions`,并按 `sourceMessageId` 去重
- 当前 Codex Desktop 同步新增常驻刷新桥:`scripts/codex-desktop-refresh-bridge-daemon.mjs` 通过 launchd 监听 `127.0.0.1:4318`,暴露 `POST /api/v1/codex-desktop/refresh``GET /api/v1/codex-desktop/events``GET /api/v1/codex-desktop/events/recent``GET /api/v1/codex-desktop/capabilities``local-agent` 会优先调用 refresh endpoint失败时回退到 `scripts/codex-desktop-refresh-hint.mjs` 命令式刷新。SSE 事件只包含线程引用、消息 ID、状态、deep link 等安全元数据,不包含用户正文或内部 prompt`scripts/codex-desktop-event-consumer.mjs` 可作为 Desktop 插件/IPC 接入前的订阅 smoke`scripts/codex-desktop-integration-probe.mjs` 负责只读探测 Codex.app 能力
- 当前 `local-agent` 还新增了两条统一电脑控制 runtime
- `local-agent/browser-control-task-runner.mjs`
- `local-agent/computer-use-task-runner.mjs`
- 当前 `browser_control / desktop_control` 任务已经可以被 `local-agent/server.mjs` 识别并分流;当本机配置了对应 runtime 命令时,会通过 JSON stdin/stdout 协议委托给外部进程执行,否则返回明确 runtime disabled 错误,不再回退占位成功结果
- 当前 `browser_control / desktop_control` 的完成回写已贯通 `targetUrl / targetApp -> RemoteRuntimeAdapter -> /api/v1/master-agent/tasks/[taskId]/complete -> boss-state.json`,服务端写入 `control_summary` 消息时会保留 `controlTarget`Android 会话页可直接渲染“目标URL/应用名”
- 相关配置项:
- `browserControlEnabled / browserControlCommand / browserControlArgs / browserControlWorkdir / browserControlTimeoutMs`
- `computerUseEnabled / computerUseCommand / computerUseArgs / computerUseWorkdir / computerUseTimeoutMs`
- 当前仓库已自带最小 smoke runtime
- `scripts/browser-control-smoke.mjs`
- `scripts/computer-use-smoke.mjs`
- `scripts/browser-control-smoke.mjs` 当前已支持两段式最小真实动作:
- 能从目标 URL 拉取 HTML 标题并回写到 `replyBody / executionSummary`
- 在显式配置 opener 命令时可实际执行打开 URL
- `scripts/computer-use-smoke.mjs` 当前已支持识别常见桌面应用名macOS 下默认用 `osascript` 激活目标应用,并支持把用户请求中的引号文本输入到当前前台应用、按需回车发送;同时保留 `open -a` 兜底,并会落盘结构化 artifact便于后续真实 Computer Use runtime 复用同一回写协议
- `config.example.json / config.cloud.json` 现默认把这两条 smoke runtime 作为 browser/desktop 控制的推荐起步配置
- `config.example.json / config.cloud.json` 现同时默认把 `browserAutomationConnected / computerUseConnected` 置为 `true`,让前台设备详情默认按“这台 Mac 已具备浏览器控制 / 桌面控制能力”展示
- 这两条 smoke runtime 当前还会返回结构化字段:
- browser`targetUrl / artifacts`
- desktop`targetApp / typedText / artifacts`
- 这样前台与后续真实 runtime 可以共用同一套结果形态,而不需要等接入 Playwright / Computer Use 后再改返回协议
- heartbeat 的 `browserAutomation / computerUse` 能力上报会同时参考静态 connected 标记和 runtime 配置状态
### 1.4 Caddy
### 1.5 Caddy
- 作用:反向代理和 HTTPS 自动续签
- 服务器服务名:`caddy.service`
- 配置文件:`deployment/Caddyfile`
- 当前站点:`boss.hyzq.net` 服务客户 Web / App API`admin.boss.hyzq.net` 服务平台总后台。独立后台第一批仍未替换线上 `/admin`,后续部署完成后再把该域名切到 `apps/boss-admin-web` 静态产物
### 1.5 boss-server-debug skill
### 1.6 boss-server-debug skill
- 作用:跨 Codex 窗口稳定连接 `106.53.170.158`
- 路径:`$HOME/.codex/skills/boss-server-debug/SKILL.md`
- 密码来源:优先读取 macOS Keychain
### 1.6 Postfix + Dovecot
### 1.7 Postfix + Dovecot
- 作用:服务器侧邮件发送 / 接收基础设施
- SMTP 端口:`25 / 465 / 587`
@@ -143,6 +188,7 @@
- `GET /me/security`
- `GET /me/about`
- `GET /me/storage`
- `GET /me/access`
- `GET /me/ai-accounts`
- `GET /me/ops`
- `GET /me/ops/audit`
@@ -163,9 +209,194 @@
#### `GET /api/state`
- 用途:读取当前完整状态
- 注意:这是内部 MVP 调试接口,会直接返回整个 `BossState`
- 当前行为最高管理员可读取完整状态非最高管理员会返回已按当前账号授权裁剪后的状态快照设备、项目、线程状态、进展事件、Skill、日志和任务都会尽量限制在可见范围内
- 注意:这是内部 MVP 调试接口,仍不建议作为普通业务页面的主数据源;业务页面应优先使用具体 `/api/v1/*` 投影接口
### 3.1.1 执行底座抽象层
### 3.1.1 多用户 RBAC 与 Skill 授权
- 权限模块:`src/lib/boss-permissions.ts`
- 状态字段:
- `accountDeviceGrants`
- `accountProjectGrants`
- `accountSkillGrants`
- `skillCatalog`
- `permissionAuditLogs`
- 当前规则:
- `highest_admin` 全局可见
- 非管理员必须通过设备、项目或 Skill 授权获得可见性
- `device.view` 只提供设备与关联项目只读可见性,不自动放大为聊天、接管、电脑控制或 Skill 使用权限
- `thread.chat / master_agent.ask / master_agent.takeover / computer.control / skill.use` 需要显式授权
- 当前已接入过滤的接口:
- `GET/POST /api/v1/admin/access`(仅最高管理员)
- `GET /api/v1/devices`
- `GET /api/v1/conversations`
- `GET /api/v1/conversations/home`
- `GET /api/v1/conversation-folders/[folderKey]`
- `GET /api/v1/projects/[projectId]`
- `GET/POST /api/v1/projects/[projectId]/messages`
- `GET /api/v1/devices/[deviceId]/skills`
- `GET /api/state`
- 当前主 Agent 行为:执行提示词使用授权快照生成,任务队列会记录 `authorizedDeviceIds / authorizedProjectIds / authorizedSkillIds / requiredPermissions`
- 当前前台入口Web `/me/access` 与原生 Android `AccessManagementActivity` 共用 `/api/v1/admin/access`,仅 `highest_admin` 可见;`admin/member` 不显示入口且直接请求会返回 `403`
#### `GET /api/v1/admin/access`
- 用途:最高管理员读取账号与授权管理台所需数据
- 权限:仅 `highest_admin`
- 返回:
- 脱敏 `accounts`,不包含 `passwordHash`
- `companies`:显式客户公司 / 租户列表
- `devices / projects / skills`
- 按同名 Skill 聚合的 `skillCatalog`
- 内置 `permissionTemplates`
- `grants.devices / grants.projects / grants.skills`
- `auditLogs`
#### `POST /api/v1/admin/access`
- 用途:最高管理员执行最小授权管理动作
- 权限:仅 `highest_admin`
- 支持动作:
- `upsert_company`:创建或更新客户公司 / 租户
- `set_company_status`:启用或停用客户公司;停用时同步禁用该租户普通子账号并撤销活跃会话
- `assign_account_company`:把账号绑定到指定客户公司
- `assign_device_company`:把设备绑定到指定客户公司
- `preview_bulk_import_accounts`:预览批量导入结果,返回新增 / 更新 / 异常数量,不写入状态
- `bulk_import_accounts`:按公司批量导入 `member/admin` 子账号
- `reset_account_password`:最高管理员重置子账号密码,重置后撤销该账号活跃会话且响应不返回 `passwordHash`
- `reclaim_account`:离职回收,停用账号、撤销活跃会话并清理设备 / 项目 / Skill 授权
- `upsert_account`:创建或更新子账号
- `set_account_status`:启用或停用子账号;停用时撤销该账号当前活跃会话,且禁止停用最高管理员账号
- `grant_device`:授予设备权限
- `grant_project`:授予项目权限
- `grant_skill`:授予 Skill 权限
- `apply_template`:对指定账号和目标设备 / 项目 / Skill 批量套用内置权限模板
- `revoke_grant`:撤销任意设备 / 项目 / Skill 授权
- 当前行为:所有变更类动作都会写入 `permissionAuditLogs`,用于后续审计和主 Agent 接手时判断权限来源;后台 mutation 会记录 `ipAddress / userAgent / requestId`,高危动作可记录安全化 `beforeJson / afterJson`
#### `GET /api/v1/admin/overview`
- 用途:最高管理员读取 To B 管理后台总览数据
- 权限:仅 `highest_admin`
- 返回:
- `summary`:公司、账号、设备、在线设备、开放风险、风险通知、严重风险数量
- `companies[]`:优先使用显式客户公司 / 租户,其次按账号域名或默认公司聚合
- `accounts[]`:脱敏账号列表,不包含 `passwordHash`
- `devices[]`设备在线状态、CLI/GUI 能力、项目数和风险数
- `risks[]`:离线设备、运维故障、线程上下文风险和失败主 Agent 任务;运维故障和线程上下文风险会带出负责人和 SLA
- `notifications[]`:开放中的风险 SLA 通知,当前由 `/api/v1/admin/risks/scan` 生成
- `grantsSummary`:设备 / 项目 / Skill 授权数量与过期授权数量
#### `GET /api/v1/admin/backoffice`
- 用途:独立 PC 企业后台读取 YuDao/Vben 风格的总后台契约数据
- 权限:仅 `highest_admin`
- 返回:
- `menuTree`工作台、租户管理、账号管理、角色权限、资源授权、Skill 中心、风险告警、审计日志、系统设置
- `workbench`:平台总览、客户健康、设备健康、风险、通知和授权摘要
- `tenants[]`:客户公司 / 租户列表,来自 `adminCompanies` 与现有聚合
- `users[]`:脱敏账号列表,不包含 `passwordHash / mfaSecret / authSessions`
- `roles`:内置角色与 `BOSS_PERMISSION_TEMPLATES`
- `resourceGroups`设备、项目线程、Skill 聚合目录和授权记录
- `audit`:风险、通知、风险时间线和 `permissionAuditLogs`
- `yudaoMapping`Boss 账本字段到后台概念的映射,用于后续数据库化或模块拆分
- 当前定位:供 `apps/boss-admin-web` 消费;现有 `/admin` 仍继续使用 `/api/v1/admin/overview``/api/v1/admin/access`
#### `POST /api/v1/admin/risks/scan`
- 用途:扫描当前风险 SLA幂等生成平台侧待跟进通知
- 权限:仅 `highest_admin`
- 当前行为:
- 扫描未关闭的 `opsFaults``threadContextAlerts`
-`slaDueAt` 已早于当前时间时,写入 `adminNotifications[]`
- 同一个 `riskId` 只生成一条 `risk_sla_overdue` 通知,重复扫描不会重复膨胀账本
- 生成新通知时发布 `project.context_risk.updated`
#### `POST /api/v1/admin/risks/actions`
- 用途:最高管理员在管理后台处理风险
- 权限:仅 `highest_admin`
- 输入:
- `riskId`:当前支持 `ops-fault:<faultId>``thread-alert:<alertId>`
- `action``assign_owner | set_sla | ack | resolve | create_repair_ticket`
- `ownerAccount``assign_owner` 必填
- `slaDueAt``set_sla` 必填
- `note`:可选处理备注
- 当前行为:
- `ops-fault` 支持指派负责人、设置 SLA、确认、关闭、创建或复用修复工单
- `thread-alert` 支持指派负责人、设置 SLA、确认和关闭关闭时写入 `resolvedAt`
- 离线设备、失败主 Agent 任务等暂不支持直接动作,会返回 `RISK_ACTION_UNSUPPORTED`
- 当前事件:成功动作会发布 `project.context_risk.updated`
#### `GET /api/v1/audits/permission-logs`
- 用途:查询 `permissionAuditLogs` 并返回第一版权限审计风险摘要
- 权限:仅 `highest_admin`;普通 `admin/member` 直接返回 `403`
- 查询参数:
- `action`
- `actorAccount`
- `targetAccount`
- `deviceId`
- `projectId`
- `skillId`
- `cursor`
- `limit`,默认 `50`,最大 `200`
- 返回:
- `logs[]`:按 `createdAt` 最新在前排序后的当前页审计日志
- `nextCursor`:下一页游标;没有更多数据时为 `null`
- `total`:匹配过滤条件的总数
- `riskSummary`:基于现有 `permissionAuditLogs` 和仍存在授权记录生成的 deterministic 摘要
- 当前风险规则:
- `rapid_permission_grants`:同一 actor / target 在 10 分钟内出现 5 条及以上授权类日志
- `skill_lifecycle_failed`Skill lifecycle 完成日志中可识别失败,或后续写入 `skill.lifecycle.failed`
- `expired_grant_present`:设备 / 项目 / Skill 授权记录已过期但仍留存在状态中
- `admin_route_denied`:已有 `task.denied` 日志能识别非最高管理员访问 admin route 被拒
- 当前限制:权限审计风险摘要仍是查询时实时计算;持久化通知账本只覆盖风险 SLA 超时场景。
#### `GET /api/v1/admin/skills/requests`
- 用途:最高管理员读取 Skill 远程治理请求队列
- 权限:仅 `highest_admin`;普通 `admin/member` 直接返回 `403`
- 返回:
- `requests[]`:当前保存在 `boss-state.json` 的 Skill lifecycle 请求
- 当前行为:按最新请求在前返回;设备端认领后状态会从 `pending` 变成 `running / completed / failed`
#### `POST /api/v1/admin/skills/requests`
- 用途:最高管理员创建 Skill 生命周期治理请求
- 权限:仅 `highest_admin`
- 支持动作:
- `install`
- `update`
- `uninstall`
- `rollback`
- `version_lock`
- 输入要求:
- 必须提供 `deviceId`
- 必须提供 `skillId``sourceUrl` 之一
- 可选 `targetVersion / rollbackToVersion / lockedVersion / checksum / expectedChecksum / trustedSource / note`
- 当前行为:请求以 `pending` 状态写入 `skillLifecycleRequests`local-agent 会按设备 token 认领执行,并把 `completed / failed` 与结果摘要写回
- 当前设备端安全策略:远程 `install` 或带 `sourceUrl` 的更新必须命中本机 `skillLifecycleAllowedSources``skillLifecycleTrustedSources`allowlist 为空时只允许既有本地 Skill 的 `update / rollback / uninstall / version_lock`。如果请求带 `checksum / expectedChecksum`local-agent 会对 `manifest.json``SKILL.md` 做 sha256 校验;校验失败会失败回写,并清理半安装目录或尽量从 `skillsDir/.boss-skill-backups` 恢复
- 当前限制:第一版仅支持 Git 安装 / 更新、本地目录卸载、Git checkout 回滚和 `.boss-skill-locks.json` 版本锁;尚未做签名校验、依赖安装沙箱或 per-run Skill 执行审计
#### `POST /api/v1/devices/[deviceId]/skill-requests/claim`
- 用途:设备端领取下一条属于自己的 Skill 生命周期请求
- 权限:设备 token 或具备 `device.manage` 的登录会话
- 返回:
- `request`:下一条请求;无待处理时为 `null`
- 当前行为:只领取当前设备 `pending` 请求,领取后改为 `running`
#### `POST /api/v1/devices/[deviceId]/skill-requests/[requestId]/complete`
- 用途:设备端回写 Skill 生命周期请求执行结果
- 权限:设备 token 或具备 `device.manage` 的登录会话
- 输入:
- `status``completed``failed`
- `resultSummary` / `error`
- 当前行为:写回 `completedAt / updatedAt / resultSummary / error`,并追加 `permissionAuditLogs`
### 3.1.2 执行底座抽象层
- 目录:`src/lib/execution/`
- 当前默认实现:
@@ -182,13 +413,14 @@
- 当前状态:
- 已在生产代码中被 `boss-master-agent.ts``local-agent/server.mjs``master-agent task complete route` 使用
- 当前仍服务 Boss 自身执行链
- 当前已补 `browser_control / desktop_control` 两个新的 execution tool并已纳入统一权限与风险分级判断
- 当前已最小接入 `ClawBackendAdapter`,但默认关闭,仅在显式配置且可用性探测通过时才参与执行
- 如果历史 `backendOverride=claw-runtime` 当前不可用,运行时会自动回退到默认后端,并把原因回给前台
- 当前仓库自带 `scripts/claw-runtime-smoke.mjs` 作为兼容 JSON 协议的 smoke runtime可用于本地和服务器验证 `ClawBackendAdapter`
- 当前已最小接入 `OmxTeamBackendAdapter`但默认关闭Web 群聊详情页和原生群资料页已经可以在 `Boss Native``OMX Team` 间切换编排后端OMX 不可用时会自动回退到默认后端并返回明确原因
- 当前仓库自带 `scripts/omx-team-smoke.mjs`,可用于本地和服务器验证 `OmxTeamBackendAdapter``dispatch_execution` JSON 协议
### 3.1.2 线程状态文档与进展事件
### 3.1.3 线程状态文档与进展事件
- 状态字段:
- `threadStatusDocuments`
@@ -198,7 +430,8 @@
- 让 Web / Android 前台能直接查看线程的当前目标、阶段、进度、架构、阻塞、建议下一步
- 当前同步策略:
- `heartbeat / thread reply` 平时优先写轻量进展事件
- 首次理解、状态变薄、长时间未刷新或主 Agent 真正接手时,才补排隐藏全量理解任务
- 只有单线程接管、全局接管或用户明确要求同步项目目标 / 版本记录时,才补排隐藏全量理解任务
- 关闭接管会同步清理仍在 queued/running 的项目理解同步任务,避免取消接管后继续主动打扰线程
### 3.2 认证相关
@@ -208,13 +441,13 @@
- 输入:
- `account`
- `purpose`: `login | register | forgot-password`
- 当前行为:在邮件验证码正式切换前,固定验证码为 `000000`
- 当前行为:在邮件验证码正式切换前,fixed 模式仍返回固定验证码,但所有验证码登录都必须先通过 `send-code` 生成有效记录
- 当前说明Web 侧已经支持 email 模式email 模式下会通过本机 `sendmail` 调用 `Postfix` 发信;服务器默认仍保持 fixed
- 当前保护60 秒冷却,同一账号 15 分钟窗口内超过 5 次会被限流
- 当前前置校验:
- `purpose=login | forgot-password` 时要求账号已存在
- `purpose=register` 时要求账号尚未注册
- 当前 fixed 模式:登录可直接输入 `000000`,不再依赖先申请验证码;注册和重置密码`send-code` 申请链路
- 当前 fixed 模式:登录注册和重置密码都必须先`send-code` 申请链路,再消费账本里的有效验证码
#### `POST /api/auth/login`
@@ -224,16 +457,16 @@
- `password`
- `code`
- 当前行为:
- 当前已临时切到免验证模式,点击登录会直接创建 `17600003315` 的最高管理员会话
- 默认不再允许临时免验证登录,只有显式配置 `BOSS_AUTH_AUTO_LOGIN=1/true/yes` 时才开启开发兜底
- 原生 Android 端登录后会持久化 `boss_session + restore token`,用于 30 天登录保持和 OTA / 覆盖安装后的会话恢复
- 当前阶段不会因为账号、密码或验证码为空而拒绝登录
- 正常模式要求 `password``code` 校验通过
- 校验通过后会写入 `boss_session` Cookie
- 当请求头带 `x-boss-native-app: 1` 时,还会额外返回 `restoreToken`
- 当前 `boss_session` 默认保持 30 天
- 连续失败 5 次后会锁定 10 分钟
- 当前密码存储:新注册 / 重置密码使用 `scrypt`;历史 `sha256` 会在下次密码登录时自动迁移
- 当前默认管理员账号:`17600003315`
- 当前默认测试密码`boss123456`
- 当前默认管理员账号:`krisolo`
- 当前默认测试密码由线上初始化配置管理,文档不再明文记录
#### `GET /api/auth/session`
@@ -248,6 +481,26 @@
- 当请求头带 `x-boss-native-app: 1` 时,还会返回:
- `restoreToken`
#### `GET /api/v1/auth/sessions`
- 用途:查看可管理的登录会话
- 当前行为:
- `highest_admin` 可查看全部活跃会话
- 其他账号只能查看自己的活跃会话
- 返回内容只包含 `sessionId / account / role / displayName / loginMethod / createdAt / expiresAt / lastSeenAt / current`
- 不返回 `sessionToken / restoreToken`
- 前台入口Web `/me/security` 与原生 Android `SecurityActivity`
#### `POST /api/v1/auth/sessions`
- 用途:撤销单个登录会话
- 输入:
- `action=revoke_session`
- `sessionId`
- 当前权限:
- `highest_admin` 可撤销任意活跃会话
- 其他账号只能撤销自己的会话
#### `POST /api/auth/restore`
- 用途:原生 APP 使用 `restore token` 恢复 `boss_session`
@@ -385,6 +638,7 @@
- 普通单线程项目当前会在写入用户消息后,继续创建 `taskType=conversation_reply` 的主 Agent 任务
- 返回体会附带 `task.taskId / taskType / status`,给 Web 和原生 Android 保持等待真实回写使用
- `projectId=master-agent``kind=text` 时,会先返回 `masterReplyState + task`,真实回复随后异步回写到账本
- Telegram Gateway 当前也复用这条主 Agent 链路Telegram 私聊文本会写入 `master-agent` 项目,快速回复直接返回,异步任务通过 `externalReplyTarget` 在完成后回推 Telegram
- 当前主链路优先走 `Master Codex Node``task queue -> local-agent -> codex exec -> complete`
- 如果当前主控是 `Master Codex Node`,但节点离线或执行立即失败,主 Agent 当前会优先尝试已配置的 `OpenAI API / 阿里百炼 Qwen` 账号,避免聊天直接只剩失败日志
- 如本机节点未接通,可切到 `OpenAI API``阿里百炼 Qwen` 备用账号
@@ -392,6 +646,16 @@
- 群聊文本消息当前还会返回 `dispatchPlan / dispatchRecommendation`,用于展示主 Agent 推荐的线程下发方案
- 如果群里已经有一条待确认推荐,接口会直接返回 `409`,要求先确认或拒绝当前推荐,避免审批消息叠加
#### `DELETE /api/v1/projects/[projectId]/messages`
- 用途:删除当前项目消息账本里的一条聊天消息
- 输入:
- `messageId`:优先从 query string 读取,也兼容 JSON body
- 当前行为:
- 删除成功后会刷新项目预览、更新时间和未读计数
- 会发布 `project.messages.updated / conversation.updated`
- Android 长按消息的“删除”菜单已接入该接口
#### `GET /api/v1/projects/[projectId]/agent-controls`
- 用途:读取当前对话级别的 `modelOverride / reasoningEffortOverride / backendOverride`
@@ -660,6 +924,7 @@
#### `GET /api/v1/storage/config`
- 用途:读取当前登录用户的附件存储配置
- 当前入口Web `我的 > 附件与存储` 与 Android `StorageSettingsActivity`
- 返回:
- `mode`: `server_file | oss`
- `ossProvider`
@@ -902,7 +1167,49 @@
- `taskType=conversation_reply` 时,会把目标 Codex 线程的原始回复写回普通单线程会话
- `taskType=dispatch_execution` 时,会把线程原始结果镜像回群聊,再追加一条主 Agent 汇总,并更新对应执行单状态
- `failed` 时写入 relay 失败消息,并更新 AI 账号健康状态
- 如果任务带有 `externalReplyTarget.provider=telegram`,完成后会尝试调用 Telegram Bot API 把 `replyBody` 回推到原始聊天
- 对群聊分发推荐失败的情况,消息入口当前会额外写入一条 `system_notice`,把“没有真实线程”或“成员引用失效”明确回显给用户
#### `GET /api/v1/integrations/telegram`
- 用途:读取 Telegram Bot 接入配置
- 当前保护:仅 `highest_admin` 可读
- 返回:脱敏后的 `enabled / mode / botTokenConfigured / webhookSecretConfigured / allowFrom / groups / defaultProjectId / groupProjectRoutes`
#### `POST /api/v1/integrations/telegram`
- 用途:保存 Telegram Bot 接入配置,并可选执行 `getMe` 探测
- 当前保护:仅 `highest_admin` 可写
- 输入:
- `enabled`
- `mode`: `webhook | polling`
- `botToken`
- `dmPolicy`: `allowlist | open | disabled`
- `allowFrom`: Telegram user id 字符串数组
- `groupPolicy`: `allowlist | open | disabled`
- `groups`: Telegram chat id 字符串数组
- `requireMentionInGroups`
- `defaultProjectId`
- `groupProjectRoutes`: 群 / Topic 到 Boss 项目的路由表,单项格式为 `{ chatId, threadId?, projectId, label? }`
- `webhookSecret`
- `webhookUrl`
- `testConnection`
- 当前行为:
- `mode=webhook` 且提供 `webhookUrl` 时,会自动调用 Telegram `setWebhook`
- `mode=polling` 或关闭接入时,会自动调用 Telegram `deleteWebhook`
- `testConnection=true` 时会额外调用 `getMe`,并把返回的 bot username 回写到配置视图
#### `POST /api/v1/integrations/telegram/webhook`
- 用途Telegram Bot webhook 入口
- 当前保护:优先校验 `x-telegram-bot-api-secret-token`,再执行 DM / group allowlist
- 当前行为:
- 私聊文本默认桥接到 `master-agent`
- 群聊文本需要命中 `groups` 白名单;开启 `requireMentionInGroups` 时,必须 `@Bot` 或直接回复当前 Bot 上一条消息;进入主 Agent 前会自动清洗 bot mention
- 如果配置了 `groupProjectRoutes`,会优先按 `chatId + threadId` 精确匹配,再按 `chatId` 匹配,把消息写入指定 Boss 项目;未命中时回到 `defaultProjectId`
- 本地 fast path 回复会立即调用 Telegram `sendMessage`
- 需要排队的主 Agent 任务会保存 `externalReplyTarget`,任务完成后从 `/api/v1/master-agent/tasks/[taskId]/complete` 自动回推 Telegram
- 已处理的 `update_id` 会保留最近 256 条用于幂等去重
- 当前保护:要求 `x-boss-device-token` 或匹配登录会话
#### `GET /api/v1/master-agent/prompt-policy`
@@ -1080,6 +1387,7 @@
- local-agent 会周期性请求 `POST /api/v1/master-agent/tasks/claim`
- 认领到任务后会执行本机 `codex exec`
- `conversation_reply` 当前会优先走 `codex exec resume <targetCodexThreadRef>`,把任务恢复到真实 Codex 线程;只有缺失真实线程引用时才退回 `--ephemeral`
- 对已绑定 `targetCodexThreadRef` 的普通单线程 `conversation_reply`local-agent 现在会在 `codex exec resume` 前先把 Boss 用户消息镜像写入目标 Codex Desktop 线程 rollout镜像按 `sourceMessageId` 去重不会因任务重试重复写入。rollout 定位优先走 `state_5.sqlite`,不可用时回退扫描 `~/.codex/sessions`;状态库可写且能命中 thread 时会同步刷新线程活跃时间
- `dispatch_execution` 当前默认也走 `codex exec resume`,但当任务显式选择 `omx-team` 且本机 `omxEnabled + omxCommand/omxArgs` 可用时,会改走 `OMX Team Runtime` JSON 协议
- `codex exec resume` 前当前还会做目标线程绑定预检若目标线程缺失、已归档、cwd 不匹配或为只读会话,会直接失败并返回标准化错误,不继续把任务派进错误线程
- 如果历史 `worker / explorer` 子线程需要转回可开发线程,除了数据库权限本身,还必须显式补发新的解锁指令覆盖其旧的“只读勘察 / 不改文件”上下文;否则前台看起来像可写,实际执行仍可能被旧上下文限制
@@ -1094,15 +1402,32 @@
- `data/boss-state.json`
状态文件当前带有迁移前置元数据:
- `schemaVersion`:当前 BossState schema 版本
- `migratedAt`:最近一次从旧 schema 迁移到当前 schema 的时间
读取状态时会先经过 `migrateBossState`,用于从无版本或旧版本 JSON 补齐当前结构,并规范化授权和 Skill 生命周期相关数组。这个机制只为后续正式 DB 迁移提供稳定 schema 边界,不表示数据库化已经完成。
关键对象:
- `schemaVersion`
- `migratedAt`
- `user`
- `devices`
- `projects`
- `verificationCodes`
- `verificationDispatches`
- `adminCompanies`
- `adminNotifications`
- `adminRiskTimeline`
- `authAccounts`
- `authSessions`
- `accountDeviceGrants`
- `accountProjectGrants`
- `accountSkillGrants`
- `skillCatalog`
- `skillLifecycleRequests`
- `aiAccounts`
- `aiAccountSwitchHistory`
- `userAttachmentStorageConfigs`
@@ -1130,8 +1455,8 @@
不要误以为已经存在:
- 正式数据库
- 正式鉴权中间件
- 已直接切换完成的正式数据库
- 企业 SSO / IdP
- 多家对象存储适配(当前只有服务器文件存储和阿里 OSS
- 完整的附件详情页与富预览器
- 完整的多端用户会话系统与刷新令牌体系
- 完整的多端会话风控平台(当前已有 restore token 轮换、CSRF 基础防护和 MFA 开关)

View File

@@ -0,0 +1,83 @@
# Codex Server 协议与 Boss 执行进度卡接入记录
更新时间:`2026-05-08`
## 1. Codex 最新开放协议结论
当前可作为 Boss 稳定集成入口的是 Codex CLI MCP server
- 启动命令:`codex mcp-server`
- Inspector 调试:`npx @modelcontextprotocol/inspector codex mcp-server`
- 官方 MCP 工具:
- `codex`:启动一个 Codex 会话,入参包含 `prompt / approval-policy / base-instructions / config / cwd / include-plan-tool / model / profile / sandbox`
- `codex-reply`:继续一个 Codex 会话,入参包含 `prompt / threadId``conversationId` 只是兼容别名
- 线程续写应使用 `tools/call` 返回里的 `structuredContent.threadId`
- 现代 MCP 客户端主要读取 `structuredContent``content` 只作为旧客户端兼容输出
本机当前检测结果:
- 本机 `codex --version``codex-cli 0.114.0`
- npm 最新稳定包:`@openai/codex 0.129.0`
- npm alpha`0.130.0-alpha.5`
- 本机 `0.114.0` 已支持 `codex mcp-server --help`,但落后于当前 `0.129.0` 的 app-server / protocol 拆分、ThreadStore、MCP turn metadata、plugin sharing 等新能力
## 2. Boss 当前采用的接入策略
短期不直接依赖 Codex Desktop 私有 UI 结构,也不把 Codex CLI 原始 stderr/stdout 泄露给 APP。
当前实现采用 Boss 自有结构化消息:
- 新消息类型:`execution_progress`
- 服务端字段:`Message.executionProgress`
- 触发范围:
- 普通单线程对话:用户在 Boss APP 指定线程里发消息
- 主 Agent 托管线程:托管消息实际派到目标 Codex 线程时
- 群聊确认下发:后续目标线程执行单会复用同一张卡
- 生命周期:
- 任务入队:创建进度卡
- local-agent 认领:更新为 running
- local-agent 完成:更新同一张卡为 completed / failed
APP 展示结构对齐截图:
- `进度`:步骤列表,显示已完成 / 进行中 / 待处理 / 失败
- `分支详情`变更行、Git 操作、GitHub CLI 可用状态
- `生成结果`从执行结果里提取文件、图片、APK、文档等产物名
- `后台智能体`:预留 OMX / Hermes / explorer 等多智能体来源展示
## 3. 安全边界
进度卡只允许展示用户可见摘要:
- 不展示系统提示词
- 不展示完整执行 prompt
- 不展示设备 token、账号密钥、内部工作目录调度说明
- 不展示 Codex CLI 启动 envelope、sandbox、approval、session id、MCP 启动日志
- `RemoteRuntimeAdapter` 仍会先拦截只读环境提示和 Codex envelope 泄漏,再进入消息账本
## 4. 历史引用项目最新状态
本次按 GitHub 最新元数据核对过的项目:
| 项目 | 最新状态 | 对 Boss 的可借鉴点 |
| --- | --- | --- |
| `openai/codex` | `rust-v0.129.0`2026-05-07 发布main 在 2026-05-08 仍有提交 | 后续优先补 `codex mcp-server` 长驻适配器;参考 ThreadStore、turn metadata、app-server protocol v3 方向,不再只靠 `codex exec resume` |
| `Yeachan-Heo/oh-my-codex` | `v0.16.2`2026-05-08 发布 | `$ultragoal` 聚合目标、commit-shared wiki / compaction、state/session isolation、Codex native hook setup 值得同步到 Boss 的任务目标与进度卡 |
| `ultraworkers/claw-code` | main 最新提交 2026-05-06`instructkr/claw-code` 已指向该仓库;暂无 GitHub release | 继续保留抽象后端,不写死版本;重点观察 skills help routing、push_output_block、Rust harness 更新 |
| `NousResearch/hermes-agent` | `v2026.5.7 / v0.13.0`Tenacity Release | Durable Multi-Agent Kanban、heartbeat / reclaim / zombie detection、goal lock、checkpoints v2 可作为 Boss 主 Agent 长任务可靠性升级参考 |
| `iflytek/skillhub` | `v0.2.6`2026-04-29 发布main 2026-05-08 仍更新 | Skill 订阅通知、OIDC 登录、S3 IAM、namespace CSV 批量成员导入,适合 Boss 企业 Skill 治理后台后续吸收 |
| `openclaw/openclaw` | `v2026.5.7`2026-05-07 发布main 2026-05-08 仍更新 | Telegram allowlist、polling watchdog、deliverySucceeded、Codex approval 去重、provider/model callback 修复,可用于 Boss Telegram 网关和远程审批 |
| `goldmar/openclaw-code-agent` | `v4.2.3`2026-05-08 发布 | OpenClaw + Codex coding agent 的 session lifecycle、wake routing、worktree/PR policy可作为 Boss “聊天控制桌面 Codex 开发”的旁路参考 |
## 5. 下一步建议
第一阶段已经落地:
- Boss 消息账本新增 `execution_progress`
- Android 原生聊天页新增结构化进度卡
- local-agent 完成回写会补 Git diff、GitHub CLI 状态和产物名
后续建议按两步继续:
1. 新增 `CodexMcpBackendAdapter`:让 `codex mcp-server` 成为 `ExecutionBackend` 的可选实现,先 feature flag 默认关闭,保留 `codex exec resume` 作为生产主链。
2. 增加任务级 live progress API`POST /api/v1/master-agent/tasks/[taskId]/progress`,让本地 agent 在执行中也能实时刷新进度卡,而不是只在 claim / complete 两个节点更新。

View File

@@ -1,6 +1,6 @@
# Boss 当前运行与部署状态
更新时间:`2026-04-03`
更新时间:`2026-04-27`
## 1. 本地状态
@@ -20,7 +20,12 @@
- 登录接口:`POST http://127.0.0.1:3000/api/auth/login`
- 登录态接口:`GET http://127.0.0.1:3000/api/auth/session`
- 登录恢复接口:`POST http://127.0.0.1:3000/api/auth/restore`
- 登录会话治理接口:`GET/POST http://127.0.0.1:3000/api/v1/auth/sessions`
- 登出接口:`POST http://127.0.0.1:3000/api/auth/logout`
- 管理后台总览接口:`GET http://127.0.0.1:3000/api/v1/admin/overview`
- 独立企业后台 BFF`GET http://127.0.0.1:3000/api/v1/admin/backoffice`
- 管理后台授权接口:`GET/POST http://127.0.0.1:3000/api/v1/admin/access`
- 管理后台风险 SLA 扫描接口:`POST http://127.0.0.1:3000/api/v1/admin/risks/scan`
- OTA 包下载接口:`GET http://127.0.0.1:3000/api/v1/user/ota/package`
- 本地 agent 健康检查:`http://127.0.0.1:4317/health`。当前这台开发机的 `launchd` 常驻已经恢复,`/health` 可在数十毫秒内返回,并且在手动 heartbeat 执行期间也不会再被 Codex 线程扫描卡死
- 本地 Skill 扫描接口:`http://127.0.0.1:4317/api/v1/skills`
@@ -28,7 +33,9 @@
- `launchd` 已安装:`~/Library/LaunchAgents/com.hyzq.boss.local-agent.plist`
- 当前执行底座抽象层已落地在 `src/lib/execution/`,并已补齐 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现
- 当前生产主链仍然沿用 `local-agent -> codex exec resume -> /api/v1/master-agent/tasks/[taskId]/complete`,执行底座重构以“先抽象、不改行为”为准
- 当前 Codex server 调研结论已记录在 `docs/architecture/codex_server_progress_card_cn.md`:官方稳定入口是 `codex mcp-server` 的 MCP 协议,本机 `codex-cli 0.114.0` 已支持该命令但落后于 npm 最新 `0.129.0`Boss 当前先保留 `codex exec resume` 主链,并新增 `execution_progress` 结构化进度卡作为 APP 可见执行态
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有显式配置 `BOSS_CLAW_*` 且可用性探测通过时,`master-agent` 当前对话中才会出现并允许选择 `claw-runtime`
- 当前已新增最小 `Telegram Gateway`Boss 当前可直接暴露 Telegram webhook把 Telegram 私聊或受控群聊文本桥接进 `master-agent` 或按群 / Topic 路由到指定 Boss 项目,并在主 Agent 异步任务完成后自动回推 Telegram配置入口已接到 Web `/me/telegram` 和原生 Android `我的 > Telegram 接入`
- 如果历史上已经保存过 `backendOverride=claw-runtime`,但当前 `Claw Runtime` 不可用,运行时会自动回退到默认后端,并在 Web/Android 前台给出明确原因
- 当前仓库已自带 `scripts/claw-runtime-smoke.mjs` 作为本地 smoke runtime在没有真实 `claw-code` 可执行文件时,可先用 `BOSS_CLAW_COMMAND=node``BOSS_CLAW_ARGS=scripts/claw-runtime-smoke.mjs` 验证整条链
- 当前 `oh-my-codex` 已以最小 `OmxTeamBackendAdapter` 形式接入执行底座,但默认关闭;当前已经接到 Web 群聊详情页 / 原生群资料页的编排后端选择卡,可在 `Boss Native``OMX Team` 间切换OMX 不可用时会自动回退到默认后端并明确提示原因
@@ -40,6 +47,10 @@
- 当前 `conversation_reply / dispatch_execution` 的线程执行结果会先经过 `RemoteRuntimeAdapter` 标准化;如果线程返回的是固定模式的内部环境提示(如“当前会话环境只读 / cwd …”),会直接转成失败,不再把原文写回会话消息
- 当前设备模型已支持同一台 Mac / Windows 同时接入 Codex `GUI + CLI` 双能力Web / Android 设备详情页都会展示两种能力状态,并允许切换默认执行模式
- 当前同项目 `GUI / CLI` 并行写入风险已接入项目/文件夹级冲突控制:默认阻断,用户只能对当前异常项目/文件夹选择 `禁止 / 允许本次 / 永久放行`
- 当前已补上“Boss 统一电脑控制中枢”第二批本地 runtime主 Agent 已能把聊天请求识别为 `discussion_only / project_development / browser_control / desktop_control``browser_control / desktop_control` 已能作为正式 `MasterAgentTask` 入队,并返回 `executionMode / riskLevel / requiresConfirmation` 元数据给前台;本机 `local-agent` 现已把 `browser-control-task-runner.mjs / computer-use-task-runner.mjs` 升级成外部 runtime 桥,并默认带上 `scripts/browser-control-smoke.mjs / scripts/computer-use-smoke.mjs` 作为 smoke 执行器,后续只需要替换配置就能接真实 browser automation 与 computer use runtime
- 当前这两条控制链的 `control_summary` 已能回写结构化目标信息browser 会保留 `targetUrl`desktop 会保留 `targetApp`Android 聊天窗口会在控制结果卡片里直接显示执行目标
- 当前 `scripts/browser-control-smoke.mjs` 已提升到“最小真实浏览器探测”:如果目标 URL 可访问,会抓取页面 `<title>` 并回写结果;`scripts/computer-use-smoke.mjs` 也已升级为 macOS 默认 `osascript` 激活应用、引号文本输入、按需回车发送、`open -a` 兜底和 artifact 回写,因此 Boss App 里的 browser/desktop 控制消息都已开始返回真实执行结果而不是固定 smoke 文案
- 当前本机 `local-agent` 默认 heartbeat 已把 `browserAutomation / computerUse` 两项能力视为“已接通起步版 runtime”因此 Boss 前台设备能力会直接显示这两条链路在线;如果后续需要临时关闭,可在 `local-agent/config.cloud.json` 里单独下掉对应 connected 标记或 runtime 命令
本地已知运行方式:
@@ -90,19 +101,31 @@ cd /Users/kris/code/boss
- `npm start`、服务器 `systemd` 与远端 `npm run build` 当前都显式设置了 `BOSS_RUNTIME_ROOT`,避免 `process.cwd()` 在 standalone / 服务器构建阶段误扫描整个仓库
- `next.config.ts` 当前已把 `deployment / docs / design / local-agent / prompts / scripts / android` 等目录排除出 standalone tracing服务器端构建不会再把非运行时资产卷进 `.next/standalone`
- `data/boss-state.json` 的写入已经改成串行事务队列、原子替换和 `.bak` 备份恢复,`heartbeat` 与 APP 日志并发写入已复核通过
- `BossState` 当前新增 `schemaVersion / migratedAt` 元数据和 `migrateBossState` 迁移入口;读取旧的无版本状态时会补齐当前 schema并规范化 `accountDeviceGrants / accountProjectGrants / accountSkillGrants / skillLifecycleRequests / permissionAuditLogs`
- 这只是正式数据库迁移前置层,当前生产读写仍然是 `data/boss-state.json`,尚未完成 PostgreSQL / Redis / 其他 DB 落地
- 当前登录成功后会写入 `boss_session` Cookie`会话 / 设备 / 我的 / 线程` 页面以及主要 `/api/v1/*` 路由都要求有效会话
- 当前 `boss_session` 默认保持 30 天,`Set-Cookie` 已验证为 `Max-Age=2592000`
- 原生 Android 客户端当前会把登录返回的 `boss_session / restore token / account` 落到 `SharedPreferences`,并在 APP 启动时通过 `/api/auth/restore` 自动补回会话;已本地验证“登录 -> 取 restore token -> restore 接口恢复”链路
- 当前多用户 / RBAC 第一阶段已落地:状态文件新增 `accountDeviceGrants / accountProjectGrants / accountSkillGrants / skillCatalog / skillLifecycleRequests / permissionAuditLogs`,非最高管理员访问 `devices / conversations / projects / messages / device skills / state` 时都会先走 `src/lib/boss-permissions.ts` 和 session-aware projections 过滤
- 当前最高管理员授权管理接口已落地:`GET/POST /api/v1/admin/access` 可以查看脱敏账号、公司、设备、项目、Skill、授权、权限模板和审计日志并支持公司管理、公司启用/停用、账号/设备归属、批量导入预览、批量导入子账号、重置子账号密码、离职回收、创建/更新子账号、启用/停用子账号、授予设备/项目/Skill 权限、套用权限模板、撤销授权;停用公司会禁用该租户普通子账号并撤销会话,停用 / 回收 / 重置账号也会撤销该账号当前活跃会话,普通账号访问返回 `403`
- 当前 To B 管理后台第一版可操作面已经落地Web `/admin``highest_admin` 可进,包含 `总览 / 账号与授权 / Skill 治理` 三个页签;总览使用 `/api/v1/admin/overview`,账号与授权复用 `/api/v1/admin/access`Skill 治理复用 `/api/v1/admin/skills/requests`;公司聚合优先使用显式 `adminCompanies`,未绑定时才回退账号域名。
- 当前企业级后台独立化第一批已开始落地:新增 `apps/boss-admin-web` 作为 Vue + Vite + Ant Design Vue 独立 PC 后台骨架,新增 `/api/v1/admin/backoffice` 作为 YuDao/Vben 风格 BFF现有 `/admin` 暂保留为主站 fallback`admin.boss.hyzq.net` 后续再切到独立后台静态产物。
- 当前后台风险处理接口已落地:`POST /api/v1/admin/risks/actions``highest_admin` 可用,支持对 `ops_fault` 指派负责人、设置 SLA、确认、关闭、创建或复用修复工单`thread_context_alert` 指派负责人、设置 SLA、确认和关闭`POST /api/v1/admin/risks/scan` 会扫描超时 SLA 并幂等写入 `adminNotifications`,管理后台总览会展示开放风险通知;不支持的风险类型会明确返回 `RISK_ACTION_UNSUPPORTED`
- 当前权限审计查询第一版已落地:`GET /api/v1/audits/permission-logs``highest_admin` 可读,支持按 `action / actorAccount / targetAccount / deviceId / projectId / skillId / cursor / limit` 查询 `permissionAuditLogs`并实时返回短时间大量授权、Skill lifecycle 失败、过期授权仍存在、admin route 拒绝访问等 deterministic 风险摘要;后台 mutation 审计已支持 `ipAddress / userAgent / requestId / beforeJson / afterJson`其中重置密码会记录安全化前后快照Web `/me/ops/audit` 会向最高管理员展示最近权限审计和风险摘要
- 当前 Skill 远程治理第一版可执行链路已落地:`GET/POST /api/v1/admin/skills/requests` 仅允许 `highest_admin` 创建和查看 `install / update / uninstall / rollback / version_lock` 请求;设备端通过 `/api/v1/devices/[deviceId]/skill-requests/claim``/complete` 认领回写local-agent 默认每 5 秒执行本机 Skill 安装 / 更新 / 卸载 / 回滚 / 版本锁,并同步最新 Skill 清单。远程安装或带 `sourceUrl` 的更新必须命中本机 `skillLifecycleAllowedSources``skillLifecycleTrustedSources`;配置为空时不允许远程新来源安装,但保留既有本地 Skill 的更新 / 回滚 / 卸载 / 版本锁。携带 `checksum / expectedChecksum` 的请求会校验 `manifest.json``SKILL.md` 的 sha256更新 / 卸载 / 回滚前会写入 `skillsDir/.boss-skill-backups` 并在失败时尽量恢复
- 当前授权管理前台已接入Web `/me/access` 与原生 Android `我的 > 用户与权限` 仅最高管理员可见,可创建子账号、授权设备/项目/Skill、套用 `只读观察员 / 项目开发者 / 设备操作者` 模板、查看同名 Skill 跨设备聚合并撤销单条授权
- 当前权限继承规则:显式 `device.view` 可带来绑定该设备项目的只读可见性,但不会自动获得 `thread.chat / master_agent.ask / master_agent.takeover / computer.control / skill.use`;这些动作必须来自项目或 Skill 显式授权
- 当前主 Agent 执行链已经使用授权快照:`boss-master-agent.ts` 会先按请求账号裁出可见设备、项目、线程状态、进展事件和 Skill再生成执行提示词排入 `MasterAgentTask` 时会记录本次授权范围,供后续审计和执行器收敛
- 登录成功后的客户端跳转当前已做稳态兜底:会先确认 `/api/auth/session` 已可读,再 `replace``/conversations`,并补一次 `window.location.replace` 防止真机 WebView 偶发卡在登录提示页
- `POST /api/auth/send-code` 当前已增加 60 秒冷却和 15 分钟窗口限流
- `POST /api/auth/send-code` 当前还会先按用途校验账号状态:登录 / 忘记密码必须是已存在账号,注册必须是未注册账号
- 当前账号连续登录失败 5 次后会锁定 10 分钟
- 当前登录页已临时切到免验证模式;点击“登录”会直接创建最高管理员会话,不再校验账号密码或验证码
- 当前登录页默认要求账号密码或验证码校验;临时开发兜底只有显式设置 `BOSS_AUTH_AUTO_LOGIN=1/true/yes` 时才会开启
- 新注册和重置密码当前已切到 `scrypt` 哈希;历史 `sha256` 密码会在下一次密码登录时自动迁移
- `launchd` 会保持 `com.hyzq.boss.local-agent` 常驻,所以本地 agent 被手动结束后会自动重启
- `launchd` 默认加载 `local-agent/config.cloud.json`,控制面指向 `https://boss.hyzq.net`
- `local-agent/config.example.json` 仍保留给本地 `127.0.0.1:3000` 回环开发
- 本地 `launchd` 当前已把 `mac-studio` 作为 `17600003315` 的绑定 Codex 节点上报
- 本地 `launchd` 当前已把 `mac-studio` 作为 `krisolo` 的绑定 Codex 节点上报
- 本地 agent 当前会递归扫描 `~/.codex/skills`,并把本机 Skill 同步到云端设备维度
- 根布局当前会挂载 APP 日志桥,路由切换、运行时错误、消息发送和 OTA 操作会通过 `/api/v1/app-logs` 实时同步到服务器;日志绑定已改成按当前登录会话解析设备
- 根布局当前还会挂载原生运行时桥:维护 APP 内导航历史、拦截 Android 返回键、防止根页直接退回桌面,并在 OTA / 同签名覆盖安装后自动尝试恢复登录态
@@ -123,6 +146,9 @@ cd /Users/kris/code/boss
- 当前原生聊天页已把待审批推荐前移到主消息流:`ProjectDetailActivity` 会直接显示 `确认下发 / 拒绝` 操作,且刷新后仍能恢复最近一条待确认推荐
- 当前 `approval_required` 群聊在已经存在一条 `pending_user_confirmation` 推荐时,会拒绝继续创建新的推荐并返回 `409`,前台会提示用户先确认或拒绝当前推荐
- 当前普通单线程聊天也已补上真实执行链:`POST /api/v1/projects/[projectId]/messages` 不再只写用户消息,而是会追加 `conversation_reply` 任务;绑定设备上的 `local-agent` 认领后会继续恢复到真实 Codex 线程,再把线程原始回复回写到该聊天窗口
- 当前 Boss APP 到 Codex 桌面版的记录同步以数据层镜像为主:普通单线程消息和托管模式消息都会把 APP 用户原文作为干净 `user_message` 写入目标 Codex 线程 rollout并同步刷新 Codex thread 的 `updated_at / updated_at_ms`;托管链路不会把主 Agent 内部调度 prompt、系统提示词或权限字段镜像成桌面可见聊天记录
- 当前 `local-agent` 已补 `Codex Desktop Refresh Bridge`rollout 镜像完成后会优先 POST 到本机常驻 `http://127.0.0.1:4318/api/v1/codex-desktop/refresh`,由 `scripts/codex-desktop-refresh-bridge-daemon.mjs` 给 Codex 桌面版发安全刷新提示daemon 不可用时回退到 `scripts/codex-desktop-refresh-hint.mjs` 命令式刷新。默认 `deeplink-reload` 模式会打开 `codex://threads/{threadId}` 目标线程深链,并在短延迟后发送一次应用刷新快捷键;它仍不模拟聊天输入、不点击、不发送。刷新桥默认会对短暂失败重试 2 次、每次间隔 120ms并把 deep link 与尝试次数作为结果返回;失败只记 `local_agent.codex_desktop_refresh_failed`,不会回滚已经写入的线程消息。当前 bridge 还暴露 `GET /api/v1/codex-desktop/events` SSE 和 `GET /api/v1/codex-desktop/events/recent`,每次刷新 hint 都会广播不含消息正文、不含内部 prompt 的 `codex_desktop_refresh` 事件;`scripts/codex-desktop-event-consumer.mjs` 是后续 Codex Desktop 插件/IPC 的订阅样例,可用 `BOSS_CODEX_DESKTOP_EVENTS_ONCE=true` 做一次性 smoke
- 当前 bridge 还暴露 `GET /api/v1/codex-desktop/capabilities`,内部复用 `scripts/codex-desktop-integration-probe.mjs` 探测当前 Codex Desktop读取 `Info.plist`、确认 `codex` URL scheme、扫描 `app.asar` 中是否存在 `codex://threads/`,并明确返回 `packagePatch.supported=false`,避免后续误走修改签名 app 包体的路线
- 当前 Web 群聊详情页也已补上待确认推荐的刷新恢复:服务端会在页面渲染时读取最近一条 `pending_user_confirmation` 的 dispatch plan聊天输入区会继续显示“等待你确认主 Agent 推荐”,不再因刷新丢失确认入口
- 当前 `AI 账号` 页面已分成三条显式接入链:`登录 OpenAI 平台账号API Key``接入阿里百炼备用账号``绑定 Master Codex Node`OpenAI API 登录成功后会立即切成当前主控,阿里百炼账号会作为备用链路保存
- 当前 `登录 OpenAI 平台账号` 已升级成浏览器辅助登录流:原生 Android 会先进入 `OpenAiOnboardingActivity`,自动打开 `OpenAI Platform` 登录页;用户登录后可直接跳到 `API Keys` 页面,回 APP 粘贴 key 完成接入
@@ -138,8 +164,8 @@ cd /Users/kris/code/boss
- 当前设备导入主链也已补上第一轮后端闭环:`heartbeat` 可上报真实项目候选,服务端会生成 `deviceImportDraft`;用户可提交勾选结果、生成导入决议,再把选中的线程真正落成聊天窗口
- Web 与原生 Android 当前都已补上“新设备导入草稿 -> 勾选 -> 决议预览 -> 应用导入”的前台流程;已绑定生产设备继续保留 heartbeat 自动导入主链
- 当前设备导入前台的状态表达已经统一为:`等待候选线程 / 等待勾选 / 建议生成中 / 建议已生成 / 已导入`,并会回显最终导入的线程名
- 当前已导入设备也支持自动同步项目理解:绑定设备 heartbeat 发现活跃线程有新活动、或线程回写了新的执行结果时,系统会直接为这台设备上已导入的线程排隐藏的 `conversation_reply` 主 Agent 任务,回写最新的项目目标、当前进度、技术架构和下一步建议
- 当前自动同步链路已经拆成两层heartbeat / thread reply 默认只追加轻量 `threadProgressEvent`;只有在线程首次理解、文档信息过薄、距离上次全量刷新太久或主 Agent 真的要接手时,才补排隐藏的全量理解任务并更新 `ThreadStatusDocument`
- 当前已导入设备的项目理解同步已经收窄到“显式接管 / 用户主动要求同步”边界:绑定设备 heartbeat 或线程回写默认只追加轻量 `threadProgressEvent`,不会在未接管状态下主动向 Codex 线程发起隐藏对话
- 当前全量理解链路只在单线程接管有效、全局接管有效,或用户明确要求“同步/核对项目目标和版本记录”时排 `conversation_reply` 任务;关闭接管会同步清理仍在 queued/running 的项目理解同步任务,避免取消接管后继续主动打扰线程
- 当前群资料页已补上“修复群成员”入口:当群里存在失效线程引用、`master-agent` 这类不可下发成员,或真实线程成员少于 2 个时,前台会明确提示并允许重新选择真实线程成员
- 当前原生聊天页也已前移“修复群成员”入口:脏群会在消息流上方直接显示 `去修复` 按钮,并跳转到群资料页完成成员替换
- 当前当 heartbeat 同时携带旧 `projects` 和新 `projectCandidates` 时,服务端会优先走 `deviceImportDraft`,不再绕过勾选/审核阶段直接自动导入聊天窗口
@@ -148,7 +174,8 @@ cd /Users/kris/code/boss
- 当前设备导入 `review` 已补 owner/admin 鉴权,并已切成真实异步审核:`review` 会先排队 `device_import_resolution` master task前台进入“主 Agent 审核中”并自动刷新;导入草稿在 `apply` 后再次 heartbeat 也不会从 `applied` 回退成 `resolved`
- 原生会话页当前的刷新失败策略已改成按当前 tab 独立判错:`会话` 不会再因为 `设备 / OTA / 设置` 的旁路请求失败而整体提示“刷新失败”
- 会话页、设备页、技能页和项目详情页当前都通过 `/api/v1/events` 的 SSE 自动刷新
- 我的页当前保留 `账号与安全 / 设置 / 运维与修复 / AI 账号 / 技能 / 关于` 六个一级入口;`AI 账号` 支持查看 `主 GPT / 备用 GPT / API 容灾`,并明确主链路优先走已经在绑定电脑上登录 `ChatGPT Plus / Codex` `Master Codex Node`
- 我的页当前保留角色感知入口:`member` 只显示 `账号与安全 / 设置 / 技能 / 关于`,其中 Skill 列表继续由服务端按授权过滤;`admin / highest_admin` 额外显示 `运维与修复 / AI 账号 / 附件与存储 / Telegram 接入``用户与权限` 只给 `highest_admin`
- `AI 账号` 支持查看 `主 GPT / 备用 GPT / API 容灾`,并明确主链路优先走已经在绑定电脑上登录 `ChatGPT Plus / Codex``Master Codex Node`
- `AI 账号` 页当前已补上显式 `登录指引`:手机端不会直接弹出 ChatGPT OAuth`主 GPT` 需要先在绑定电脑上的 Codex / ChatGPT Plus 会话里登录,再回手机端点“测试连接 / 校验连接”
- `AI 账号` 页当前已升级成双入口:首页会显式展示 `登录 OpenAI 平台账号``绑定电脑上的 Codex 节点`
- `登录 OpenAI 平台账号` 当前通过填写 `OpenAI API Key` 完成;校验成功后会立即设为当前主控
@@ -157,6 +184,8 @@ cd /Users/kris/code/boss
- 因此 `POST /api/v1/accounts/onboard/openai-api` 在公网环境下已经能返回明确中文网络错误,但在服务器出网恢复前,还不能完成真实 OpenAI 平台账号探针与调用
- `POST /api/v1/accounts/[accountId]/validate` 当前对 `master_codex_node` 不再只看 `nodeId`,还会同时校验绑定设备是否在线;设备离线时返回 `degraded` 和清晰的人类可读提示
- 主 Agent 当前真实对话链路已验证通过:`Boss Web -> /api/v1/projects/master-agent/messages -> master-agent task queue -> local-agent -> codex exec -> /complete -> 项目消息账本`
- Telegram 当前真实对话链路已接通:`Telegram Bot webhook -> /api/v1/integrations/telegram/webhook -> master-agent -> /api/v1/master-agent/tasks/[taskId]/complete -> Telegram Bot sendMessage`
- Telegram 配置保存当前也会自动做 webhook 同步webhook 模式自动 `setWebhook`polling/关闭时自动 `deleteWebhook`
- 主 Agent 单聊当前已改成“快速入队 + 异步回流”:`POST /api/v1/projects/master-agent/messages` 会先返回 `masterReplyState + task`,真实回复随后再回写消息账本
- 当前对话级 `agentControls` 已经生效:`master-agent` 会话支持 `modelOverride / reasoningEffortOverride`,并会优先作用到实际 OpenAI 回复和 Master Codex Node 执行 prompt
- 当前对话级 `agentControls` 也已支持 `backendOverride``master-agent` 会话可在 `Claw Runtime` 可用时显式选择 `claw-runtime`,由 `ExecutionBackendSelector` 在当前对话里优先尝试对应后端;不可用时保存接口会直接拒绝,并返回人类可读原因
@@ -170,19 +199,19 @@ cd /Users/kris/code/boss
- `npm run aab:release` 当前会先准备本机 release keystore再构建 signed release AAB 并发布到 `public/downloads/boss-android-latest.aab`
- AAB 发布脚本当前还会额外保留带版本号的归档包:`public/downloads/boss-android-v{versionName}-{flavor}.aab`
- AAB 归档元数据会写入 `public/downloads/boss-android-latest-aab.json`
- 当前默认管理员账号:`17600003315`
- 当前默认测试密码`boss123456`
- 登录页当前是临时免验证入口;Web 登录页和原生 Android 登录页都会直接创建会话
- 当前默认管理员账号:`krisolo`
- 当前默认测试密码由线上初始化配置管理,文档不再明文记录
- Web 登录页和原生 Android 登录页默认都必须通过账号密码或验证码校验后才会创建会话
- 当前已生成 Android debug APK`android/app/build/outputs/apk/debug/app-debug.apk`
- 当前已生成 Android signed release APK`android/app/build/outputs/apk/release/app-release.apk`
- 当前 release 构建还会额外生成带版本号的 APK`android/app/build/outputs/apk/release/boss-android-v{versionName}-release.apk`
- 当前最新 release 构建版本:`2.5.11``versionCode=24`
- 当前 release keystore 位于本机 `android/keystores/boss-release.keystore`,签名参数位于 `android/signing/release-signing.properties`
- 真机开发约束:除非用户明确要求切换设备,后续 Android 开发、ADB 安装、交互回归与问题复现统一使用 `PLB110`;如果 `PLB110` 当前不在线,应先恢复这台设备连接,不自动切到其他手机
- 真机开发约束:用户已明确切换到当前连接的 OPPO `PHZ110`ADB serial `U84XJRIB7D65ZH45`除非用户再次要求切换设备,后续 Android 开发、ADB 安装、交互回归与问题复现统一使用这台 OPPO不再回退到原 `PLB110`
- Android 真机无线调试当前可恢复使用但系统层面没有“永久保持无线调试开启”的官方稳定开关重启、切网、ADB server 重启或重新切换 USB 调试后,都可能自动失效
- 如果要尽量稳定,当前推荐做法是:同一局域网下先走 USB 启用,再执行 `adb tcpip 5555``adb connect <phone-ip>:5555`;同时固定同一 SSID、避免切热点/VPN、开启“保持唤醒”并保留 USB 作为长时间调试兜底
- `2.0.1` 已在本机连接的华为真机上复核通过,修复了 `Theme.SplashScreen` 导致的 `AppCompatActivity` 启动闪退
- `2.1.0` 已把 Web 一级页和主要二级页全部补成原生活动页:`MainActivity / ProjectDetailActivity / ProjectGoalsActivity / ProjectVersionsActivity / ProjectForwardActivity / ThreadDetailActivity / DeviceDetailActivity / DeviceEnrollmentActivity / SkillInventoryActivity / SecurityActivity / SettingsActivity / AiAccountsActivity / OpsCenterActivity / AboutActivity`
- `2.1.0` 已把 Web 一级页和主要二级页全部补成原生活动页:`MainActivity / ProjectDetailActivity / ProjectGoalsActivity / ProjectVersionsActivity / ProjectForwardActivity / ThreadDetailActivity / DeviceDetailActivity / DeviceEnrollmentActivity / SkillInventoryActivity / SecurityActivity / AccessManagementActivity / SettingsActivity / AiAccountsActivity / OpsCenterActivity / AboutActivity`
- `2.1.0` 已完成签名包覆盖安装到本机连接的华为真机,并确认 `com.hyzq.boss` 可以成功拉起进程
- `2.1.1` 已补上原生 OTA 下载安装引导、`REQUEST_INSTALL_PACKAGES` 权限声明,以及根页默认入口/返回逻辑收口
- `2.2.0` 已把原生 UI 回退到微信式交互:会话首页改为简单聊天列表,项目详情页改为聊天优先,只保留 `项目目标 / 版本记录` 两个轻入口,设备页和我的页根面改为简单列表
@@ -201,16 +230,24 @@ cd /Users/kris/code/boss
- `2.5.5` 已给 `approval_required` 群聊补齐“确认 / 拒绝”两条审批动作;拒绝后会把群审批状态写成 `rejected`,并追加系统提示,不再继续下发到线程
- `2.5.11` 对应这一轮的主链收口Android 会话首页改为直接读取 `/api/v1/conversations`,会把这台 Mac 上已导入的 Codex 线程对话直接平铺出来;`master-agent` 对“操作真实线程”的请求会先生成推荐下发方案,确认后再把任务派到真实线程执行;线程无绑定或设备离线时,确认接口会给清晰失败原因,避免假成功状态
- 当前附件分析任务已带受控 `task token` 下载链接和文本摘录:本地开发环境会跟随请求 origin 生成链接,生产环境默认走 `https://boss.hyzq.net`
- `2.5.11` 当前补齐了消息删除闭环:`DELETE /api/v1/projects/[projectId]/messages?messageId=...` 会删除账本消息、刷新会话预览并推送实时事件Android 长按消息的“删除”已接入该接口
- `2.5.11` 当前补齐了原生 `我的 > 附件与存储` 入口Android 可直接查看当前存储方式,切换服务器文件存储 / 阿里 OSS并支持保存或测试并保存
- `2.5.11` 当前后台通知已扩展到所有会话里的主 Agent 回复:只要 APP 不在前台,线程会话内的主 Agent 接管回复也会触发 Android 系统通知
- `2.5.x` 当前已补上会话首页独立建群入口:可以不从单线程聊天内部出发,直接在会话首页右上角 `+` 建立新群聊;同时已把多个原生自定义 top bar 页面统一纳入状态栏安全区处理
- 当前 `local-agent` 已能回写带 `dispatchExecutionId / targetProjectId / targetThreadId / rawThreadReply` 的任务完成载荷,群聊分发执行结果不再只停留在主 Agent 队列
- 当前 `local-agent``conversation_reply` 任务会优先使用 `codex exec resume <targetCodexThreadRef>`,只有缺失真实线程引用时才退回 `--ephemeral`
- 当前已绑定真实 `codexThreadRef` 的普通单线程聊天,会在 `local-agent` 执行 `codex exec resume` 前,先把 Boss 用户消息镜像写入对应 Codex Desktop rollout这样 APP 发起的消息也能进入桌面版同一线程历史,并按 `sourceMessageId` 去重。rollout 定位优先使用 `state_5.sqlite`,状态库不可用或索引缺失时回退扫描 `~/.codex/sessions`;写入后会尽量刷新 `threads.updated_at / updated_at_ms / has_user_event`,再通过 `codex://threads/{threadId}` 深链提示桌面版打开目标线程
- 当前 `local-agent``dispatch_execution` 任务会按 `orchestrationBackendId` 分流:默认走 `codex exec resume`;当任务显式选择 `omx-team` 且本机 `omxEnabled + omxCommand/omxArgs` 可用时,会改走 `OMX Team Runtime` JSON 协议执行并回写 `rawThreadReply / replyBody`
- 当前 `local-agent` 会在 Codex 任务完成时回传 `executionProgress`:服务端把同一任务的进度卡从 queued / running 更新到 completed / failedAndroid 原生聊天页会显示“进度 / 分支详情 / 生成结果 / 后台智能体”,其中 Git diff、GitHub CLI 可用性和产物名由本地 agent 补齐
- 当前 `local-agent``browser_control / desktop_control` 已从占位骨架升级成外部 runtime 桥:当本机配置了 `browserControlEnabled + browserControlCommand``computerUseEnabled + computerUseCommand` 时,会把标准化 JSON 请求透传给外部进程,并解析单行 JSON 结果;未启用时会 fail closed返回明确的 runtime disabled 错误,不再假装执行成功
- 当前历史脏群如果不再包含真实线程成员,群聊消息不会再表现成“无响应”;服务端会在群内追加明确 `system_notice`,提示先重新添加线程成员
- 当前设备导入决议已经升级成真正通过 `local-agent -> codex exec -> /complete` 回写的主 Agent 决议链Web 和 Android 前台都会在 `pending_resolution` 阶段显示审核任务状态,并在任务完成后自动刷新出正式导入建议
- 当前 `local-agent` 已改成先启动本地 `4317` 健康监听,再异步跑首次 heartbeat 和 task poll避免控制面短时阻塞时本地健康探针不可用
- 当前 heartbeat 上报 `browserAutomation / computerUse` 能力时,不再只看静态 `browserAutomationConnected / computerUseConnected` 布尔值;如果本机已经配置可执行的 browser/computer runtime也会自动把对应能力标记成 connected
- Codex 项目/线程扫描当前已搬到 worker 线程执行,避免 `.codex/logs_1.sqlite``state_5.sqlite` 的同步扫描阻塞主线程健康接口
- 当前 `local-agent` 的任务完成回写已通过 `RemoteRuntimeAdapter` 标准化,`conversation_reply / dispatch_execution` 的完成载荷会先做统一归一化,再进入主 Agent 完成路由
- 原生 Android 当前对 `master-agent` 聊天不再依赖长时间同步等待;发送后会先显示“主 Agent 思考中”,右上角改成微信式 `...` 菜单,菜单项包含 `模型 / 推理强度 / 会话信息 / 刷新`
- 原生 Android 当前已新增 `TelegramIntegrationActivity`:可从 `我的 > Telegram 接入` 查看当前 Bot 状态、配置 Bot Token / Webhook Secret / Webhook URL、私聊白名单、群聊白名单、群聊触发策略和群 / Topic 到 Boss 项目的路由;群聊可配置为只接受 `@Bot` 或直接回复当前 Bot 的消息,并可直接测试连接或保存配置
## 2. 服务器状态
@@ -237,7 +274,8 @@ cd /Users/kris/code/boss
- `boss-web` 当前通过 `npm start` 启动
- 实际监听端口为 `3000`
- `boss-web.service` 显式设置了 `BOSS_STATE_FILE=/opt/boss/data/boss-state.json`
- `Caddy` 反代 `127.0.0.1:3000`
- `Caddy` 反代 `127.0.0.1:3000``boss.hyzq.net` 服务客户 Web / App API`admin.boss.hyzq.net` 作为平台总后台独立 PC 入口并把根路径跳转到 `/admin`
- 服务器上存在 `gptpluscontrol-boss-caddy-reconcile.timer`,会周期性用 `/home/ubuntu/build/gptpluscontrol/deploy/server/caddy.boss_hyzq_net.gptpluscontrol.conf` 重写 `/etc/caddy/Caddyfile``/opt/boss/deployment/Caddyfile`;以后改 Caddy 入口必须同步更新这份 canonical否则会重新生成重复站点块并导致 Caddy reload 失败
- `Postfix` 监听 `25 / 465 / 587`
- `Dovecot` 监听 `993`
- 当前部署脚本在远端重启服务后会自动执行一遍本机 health check
@@ -257,10 +295,12 @@ cd /Users/kris/code/boss
- 服务器本机 `dig +short boss.hyzq.net` 返回 `106.53.170.158`
- 服务器本机访问 `http://boss.hyzq.net` 会被 `308` 跳转到 `https://boss.hyzq.net`
- 服务器本机执行 `curl --resolve boss.hyzq.net:443:127.0.0.1 https://boss.hyzq.net -I` 返回 `307` 并跳转到 `/auth/login`
- 当前 `admin.boss.hyzq.net` 用于平台总后台,应用根路由会在该 host 下把已登录用户送到 `/admin`,未登录用户送到 `/auth/login`
同时也确认了这些事实:
- 当前本机网络 `dig +short boss.hyzq.net` 仍返回 `198.18.1.188`
- 当前本机网络 `dig +short admin.boss.hyzq.net` 暂无 A 记录;需要在 DNSPod 增加 `admin -> 106.53.170.158`
- 当前本机网络 `curl -I http://boss.hyzq.net` 返回 `308`
- 当前本机网络 `curl -I https://boss.hyzq.net` 返回 `HTTP/2 307`,并跳转到 `/auth/login`
- 当前本机网络 `curl https://boss.hyzq.net/api/health` 返回 `{"ok":true,"service":"boss-web",...}`
@@ -283,13 +323,13 @@ cd /Users/kris/code/boss
## 4. 当前未完成或仅为 MVP 的部分
- 当前服务器默认仍是 `fixed`,验证码`000000`
- 当前服务器默认仍是 `fixed`验证码登录必须先通过 `send-code` 生成账本记录;不能只靠固定码直接登录
- 当前虽然已经补齐 OTA 版本中心、检查更新、执行升级和 APK 包下载链路,但仍是文件型状态驱动的 MVP不是原生增量更新基础设施
- 当前“OTA / 重装后不掉登录”覆盖原生 Android 客户端的 `SharedPreferences` 恢复与同签名覆盖安装;如果用户先卸载 APP 再全新安装,仍可能丢失本地原生存储
- 数据存储仍是文件型,而不是数据库
- 数据存储默认仍是文件型,但已经有 PostgreSQL store adapter、schema 和维护脚本生产切换前需先执行备份、dry-run 迁移和回滚演练
- 设备发现、项目扫描和额度采集仍是静态配置驱动的 MVP
- APP 实时日志当前已能同步到主 Agent 会话,但还没有单独的日志检索、分页和告警升级规则
- Skill 清单当前按设备同步和展示已经可用,但还没有“安装 / 卸载 Skill”这种远程管理能力
- Skill 清单当前按设备同步和展示已经可用;远程治理目前只有最高管理员创建 lifecycle 请求和 list 状态,尚未真正下发到设备端执行安装 / 更新 / 卸载 / 回滚
- 服务器侧主 Agent 实时回复依赖被绑定设备的 `local-agent` 在线并能执行 `codex exec`;如果设备离线,只能保留任务或走 API 容灾账号
- 设备导入主链的后端状态机已经跑通,并且已经分成两条:
- 新接入设备继续走 `import draft -> 勾选 -> review -> apply`
@@ -304,7 +344,9 @@ cd /Users/kris/code/boss
- 原生 Android 的二级深层页虽然仍保留 `ProjectForwardActivity / ThreadDetailActivity / OpsCenterActivity` 等能力,但它们已经退出主 UI 正面;后续如再加入口,需继续遵守“一级微信式,复杂能力下沉”的规则
- Android 本地 Gradle 验证当前必须串行执行;如果并发跑 `testDebugUnitTest / compileDebugJavaWithJavac / assembleDebug`,会导致中间产物互踩并出现假失败
- 聊天附件当前已经支持真实上传、消息落账本、受保护下载和原生打开;默认后端为服务器文件存储,可按用户切到阿里 OSS 私有桶
- 认证虽然已有最小会话 Cookie但还没有刷新令牌、跨端会话治理、CSRF 防护和更细的风控策略
- 企业认证默认值已收紧:`POST /api/auth/login` 默认不再允许临时免验证登录,只有显式设置 `BOSS_AUTH_AUTO_LOGIN=1/true/yes` 才会开启开发兜底。
- 状态存储现在通过 `src/lib/boss-state-store.ts` 抽象,默认继续使用 `data/boss-state.json`;设置 `BOSS_STATE_STORE=postgres` 时必须同时配置 `BOSS_DATABASE_URL`schema 见 `scripts/postgres-state-schema.sql`
- 认证已补 CSRF 基础防护、restore token 轮换、账号锁定和子账号 MFA 开关;后续仍可继续补更完整的企业 IdP / SSO
- 邮件对外正式投递仍缺少 DNS / 信誉相关的最终收口,例如 SPF、DKIM、DMARC、MX 与退信策略
- 外部真实邮箱的 end-to-end 收件链路还没有在生产账号上完成最终验收
@@ -314,11 +356,13 @@ cd /Users/kris/code/boss
```bash
curl -sS http://127.0.0.1:3000/api/health
curl -sS -H 'Content-Type: application/json' -d '{"account":"17600003315","password":"boss123456","method":"password"}' http://127.0.0.1:3000/api/auth/login
curl -sS -H 'Content-Type: application/json' -d '{"account":"krisolo","password":"<admin-password>","method":"password"}' http://127.0.0.1:3000/api/auth/login
curl -sS http://127.0.0.1:3000/api/auth/session
curl -sS http://127.0.0.1:3000/api/v1/conversations
curl -sS http://127.0.0.1:3000/api/v1/projects/master-agent
curl -sS http://127.0.0.1:3000/api/v1/devices/mac-studio/skills
node scripts/boss-state-store-maintenance.mjs backup-file --dry-run
node scripts/boss-state-store-maintenance.mjs migrate-file-to-postgres --dry-run
curl -I http://127.0.0.1:3000/api/v1/user/ota/package
curl -sS http://127.0.0.1:4317/health
curl -sS http://127.0.0.1:4317/api/v1/skills

View File

@@ -0,0 +1,88 @@
# Boss 依赖漏洞治理记录
更新时间:`2026-04-27`
## 本次治理范围
- 处理 Web/npm 依赖:`package.json``package-lock.json`
- 处理应用源码中与漏洞依赖绑定的附件存储实现:`src/lib/boss-storage-aliyun-oss.ts`
- 处理构建追踪 warning`src/lib/boss-mail.ts`
- 未改 Android 工程、`local-agent` 或部署脚本。
- 修复策略:先运行 `npm audit --json` 定位来源;不使用 `npm audit fix --force`;对没有安全小版本升级路径的依赖链,改为移除依赖并用项目内最小实现替换。
## 漏洞统计
治理前 `npm audit --json`
- total`14`
- high`6`
- moderate`2`
- low`6`
- critical`0`
第一轮治理后 `npm audit --json`
- total`11`
- high`3`
- moderate`2`
- low`6`
- critical`0`
最终治理后 `npm audit`
- `found 0 vulnerabilities`
## 已应用的安全修复与替换
- `npm audit fix` 自动更新传递依赖:
- `@xmldom/xmldom``0.8.11 -> 0.8.13`
- `brace-expansion``1.1.12 -> 1.1.14`
- `lodash``4.17.23 -> 4.18.1`
- 根级 `postcss``8.5.8 -> 8.5.12`
- 手动把 Next patch 版本升级到安全版本:
- `next``16.2.1 -> 16.2.4`
- `eslint-config-next``16.2.1 -> 16.2.4`
- 使用 npm `overrides` 将 Next 内部 `postcss` 收敛到安全版本:
- `postcss``8.5.12`
- 移除旧 OSS SDK 与代理链:
- 移除 `ali-oss`
- 移除 `@types/ali-oss`
- 移除 `proxy-agent`
- 将阿里云 OSS 附件存储改为项目内原生 REST 客户端:
- 使用 Node `fetch` 发起 `PUT / GET / bucketInfo`
- 使用 `crypto.createHmac("sha1")` 生成 OSS V1 Authorization 与签名下载 URL。
- 保持现有外部调用接口:上传附件、签名下载、读取对象、配置校验。
- 将验证码邮件投递的 sendmail 启动器固定为 `/usr/bin/env` 字面量,避免 Turbopack 把动态 sendmail 路径追踪成大范围文件模式。
## 不采用的方案
- 未采用 `npm audit fix --force`
- npm 给出的部分修复路径包含 Next 降级,破坏当前 `Next.js 16 + React 19` 运行线。
- 未采用 `proxy-agent@8.0.1` override
-`urllib@2` 通过 CommonJS lazy require 使用 `proxy-agent@5`,强制替换为 ESM 版本存在运行时破坏风险。
- 未采用 `ali-oss@6.19.0-audit.1`
- 实测会把漏洞转移到 `urllib@3 -> undici@5` 链,`npm audit` 仍剩 `3` 条漏洞。
- 未等待 Next 官方 patch
- 当前可以用 `overrides.postcss=8.5.12` 通过 lint/build 回归,风险可控。
## 已执行命令
```bash
npm audit --json
npm audit fix
npm install next@16.2.4 eslint-config-next@16.2.4 --save-exact
npm install
npm audit
npm ls ali-oss proxy-agent urllib undici postcss next --all
npx tsx --test tests/boss-mail.test.ts tests/aliyun-oss-storage.test.ts
npm run lint
npm run build
```
最终验证结果:
- `npm audit`:通过,`found 0 vulnerabilities`
- `npm ls ali-oss proxy-agent urllib undici postcss next --all`:通过,漏洞依赖链已不存在;`next` 使用 `postcss@8.5.12`
- `npx tsx --test tests/boss-mail.test.ts tests/aliyun-oss-storage.test.ts``5/5` 通过。
- `npm run lint`:通过。
- `npm run build`:通过;未再出现 `boss-mail.ts` Turbopack broad file pattern warning。

View File

@@ -0,0 +1,197 @@
# RBAC / Skill / 主 Agent 权限与回归矩阵
更新时间:`2026-04-27`
这份文档只梳理当前已经落地或明确未生产化的多用户、RBAC、Skill、主 Agent 权限和多设备控制链路。当前运行真相仍以 `current_runtime_and_deploy_status_cn.md``api_and_service_inventory_cn.md` 为准。
## 1. 当前开发状态
### 1.1 已落地
- 多用户 / RBAC 第一阶段已经落地到文件状态:`accountDeviceGrants / accountProjectGrants / accountSkillGrants / skillCatalog / permissionAuditLogs` 已进入 `BossState`
- 最高管理员授权台已经可用:`GET/POST /api/v1/admin/access``highest_admin` 可访问,支持创建 / 更新子账号、授予设备 / 项目 / Skill 权限、套用模板和撤销授权。
- Web `/me/access` 与 Android `AccessManagementActivity` 已接入授权管理;`member` 不显示入口,直接请求也应返回 `403`
- 会话、设备、项目详情、消息读写、设备 Skill、`/api/state` 已按当前登录账号裁剪;最高管理员保持全局可见。
- 主 Agent prompt 与任务队列已接入授权快照:生成提示词时只带当前账号可见设备、项目、线程状态文档、进展事件和 Skill`MasterAgentTask` 会记录 `authorizedDeviceIds / authorizedProjectIds / authorizedSkillIds / requiredPermissions`
- 本地 `local-agent` 已能扫描 `~/.codex/skills` 并同步到云端设备 Skill 接口Web / Android Skill 页按授权后的设备和 Skill 展示。
- 普通线程单聊、群聊下发、设备导入审核、browser/desktop 控制都已经进入 `master-agent task queue -> local-agent -> complete` 主链。
- browser/desktop 控制已从占位结果升级为外部 runtime 桥:未配置时 fail closed配置 smoke runtime 时可回写结构化 `control_summary`
### 1.2 部分落地但仍属 MVP
- 登录会话已有 `boss_session`、原生 `restore token` 和单会话撤销但还没有独立刷新令牌、完整吊销审计、CSRF 防护和更细风控策略。
- `permissionAuditLogs` 已有第一版最高管理员查询入口和 deterministic 风险摘要;仍不是后台持久告警、归档和独立审计存储系统。
- Skill 当前已支持“扫描、展示、授权、复制调用语句、进入主 Agent 授权上下文”,并新增最高管理员发起的远程安装 / 更新 / 卸载 / 回滚 / 版本锁请求local-agent 会认领并执行本机 Skill 文件或 Git 操作,但还不是带签名校验、依赖沙箱和执行审计的完整 Skill 平台。
- 主 Agent 可以携带授权快照并派任务,但审批流仍是局部场景:群聊 `approval_required` 已有确认 / 拒绝;高风险 Skill、远程安装、跨设备接管还没有统一审批引擎。
- 多设备控制当前以设备在线状态、设备绑定、项目线程绑定和 runtime 配置为准,尚未形成租约、抢占、并发冲突仲裁的完整生产级控制面。
## 2. 权限模型
### 2.1 角色
| 角色 | 当前含义 | 当前边界 |
| --- | --- | --- |
| `highest_admin` | 最高管理员,默认账号 `krisolo` | 全局可见可管理账号、授权、AI 账号、Telegram、运维入口和所有活跃会话 |
| `admin` | 管理员 / 可信协作者 | 可见更多“我的”入口,但当前不是全局授权管理员;不能访问 `/api/v1/admin/access` |
| `member` | 子账号 / 普通成员 | 只看被授权设备、项目和 Skill`我的` 入口限制为个人安全、设置、技能、关于 |
### 2.2 权限点
| 权限 | 作用对象 | 当前作用 |
| --- | --- | --- |
| `device.view` | 设备 | 查看设备;可带来该设备关联项目的只读可见性 |
| `device.manage` | 设备 | 预留给设备管理动作,当前不是主要前台能力 |
| `project.view` | 项目 / 线程 / 群聊 | 查看项目详情、会话列表、线程状态和项目投影 |
| `thread.chat` | 项目 / 线程 / 群聊 | 向普通项目或线程发送消息并创建 `conversation_reply` |
| `master_agent.ask` | 项目 / 主 Agent | 向主 Agent 提问或让主 Agent 生成推荐 / 任务 |
| `master_agent.takeover` | 项目 / 线程 | 允许主 Agent 接管或代表用户推动线程执行 |
| `computer.control` | 设备 / 项目 | 允许 browser/desktop 控制类任务进入执行链 |
| `skill.view` | Skill | 查看已授权 Skill |
| `skill.use` | Skill | 把 Skill 作为可用能力放入授权上下文或调用语句 |
| `skill.manage` | Skill | 预留给细粒度 Skill 管理;当前远程安装 / 更新仍由 `highest_admin` 入口硬限制 |
| `account.manage` | 账号 | 预留;当前账号授权管理仍以 `highest_admin` 角色硬限制为准 |
| `audit.view` | 审计 | 预留;当前权限审计查询入口仍以 `highest_admin` 硬限制为准 |
### 2.3 继承与显式授权
- `highest_admin` 绕过设备、项目和 Skill 授权检查。
- 非最高管理员如果拥有某台设备或被授予 `device.view`,可以只读看到该设备关联的项目。
- `device.view` 不会自动放大为 `thread.chat / master_agent.ask / master_agent.takeover / computer.control / skill.use`
- 聊天、主 Agent 接管、电脑控制和 Skill 使用必须来自项目授权、设备授权或 Skill 授权中的显式权限。
- Skill 授权可带 `deviceId / projectId` scope同名 Skill 会聚合进 `skillCatalog`,但实际可见 / 可用仍要按设备和项目 scope 判断。
- 过期授权通过 `expiresAt` 失效;当前应在回归中覆盖过期授权不再生效。
### 2.4 内置模板
| 模板 | 设备权限 | 项目权限 | Skill 权限 | 适用场景 |
| --- | --- | --- | --- | --- |
| 只读观察员 | `device.view` | `project.view` | `skill.view` | 只看设备、项目和 Skill不允许聊天或执行 |
| 项目开发者 | `device.view` | `project.view / thread.chat / master_agent.ask` | `skill.view / skill.use` | 参与项目开发,可问主 Agent 和调用已分配 Skill |
| 设备操作者 | `device.view / computer.control` | `project.view / thread.chat / master_agent.ask / master_agent.takeover / computer.control` | `skill.view / skill.use` | 可信协作者,可触发接管和电脑控制 |
## 3. 控制链路权限边界
### 3.1 主 Agent 单聊
- 入口:`POST /api/v1/projects/master-agent/messages`
- 权限:当前需要 `master_agent.ask`;最高管理员全局通过。
- 执行链:写入消息后创建 `MasterAgentTask`,优先走 `Master Codex Node`,设备离线或立即失败时可退到已配置 API / 阿里备用链。
- 授权快照:任务保存 `authorizedDeviceIds / authorizedProjectIds / authorizedSkillIds / requiredPermissions`,用于执行器和后续审计判断。
### 3.2 普通线程单聊
- 入口:`POST /api/v1/projects/[projectId]/messages`
- 权限:普通项目需要 `thread.chat`;只读 `project.view` 不能发送消息。
- 执行链:创建 `conversation_reply`,由绑定设备 `local-agent``codex exec resume <targetCodexThreadRef>` 回到真实 Codex 线程。
- 重要边界如果线程缺失、设备离线、cwd 不匹配或历史只读线程上下文未解除,应失败并给出明确原因,不应假成功。
### 3.3 群聊下发
- 入口:群聊消息进入主 Agent 推荐;用户确认后调用 dispatch plan confirm。
- 权限:需要项目聊天 / 主 Agent 推荐能力;最终下发目标必须是真实可执行线程成员。
- 当前审批:`approval_required` 群聊支持确认 / 拒绝,一次只保留一个待确认推荐,避免叠加。
- 回写:`dispatch_execution` 完成后线程原始结果回群,再追加主 Agent 汇总;重复完成应幂等。
### 3.4 Skill
- 采集:`local-agent` 扫描本机 `~/.codex/skills`,上报 `/api/v1/devices/[deviceId]/skills`
- 展示:`GET /api/v1/devices/[deviceId]/skills` 和 Web / Android Skill 页按账号授权过滤。
- 使用:`skill.use` 决定 Skill 是否能进入当前账号的主 Agent 授权上下文或被用户复制调用。
- 已落地第一版远程安装、远程更新、远程卸载、Git checkout 回滚和版本锁请求会被 local-agent 认领执行并同步最新清单。
- 未生产化:远程 Skill 执行、签名校验、沙箱隔离、撤销后本地禁用、来源信任和依赖安装策略尚未完成。
### 3.5 多设备与电脑控制
- 设备能力来自 heartbeatCodex GUI / CLI、browserAutomation、computerUse 等。
- browser/desktop 控制任务要求 `computer.control`,并通过 `MasterAgentTask` 进入 `local-agent` 外部 runtime 桥。
- smoke runtime 当前能做最小真实动作和 artifact 回写,但还不是完整 Playwright / Computer Use 生产运行时。
- 同项目 GUI / CLI 并行写入已有冲突控制:默认阻断,用户可对异常项目选择本次 / 永久放行。
## 4. 回归矩阵
### 4.1 Web / API
| 场景 | 要测什么 | 命令 |
| --- | --- | --- |
| 基础构建 | Next.js 构建和 lint 无退化 | `npm run build && npm run lint` |
| 健康检查 | Web 服务可启动、健康探针正常 | `npm start` 后执行 `curl -sS http://127.0.0.1:3000/api/health` |
| 登录态 | 登录、session、restore、logout 链路 | `curl -sS -H 'Content-Type: application/json' -d '{"account":"krisolo","password":"<admin-password>","method":"password"}' http://127.0.0.1:3000/api/auth/login` |
| 会话治理 | 最高管理员可看全部会话,子账号只能看自己,会话 token 不泄露 | `curl -sS http://127.0.0.1:3000/api/v1/auth/sessions` |
| 授权台保护 | 未登录返回 `401`,非最高管理员返回 `403`,最高管理员可读脱敏数据 | `curl -i http://127.0.0.1:3000/api/v1/admin/access` |
| 授权动作 | `upsert_account / grant_device / grant_project / grant_skill / apply_template / revoke_grant` 都写入 `permissionAuditLogs` | 用最高管理员 Cookie 对 `/api/v1/admin/access` 发 JSON POST |
| 权限审计查询 | 最高管理员可按 action / actor / target / device / project / skill / cursor / limit 查询,普通账号 `403` | `npx tsx --test tests/audit-permission-logs-route.test.ts` |
| 权限审计风险 | 能识别短时间大量授权、Skill lifecycle 失败、过期授权仍存在、admin route 拒绝访问 | `npx tsx --test tests/audit-permission-logs-route.test.ts` |
| 账号裁剪 | 子账号只看到被授权设备 / 项目 / Skill | 用子账号 Cookie 分别请求 `/api/v1/devices``/api/v1/conversations``/api/v1/devices/mac-studio/skills` |
| 项目写权限 | 只有 `thread.chat` 可发普通线程消息,只读账号应 `403` | `curl -i -H 'Content-Type: application/json' -d '{"kind":"text","body":"权限回归"}' http://127.0.0.1:3000/api/v1/projects/<projectId>/messages` |
| 主 Agent 权限 | `master_agent.ask` 才能进入主 Agent 任务链,任务包含授权快照 | `curl -sS -H 'Content-Type: application/json' -d '{"kind":"text","body":"列出我可见的设备和 Skill"}' http://127.0.0.1:3000/api/v1/projects/master-agent/messages` |
| Skill 过滤 | Skill 列表按设备和账号授权过滤 | `curl -sS http://127.0.0.1:3000/api/v1/devices/mac-studio/skills` |
| Skill 治理请求 | 最高管理员可创建请求,设备可认领和回写 | `npx tsx --test tests/skill-lifecycle-route.test.ts` |
| browser/desktop fail closed | 未配置 runtime 时返回明确 disabled不写假成功 | 关闭 `browserControl* / computerUse*` 后发控制类主 Agent 消息 |
| 群聊审批 | `approval_required` 只能有一条待确认推荐,确认 / 拒绝状态正确 | 用群聊项目消息接口触发 dispatch plan再测 confirm / reject |
### 4.2 local-agent / 本机设备
| 场景 | 要测什么 | 命令 |
| --- | --- | --- |
| 健康探针 | `launchd` 常驻不被首次 heartbeat 阻塞 | `curl -sS http://127.0.0.1:4317/health` |
| Skill 扫描 | 本机 Skill 能递归扫描并返回 | `curl -sS http://127.0.0.1:4317/api/v1/skills` |
| Skill lifecycle | local-agent 能认领请求、执行版本锁/卸载等安全本机操作并同步清单 | `node --test tests/local-agent-skill-lifecycle-runner.test.mjs` |
| 心跳上报 | 设备、能力、Skill、thread-context 能上报 | `curl -sS -X POST http://127.0.0.1:4317/api/v1/heartbeat` |
| 任务认领 | `conversation_reply / dispatch_execution / browser_control / desktop_control` 能被认领或明确失败 | 触发对应 Web/API 消息后观察项目消息账本和 local-agent 日志 |
| Codex 线程恢复 | 有 `targetCodexThreadRef` 时走 `codex exec resume`,缺失时才退 `--ephemeral` | 发送普通线程消息并检查回写内容 |
| rollout 镜像 | Boss 用户消息先镜像进 Codex Desktop 同线程,重试不重复写入 | 对已绑定真实线程的项目发送消息后检查 Desktop 线程历史 |
### 4.3 Android
| 场景 | 要测什么 | 命令 |
| --- | --- | --- |
| 构建 | Debug APK 可构建并发布到 downloads | `npm run apk:debug` |
| Release | signed release APK 可构建 | `npm run apk:release` |
| 单元测试 | Android 本地测试串行通过,避免 Gradle 中间产物互踩 | `cd android && ./gradlew testDebugUnitTest` |
| 真机安装 | OPPO `PHZ110` 安装并可启动 | `adb -s U84XJRIB7D65ZH45 install -r android/app/build/outputs/apk/debug/app-debug.apk` |
| 角色入口 | `member / admin / highest_admin` 的“我的”入口差异正确 | 真机登录不同账号,检查 `用户与权限 / 技能 / 运维 / AI 账号 / Telegram` 可见性 |
| 权限管理页 | 最高管理员可创建子账号、套模板、撤销授权 | 真机打开 `我的 > 用户与权限` |
| Skill 页 | 子账号只看到授权 Skill可复制调用语句 | 真机打开 `我的 > 技能` |
| 聊天等待态 | 主 Agent、普通线程、群聊下发都显示等待直到真实回写或超时 | 真机分别发送三类消息 |
| 控制结果卡 | browser/desktop 控制结果以目标 URL / 应用名卡片展示 | 真机向主 Agent 发送控制类请求 |
### 4.4 真机 / 多设备控制
| 场景 | 要测什么 | 命令 |
| --- | --- | --- |
| ADB 目标 | 默认只使用 OPPO `PHZ110`,不自动回退旧设备 | `adb devices` |
| 无线调试 | 同一局域网 + USB 初次启用后可切无线 | `adb -s U84XJRIB7D65ZH45 tcpip 5555 && adb connect <phone-ip>:5555` |
| 设备在线 | Boss 设备页显示 `mac-studio` 在线及 browser/computer 能力 | `curl -sS http://127.0.0.1:4317/health && curl -sS -X POST http://127.0.0.1:4317/api/v1/heartbeat` |
| GUI / CLI 冲突 | 同项目双执行模式默认阻断,允许本次 / 永久放行生效 | 在设备详情或项目冲突提示中切换策略后再次派发 |
| 设备离线 | 主 Agent / 项目确认接口返回明确离线原因,不假成功 | 停掉 local-agent 后发送线程或控制任务 |
### 4.5 服务器部署
| 场景 | 要测什么 | 命令 |
| --- | --- | --- |
| SSH 健康 | 固定服务器 `106.53.170.158` 可连 | `"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" health` |
| Web 服务 | `boss-web.service` 运行且本机 API 正常 | `"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" exec "systemctl status boss-web --no-pager && curl -sS http://127.0.0.1:3000/api/health"` |
| Caddy / HTTPS | Caddy 运行,域名跳转正常 | `"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" exec "systemctl status caddy --no-pager && curl -I --resolve boss.hyzq.net:443:127.0.0.1 https://boss.hyzq.net"` |
| 外网域名 | 当前网络能访问公网 HTTPS API | `curl -I https://boss.hyzq.net && curl -sS https://boss.hyzq.net/api/health` |
| 状态文件 | 部署不覆盖服务器 `data/boss-state.json` | 部署前后在服务器检查 `/opt/boss/data/boss-state.json` mtime 和关键账号数据 |
| 邮件端口 | Postfix / Dovecot 在线 | `"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" exec "systemctl status postfix --no-pager && systemctl status dovecot --no-pager"` |
## 5. 剩余缺口
### 5.1 需要生产化的权限能力
- Skill 远程安装 / 更新 / 卸载:第一版设备端安装器和版本锁已落地;仍需要签名校验、来源信任、安装审计增强和失败自动回滚。
- Skill 远程执行:需要明确输入输出协议、沙箱边界、资源限制、敏感权限提示和 per-run 审计。
- 统一审批流:高风险 Skill、电脑控制、跨设备接管、生产部署、账号和存储配置变更应进入同一审批模型而不是分散在群聊确认里。
- 多级组织:当前只有角色 + 单账号授权;还没有组织、团队、项目组、继承授权、批量授权、离职回收和委派管理员。
- 审计告警:授权日志已有账本,但缺少审计检索、异常检测、告警通道、不可篡改归档和审计报表。
- 风险分级执行:`requiresConfirmation / riskLevel` 已开始进入任务元数据,但还没有统一策略中心约束哪些风险必须二次确认。
### 5.2 需要生产化的运行能力
- 数据库:当前仍是 `data/boss-state.json` 文件存储RBAC、审计、会话和任务队列生产化前需要迁移到数据库并补索引和事务边界。
- 会话安全需要独立刷新令牌、完整吊销审计、CSRF 防护、设备绑定策略、登录风险检测和异常会话告警。
- 多设备控制租约:需要 device lease、抢占、超时释放、只读观察、独占输入和并发写入审计。
- 真实 Browser / Computer Use runtime当前 smoke runtime 只能作为过渡层;生产需要接入真实浏览器自动化和桌面控制执行器。
- 服务器出网:公网服务器当前对 `api.openai.com` 直接出网仍未完全打通OpenAI API 线上探针和调用依赖网络恢复。
- 生产邮件验收Postfix / Dovecot 已部署,但 SPF、DKIM、DMARC、MX、退信策略和真实外部收件链路仍需最终验收。

View File

@@ -0,0 +1,75 @@
# Telegram Gateway Integration Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 为 Boss 增加可用的 Telegram 对话入口,让 Telegram 用户能安全地与主 Agent 对话,并在主 Agent 异步完成任务后把结果回推回 Telegram。
**Architecture:**`src/lib` 新增一个轻量 Telegram gateway负责 update 归一化、访问控制、消息分流和 Telegram Bot API 调用Next.js 暴露 webhook 与管理员配置接口,仍然复用现有 `boss-master-agent``boss-data` 主链,不复制对话业务。异步回复依赖现有 `/api/v1/master-agent/tasks/[taskId]/complete` 完成回调,在任务落盘后立即尝试发回 Telegram。
**Tech Stack:** Next.js App Router、TypeScript、文件型状态 `data/boss-state.json`、原生 `fetch`、Node test runner + `tsx --test`
---
### Task 1: 定义 Telegram 状态与配置模型
**Files:**
- Create: `src/lib/telegram-gateway.ts`
- Modify: `src/lib/boss-data.ts`
- Test: `tests/telegram-gateway.test.ts`
- [ ] **Step 1: 写 Telegram 配置/状态的失败测试**
- [ ] **Step 2: 运行测试确认因接口缺失而失败**
- [ ] **Step 3: 在 `boss-data.ts` 增加 Telegram 配置与任务外部回推字段**
- [ ] **Step 4: 在 `telegram-gateway.ts` 增加归一化、mask、session key、chunk 等纯函数**
- [ ] **Step 5: 重新运行测试确认通过**
### Task 2: 打通 webhook 与主 Agent 桥接
**Files:**
- Create: `src/app/api/v1/integrations/telegram/webhook/route.ts`
- Modify: `src/lib/telegram-gateway.ts`
- Modify: `src/lib/boss-master-agent.ts`
- Test: `tests/telegram-gateway.test.ts`
- [ ] **Step 1: 写 webhook 接收、secret 校验、allowlist、主 Agent 快速回复 的失败测试**
- [ ] **Step 2: 跑测试确认 RED**
- [ ] **Step 3: 实现 webhook handler把 Telegram 文本桥接到 `master-agent`**
- [ ] **Step 4: 对快速回复直接回 Telegram对排队任务保存外部回推目标**
- [ ] **Step 5: 跑测试确认 GREEN**
### Task 3: 打通任务完成后的 Telegram 异步回推
**Files:**
- Modify: `src/lib/boss-data.ts`
- Modify: `src/app/api/v1/master-agent/tasks/[taskId]/complete/route.ts`
- Modify: `src/lib/telegram-gateway.ts`
- Test: `tests/telegram-gateway.test.ts`
- [ ] **Step 1: 写任务完成后自动回推 Telegram 的失败测试**
- [ ] **Step 2: 跑测试确认 RED**
- [ ] **Step 3: 在任务模型中加入 `externalReplyTarget` 并在 complete route 中触发 Telegram 发信**
- [ ] **Step 4: 补充发送成功/失败去重保护**
- [ ] **Step 5: 跑测试确认 GREEN**
### Task 4: 增加管理员配置接口
**Files:**
- Create: `src/app/api/v1/integrations/telegram/route.ts`
- Modify: `src/lib/telegram-gateway.ts`
- Test: `tests/telegram-integration-route.test.ts`
- [ ] **Step 1: 写 GET/POST 配置接口失败测试**
- [ ] **Step 2: 跑测试确认 RED**
- [ ] **Step 3: 实现管理员鉴权、配置读取、保存、token 掩码与 getMe 探测**
- [ ] **Step 4: 跑测试确认 GREEN**
### Task 5: 文档与回归验证
**Files:**
- Modify: `README.md`
- Modify: `docs/architecture/api_and_service_inventory_cn.md`
- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md`
- [ ] **Step 1: 更新 Boss 当前能力文档,写清 Telegram 接入方式、能力边界与部署方式**
- [ ] **Step 2: 运行 `tsx --test`、`npm run lint`、`npm run build`**
- [ ] **Step 3: 记录未完成项与后续扩展点群聊策略、pairing、Feishu/Telegram 复用层)**

View File

@@ -0,0 +1,274 @@
# Codex Desktop Thread Sync Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让 Boss App 发往单线程 Codex 会话的用户消息,在继续现有 `conversation_reply -> codex exec resume` 主链前,同步镜像进本机 Codex Desktop 的同一个线程历史。
**Architecture:** 服务端继续以 Boss 项目账本为主真相,但给普通单线程 `conversation_reply` 任务补齐 `sourceMessage*` 元数据和显式镜像开关。`local-agent` 在执行 `codex exec resume` 前,按 `targetCodexThreadRef` 解析目标 rollout 文件,先做一次本地 user_message append + 去重再继续原有执行链。rollout 定位优先使用 `state_5.sqlite`,若本机 Codex CLI/Desktop 版本导致状态库不可用,则回退扫描 `~/.codex/sessions`rollout 写入后尽量刷新 `threads.updated_at / updated_at_ms / has_user_event`,但不依赖 GUI 自动化。
**Tech Stack:** Next.js App Router, TypeScript, Node.js, sqlite, local-agent Node runtime, `tsx --test`, Node test runner
---
### Task 1: 给 conversation task 补齐 Desktop 镜像元数据
**Files:**
- Modify: `src/lib/boss-data.ts`
- Modify: `src/lib/boss-master-agent.ts`
- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts`
- Test: `tests/single-thread-message-execution.test.ts`
- [x] **Step 1: 写失败测试,要求普通单线程消息返回的任务带 sourceMessage 元数据**
```ts
assert.equal(task?.sourceMessageId, message.id);
assert.equal(task?.sourceMessageBody, "请同步一下当前阻塞情况");
assert.equal(task?.sourceMessageSentAt, message.sentAt);
assert.equal(task?.mirrorBossUserMessageToCodexDesktop, true);
```
- [x] **Step 2: 运行测试确认失败**
Run: `npx tsx --test tests/single-thread-message-execution.test.ts`
Expected: FAIL提示 `sourceMessageBody/sourceMessageSentAt/mirrorBossUserMessageToCodexDesktop` 不存在或断言失败。
- [x] **Step 3: 写最小实现**
`MasterAgentTask` 和状态序列化/反序列化里补字段:
```ts
sourceMessageId?: string;
sourceMessageBody?: string;
sourceMessageSentAt?: string;
mirrorBossUserMessageToCodexDesktop?: boolean;
```
`queueThreadConversationReplyTask` 中透传:
```ts
sourceMessageId: params.sourceMessageId,
sourceMessageBody: params.sourceMessageBody,
sourceMessageSentAt: params.sourceMessageSentAt,
mirrorBossUserMessageToCodexDesktop:
params.relayViaMasterAgent ? undefined : true,
```
在消息 route 调用时补:
```ts
const queuedTask = await queueThreadConversationReplyTask({
projectId,
requestMessageId: message.id,
requestText: message.body,
requestedBy: session.displayName || session.account,
requestedByAccount: session.account,
sourceMessageId: message.id,
sourceMessageBody: message.body,
sourceMessageSentAt: message.sentAt,
});
```
- [x] **Step 4: 运行测试确认通过**
Run: `npx tsx --test tests/single-thread-message-execution.test.ts`
Expected: PASS
### Task 2: 新增 rollout writer并确保重复任务不重复写 Desktop 线程
**Files:**
- Create: `local-agent/codex-thread-rollout-writer.mjs`
- Test: `tests/local-agent-codex-rollout-writer.test.mjs`
- [x] **Step 1: 写失败测试,约束 writer 会写入 user_message 且按 sourceMessageId 去重**
```js
test("appendBossUserMessageToCodexThreadRollout writes one user_message event and dedupes by source message id", async () => {
const first = await appendBossUserMessageToCodexThreadRollout({ ... });
const second = await appendBossUserMessageToCodexThreadRollout({ ... });
assert.equal(first.status, "written");
assert.equal(second.status, "duplicate");
});
```
- [x] **Step 2: 运行测试确认失败**
Run: `node --test tests/local-agent-codex-rollout-writer.test.mjs`
Expected: FAIL提示模块不存在或导出函数不存在。
- [x] **Step 3: 写最小实现**
实现 writer 逻辑:
```js
export async function appendBossUserMessageToCodexThreadRollout(params) {
const rolloutPath = await resolveThreadRolloutPath(params);
const duplicate = await hasBossSourceMessageInRolloutTail(rolloutPath, params.sourceMessageId);
if (duplicate) return { status: "duplicate", rolloutPath };
const responseItem = JSON.stringify({
timestamp: params.sentAt,
type: "response_item",
payload: {
type: "message",
role: "user",
content: [{ type: "input_text", text: params.message }],
},
});
const event = JSON.stringify({
timestamp: params.sentAt,
type: "event_msg",
payload: {
type: "user_message",
message: params.message,
images: [],
local_images: [],
text_elements: [],
metadata: {
bossSourceMessageId: params.sourceMessageId,
bossMirroredFrom: "boss-app",
},
},
});
await appendFile(rolloutPath, `${responseItem}\n${event}\n`, "utf8");
return { status: "written", rolloutPath };
}
```
- [x] **Step 4: 运行测试确认通过**
Run: `node --test tests/local-agent-codex-rollout-writer.test.mjs`
Expected: PASS
### Task 3: 在 local-agent 执行 resume 前追加 Desktop 线程镜像
**Files:**
- Modify: `local-agent/codex-task-runner.mjs`
- Modify: `tests/local-agent-codex-task-runner.test.mjs`
- [x] **Step 1: 写失败测试,要求 prepare 阶段保留镜像计划,且 relay task 不启用**
```js
assert.deepEqual(result.execution.desktopMirror, {
enabled: true,
sourceMessageId: "msg-1",
sourceMessageBody: "请继续推进",
});
```
- [x] **Step 2: 运行测试确认失败**
Run: `node --test tests/local-agent-codex-task-runner.test.mjs`
Expected: FAIL提示 `desktopMirror` 不存在。
- [x] **Step 3: 写最小实现**
`buildCodexTaskExecution` 返回值中增加:
```js
desktopMirror: shouldMirrorBossUserMessageToDesktop(task)
? {
enabled: true,
sourceMessageId: task.sourceMessageId,
sourceMessageBody: task.sourceMessageBody,
sourceMessageSentAt: task.sourceMessageSentAt,
targetThreadRef,
}
: { enabled: false }
```
其中 `shouldMirrorBossUserMessageToDesktop(task)` 需要保证:
- `task.taskType === "conversation_reply"`
- `task.mirrorBossUserMessageToCodexDesktop === true`
- `task.relayViaMasterAgent !== true`
- `targetThreadRef/sourceMessageId/sourceMessageBody` 全部存在
- [x] **Step 4: 运行测试确认通过**
Run: `node --test tests/local-agent-codex-task-runner.test.mjs`
Expected: PASS
### Task 4: 在实际任务执行前调用 rollout writer并保持现有 resume/complete 主链不回归
**Files:**
- Modify: `local-agent/server.mjs`
- Modify: `tests/local-agent-codex-task-runner.test.mjs`
- Modify: `tests/single-thread-message-execution.test.ts`
- [x] **Step 1: 写失败测试,要求 server 在 spawn codex 前先执行 rollout 镜像**
```js
assert.equal(writerCalls.length, 1);
assert.equal(writerCalls[0].sourceMessageId, "msg-1");
assert.equal(writerCalls[0].message, "请继续推进");
```
- [x] **Step 2: 运行测试确认失败**
Run: `node --test tests/local-agent-codex-task-runner.test.mjs`
Expected: FAIL提示 writer 未被调用。
- [x] **Step 3: 写最小实现**
`runMasterAgentTask``spawn("codex", ...)` 前增加:
```js
if (codexExecution.desktopMirror?.enabled) {
await appendBossUserMessageToCodexThreadRollout({
stateDbPath: config.codexStateDbPath,
targetThreadRef: codexExecution.desktopMirror.targetThreadRef,
sourceMessageId: codexExecution.desktopMirror.sourceMessageId,
message: codexExecution.desktopMirror.sourceMessageBody,
sentAt: codexExecution.desktopMirror.sourceMessageSentAt ?? new Date().toISOString(),
});
}
```
如果镜像失败:
- 不吞掉错误
- 直接按任务失败返回,让链路保持 fail-closed
- [x] **Step 4: 运行定向测试确认通过**
Run:
```bash
node --test tests/local-agent-codex-rollout-writer.test.mjs
node --test tests/local-agent-codex-task-runner.test.mjs
npx tsx --test tests/single-thread-message-execution.test.ts
```
Expected: PASS
### Task 5: 回归验证与文档同步
**Files:**
- Modify: `README.md`(如需补一句运行时说明)
- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md`
- Modify: `docs/architecture/api_and_service_inventory_cn.md`
- [x] **Step 1: 跑仓库要求的基线验证**
Run:
```bash
npm run lint
npm run build
```
Expected: PASS
- [x] **Step 2: 补文档**
在运行时/服务清单文档补一句:
- Boss 普通线程单聊现在会在 local-agent 执行 `codex exec resume` 前,把 Boss 用户消息镜像进目标 Codex Desktop 线程 rollout
- 该能力仅针对已绑定 `codexThreadRef` 的单线程会话
- [x] **Step 3: 完成最终自检**
检查:
- 没有把主 Agent 会话或 takeover relay 错写进 Desktop 子线程
- 没有重复写 rollout
- 现有 heartbeat 读取 recent desktop replies 仍可工作

View File

@@ -0,0 +1,176 @@
# Boss 统一电脑控制中枢 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让 Boss 聊天成为统一电脑控制入口。用户在主 Agent 或线程聊天里提出需求后,系统能在“普通讨论 / Codex 开发 / 浏览器自动化 / 桌面控制”之间自动选路,并通过本机 `local-agent` 执行。
**Architecture:** 继续复用 Boss 现有消息账本、`MasterAgentTask` 队列、执行底座和 `local-agent`。本次新增 `browser_control / desktop_control` 两类正式任务与 runtime并让主 Agent 先做执行意图判断,再把请求路由到 Codex 线程、browser automation、computer use 或直接回复。
**Tech Stack:** Next.js App Router, TypeScript, Node.js local-agent, existing execution abstraction, `tsx --test`, Node test runner
---
### Task 1: 扩展执行类型与任务模型
**Files:**
- Modify: `src/lib/execution/types.ts`
- Modify: `src/lib/execution/tool-registry.ts`
- Modify: `src/lib/boss-data.ts`
- Test: `tests/computer-control-task-model.test.ts`
- [ ] **Step 1: 先写失败测试,要求任务模型支持 browser_control / desktop_control**
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
npx tsx --test tests/computer-control-task-model.test.ts
```
- [ ] **Step 3: 实现最小模型扩展**
补齐:
- `ExecutionRequestKind`
- `ExecutionToolName`
- `MasterAgentTaskType`
- `MasterAgentTask``intentCategory / runtimeKind / riskLevel / confirmationPolicy` 等字段
- [ ] **Step 4: 再跑测试确认通过**
### Task 2: 给主 Agent 增加控制意图分类
**Files:**
- Modify: `src/lib/boss-master-agent.ts`
- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts`
- Test: `tests/master-agent-control-intent-routing.test.ts`
- [ ] **Step 1: 先写失败测试,覆盖讨论 / 开发 / 浏览器 / 桌面四类消息**
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
npx tsx --test tests/master-agent-control-intent-routing.test.ts
```
- [ ] **Step 3: 实现最小路由逻辑**
要求:
- 讨论类继续直接回复
- 开发类仍优先走现有 `conversation_reply`
- 浏览器类排 `browser_control`
- 桌面类排 `desktop_control`
- [ ] **Step 4: 再跑测试确认通过**
### Task 3: 给 local-agent 增加 browser/computer use runtime 分流骨架
**Files:**
- Create: `local-agent/browser-control-task-runner.mjs`
- Create: `local-agent/computer-use-task-runner.mjs`
- Modify: `local-agent/server.mjs`
- Test: `tests/local-agent-browser-control-runner.test.mjs`
- Test: `tests/local-agent-computer-use-runner.test.mjs`
- [ ] **Step 1: 先写失败测试,要求 local-agent 能识别新任务类型并分流**
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
node --test tests/local-agent-browser-control-runner.test.mjs
node --test tests/local-agent-computer-use-runner.test.mjs
```
- [ ] **Step 3: 实现最小分流骨架**
第一版先做:
- browser_control: 返回标准化占位结果或接入现有 browser runtime
- desktop_control: 返回标准化占位结果或接入 computer-use runtime
要求:
- 不能影响现有 `conversation_reply / dispatch_execution`
- [ ] **Step 4: 再跑测试确认通过**
### Task 4: 增加风险分级与确认策略骨架
**Files:**
- Modify: `src/lib/execution/permission-policy.ts`
- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts`
- Test: `tests/computer-control-permission-policy.test.ts`
- [ ] **Step 1: 写失败测试,验证 low/medium/high 三档行为**
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
npx tsx --test tests/computer-control-permission-policy.test.ts
```
- [ ] **Step 3: 实现最小确认策略**
要求:
- `low` 默认可执行
- `medium` 标记需轻确认
- `high` 标记需强确认
- [ ] **Step 4: 再跑测试确认通过**
### Task 5: 前台返回执行模式元数据并做回归
**Files:**
- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts`
- Modify: `src/lib/boss-data.ts`
- Test: `tests/project-message-execution-mode.test.ts`
- [ ] **Step 1: 写失败测试,要求消息返回 executionMode/riskLevel**
- [ ] **Step 2: 运行测试确认失败**
- [ ] **Step 3: 实现最小返回结构**
- [ ] **Step 4: 再跑测试确认通过**
### Task 6: 基线验证与文档同步
**Files:**
- Modify: `README.md`
- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md`
- Modify: `docs/architecture/api_and_service_inventory_cn.md`
- [ ] **Step 1: 同步运行时文档**
- [ ] **Step 2: 跑仓库基线验证**
Run:
```bash
npm run lint
npm run build
```
- [ ] **Step 3: 跑新增与相关回归测试**
Run:
```bash
npx tsx --test tests/computer-control-task-model.test.ts
npx tsx --test tests/master-agent-control-intent-routing.test.ts
npx tsx --test tests/computer-control-permission-policy.test.ts
npx tsx --test tests/project-message-execution-mode.test.ts
node --test tests/local-agent-browser-control-runner.test.mjs
node --test tests/local-agent-computer-use-runner.test.mjs
```
- [ ] **Step 4: 如涉及 Android 前台行为,再补真机复核**

View File

@@ -0,0 +1,168 @@
# Boss Enterprise Hardening Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 把 Boss 从 MVP 管理后台推进到 To B 可交付的第一批企业化硬化版本。
**Architecture:** 保留当前 `BossState` 文件账本作为兼容层,同时新增可切换的状态存储适配层、企业认证默认值、租户隔离守卫、风险 SLA 扫描和增强审计字段。所有高危行为先用测试锁住,再通过 `/admin``/api/v1/*` 渐进暴露。
**Tech Stack:** Next.js App Router、TypeScript、Node `node:test`、现有文件型状态、可选 PostgreSQL JSONB 单行快照、Ant Design 管理后台。
---
## 执行状态
- 2026-04-27已补齐认证安全默认值、状态存储适配层、租户强隔离、风险 SLA 通知账本、后台高危操作、增强审计字段和文档更新。
- 待最终收口:全量 `tests/*.test.ts``npm run lint``npm run build``npm audit` 和服务器 smoke。
### Task 1: 认证安全默认值
**Files:**
- Modify: `src/app/api/auth/login/route.ts`
- Modify: `src/app/auth/login/page.tsx`
- Modify: `src/components/app-ui.tsx`
- Test: `tests/auth-login-hardening-route.test.ts`
- [x] **Step 1: Write failing tests**
覆盖默认关闭免验证登录、显式 `BOSS_AUTH_AUTO_LOGIN=1` 才允许免验证、账号密码登录仍可用。
- [ ] **Step 2: Implement minimal auth hardening**
`shouldAllowTemporaryAutoLogin()` 改成只接受 `1 / true / yes`;登录页文案从“临时免验证”改成企业登录;固定验证码提示只在 fixed delivery 模式下展示。
- [ ] **Step 3: Verify**
Run: `npx tsx --test tests/auth-login-hardening-route.test.ts tests/auth-session-governance.test.ts`
### Task 2: 状态存储适配层
**Files:**
- Create: `src/lib/boss-state-store.ts`
- Modify: `src/lib/boss-data.ts`
- Create: `scripts/postgres-state-schema.sql`
- Test: `tests/boss-state-store.test.ts`
- [ ] **Step 1: Write failing tests**
覆盖默认 `file` 模式、`BOSS_STATE_STORE=postgres` 但无 `BOSS_DATABASE_URL` 时 fail closed、PostgreSQL SQL schema 包含 `boss_state_snapshots``jsonb`
- [ ] **Step 2: Implement adapter**
新增 `createBossStateStore()`默认文件读写PostgreSQL 模式先通过动态 `pg` 依赖实现单行 JSONB 快照,未安装或未配置时给出明确错误。
- [ ] **Step 3: Wire boss-data**
`readState/writeState/loadPersistedStateRaw` 通过 store 读写,保持 `mutateState` 事务队列不变。
### Task 3: 租户强隔离
**Files:**
- Modify: `src/lib/boss-permissions.ts`
- Modify: `src/lib/boss-admin-overview.ts`
- Test: `tests/rbac-tenant-isolation.test.ts`
- [ ] **Step 1: Write failing tests**
同公司账号能访问授权设备 / 项目;不同公司账号即使误授 grant 也不能访问;未绑定公司历史数据继续按 owner/grant 兼容。
- [ ] **Step 2: Implement tenant guard**
在非 `highest_admin` 路径中加入 `companyId` 比对。设备优先读 `device.companyId`,账号读 `authAccount.companyId`,项目通过绑定设备推导公司集合。
### Task 4: 风险 SLA 和通知账本
**Files:**
- Modify: `src/lib/boss-data.ts`
- Create: `src/lib/boss-risk-notifications.ts`
- Create: `src/app/api/v1/admin/risks/scan/route.ts`
- Modify: `src/components/admin/boss-admin-app.tsx`
- Test: `tests/admin-risk-sla-notifications-route.test.ts`
- [ ] **Step 1: Write failing tests**
设置过期 SLA 后扫描会生成通知;重复扫描不重复生成同一风险通知;通知会进入管理后台总览。
- [x] **Step 2: Implement notification model**
新增 `adminNotifications`,字段包含 `notificationId / kind / severity / companyId / riskId / title / body / status / createdAt / acknowledgedAt`
- [x] **Step 3: Implement scanner**
- [x] **Step 4: Implement dispatch and timeline**
新增 `/api/v1/admin/notifications/dispatch`,支持 sendmail 邮件通道或 disabled 模式状态落账;新增 `adminRiskTimeline` 记录通知生成、派发和人工处置。
扫描 `opsFaults``threadContextAlerts`,对 `slaDueAt < now` 且未关闭的风险生成 `risk_sla_overdue` 通知。
### Task 5: 后台高危操作补齐
**Files:**
- Modify: `src/lib/boss-data.ts`
- Modify: `src/app/api/v1/admin/access/route.ts`
- Modify: `src/components/admin/admin-access-panel.tsx`
- Test: `tests/admin-access-enterprise-ops-route.test.ts`
- [x] **Step 1: Write failing tests**
最高管理员可停用公司、重置子账号密码、批量导入预检;停用公司会禁用该公司普通子账号并撤销会话;最高管理员账号不可被公司停用波及。
- [x] **Step 2: Implement actions**
新增 `set_company_status / reset_account_password / preview_bulk_import_accounts` 三个 action并接到 PC 管理后台。
- [x] **Step 3: Implement enterprise UX polish**
补齐公司套餐、合同到期、客户成功、CSV 导入、危险操作确认和子账号 MFA 开关。
### Task 6: 增强审计字段
**Files:**
- Modify: `src/lib/boss-data.ts`
- Modify: admin action routes under `src/app/api/v1/admin/*`
- Test: `tests/admin-audit-compliance.test.ts`
- [x] **Step 1: Write failing tests**
高危动作写入 `ipAddress / userAgent / beforeJson / afterJson / requestId`API 响应不泄露 `passwordHash / apiKey / sessionToken / restoreToken`
- [x] **Step 2: Implement audit metadata**
扩展 `PermissionAuditLog`,新增 `buildRequestAuditMeta(request)`,所有 admin mutation route 传入审计上下文。
- [x] **Step 3: Implement auth hardening**
补齐浏览器 CSRF 基础防护、restore token 轮换和子账号 MFA 校验。
### Task 7: Docs, regression, deploy
**Files:**
- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md`
- Modify: `docs/architecture/api_and_service_inventory_cn.md`
- Modify: `docs/architecture/admin_refine_backoffice_cn.md`
- [x] **Step 1: Update docs**
记录企业登录默认值、PostgreSQL 切换方式、租户隔离规则、风险 SLA 扫描和后台高危操作。
- [ ] **Step 2: Full verification**
Run:
```bash
npx tsx --test tests/*.test.ts
npm run lint
npm run build
npm audit
```
- [ ] **Step 3: Deploy and smoke**
Run:
```bash
./scripts/deploy-server.sh
curl -fsS https://boss.hyzq.net/api/health
```
Post-deploy verify `/admin``/api/v1/admin/access``/api/v1/admin/overview``/api/v1/admin/risks/scan`

View File

@@ -0,0 +1,158 @@
# Boss Admin Backoffice Redesign Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Rebuild `/admin` into a PC To B operations backoffice with a dashboard, customer workspace, permission workspace, and risk/governance command center.
**Architecture:** Keep the existing Next.js App Router route and existing admin APIs. Refactor the current client shell into focused React components under `src/components/admin/`, reusing `/api/v1/admin/overview`, `/api/v1/admin/access`, `/api/v1/admin/risks/actions`, and `/api/v1/admin/skills/requests`.
**Tech Stack:** Next.js 16 App Router, React 19, Ant Design, `@refinedev/core`, TypeScript source tests with `node:test`.
---
### Task 1: Source Tests For New Admin Structure
**Files:**
- Modify: `tests/admin-refine-page.test.ts`
- [ ] **Step 1: Update the admin structure assertions**
Replace the old page shell expectations with assertions for these strings:
```ts
for (const title of ["平台运营驾驶舱", "客户与账号", "授权工作台", "风险与治理"]) {
assert.match(source, new RegExp(title));
}
for (const title of ["今日待处理", "客户健康排行", "关键风险队列", "节点健康"]) {
assert.match(source, new RegExp(title));
}
assert.doesNotMatch(source, /window\.prompt/);
```
- [ ] **Step 2: Run the focused test**
Run:
```bash
npx tsx --test tests/admin-refine-page.test.ts
```
Expected: fail until the component is refactored.
### Task 2: Admin Shell And Navigation
**Files:**
- Modify: `src/components/admin/boss-admin-app.tsx`
- [ ] **Step 1: Replace top tabs with PC backoffice navigation**
Implement a left-side navigation with four keys: `dashboard`, `customers`, `permissions`, `governance`.
- [ ] **Step 2: Keep Refine data provider mounted**
Keep:
```tsx
<Refine dataProvider={createBossAdminDataProvider(initialOverview ?? undefined)} resources={resources}>
```
Expected: existing data provider tests continue to pass.
### Task 3: Dashboard
**Files:**
- Modify: `src/components/admin/boss-admin-app.tsx`
- [ ] **Step 1: Build metric cards**
Use existing `summary`, `companies`, `devices`, `risks`, `notifications`.
- [ ] **Step 2: Build key queues**
Dashboard must include:
```tsx
"今日待处理"
"客户健康排行"
"关键风险队列"
"节点健康"
"最近事件"
```
Expected: no big full-width table as the first visual object.
### Task 4: Customer And Permission Workspaces
**Files:**
- Modify: `src/components/admin/boss-admin-app.tsx`
- Reuse: `src/components/admin/admin-access-panel.tsx`
- [ ] **Step 1: Add customer overview section**
Show company table, account table, and customer onboarding hints.
- [ ] **Step 2: Mount `AdminAccessPanel` under 授权工作台**
Keep the existing working mutation path, but wrap it in clearer page copy and narrower visual hierarchy.
### Task 5: Risk Command Center
**Files:**
- Modify: `src/components/admin/boss-admin-app.tsx`
- [ ] **Step 1: Replace prompt-based actions**
Remove `window.prompt` for assigning owner and SLA. Use controlled inline inputs and buttons.
- [ ] **Step 2: Keep existing risk actions**
Continue posting:
```ts
{ riskId, action: "assign_owner", ownerAccount }
{ riskId, action: "set_sla", slaDueAt }
{ riskId, action: "ack" }
{ riskId, action: "resolve" }
{ riskId, action: "create_repair_ticket" }
```
### Task 6: Skill Governance
**Files:**
- Modify: `src/components/admin/boss-admin-app.tsx`
- Reuse: `src/components/admin/admin-skill-lifecycle-panel.tsx`
- [ ] **Step 1: Move Skill lifecycle panel under 风险与治理**
Use a nested Ant Design `Tabs` with `风险战情室` and `Skill 生命周期`.
### Task 7: Verification
**Files:**
- Test: `tests/admin-refine-page.test.ts`
- Test: `tests/admin-overview-route.test.ts`
- Test: `tests/admin-risk-actions-route.test.ts`
- Test: `tests/admin-skill-lifecycle-panel-source.test.ts`
- [ ] **Step 1: Run focused admin tests**
```bash
npx tsx --test tests/admin-refine-page.test.ts tests/admin-overview-route.test.ts tests/admin-risk-actions-route.test.ts tests/admin-skill-lifecycle-panel-source.test.ts
```
Expected: all pass.
- [ ] **Step 2: Run lint/build**
```bash
npm run lint
npm run build
```
Expected: both pass.
## Self-review
- Spec coverage: covers dashboard, customer workspace, permission workspace, risk command center, Skill governance, testing.
- Placeholder scan: no TBD/TODO language.
- Type consistency: component names and existing endpoints match current code.

View File

@@ -0,0 +1,24 @@
# YuDao 风格企业后台独立化实施计划
日期2026-04-30
## 执行批次
第一批只做独立后台骨架和 BFF 契约,确保可以继续迭代而不影响现有 `/admin`
## 步骤
1. 新增 `/api/v1/admin/backoffice` 的测试,覆盖 `highest_admin` 鉴权、YuDao 风格菜单、租户/账号/角色/资源/风险/审计数据,以及敏感字段不泄露。
2. 新增 `apps/boss-admin-web` 源码测试,覆盖 Vue/Vite/Ant Design Vue 工程骨架、API 地址、登录态携带、核心页面文案和根工程隔离。
3. 实现 Admin BFF`buildAdminOverview(state)``BOSS_PERMISSION_TEMPLATES`、设备、项目、Skill、审计记录聚合为独立后台契约。
4. 搭建独立 Vue 后台工程提供工作台、租户、账号、角色权限、资源授权、Skill 中心、风险告警和审计日志页面骨架。
5. 修改根工程 `tsconfig.json``eslint.config.mjs`,避免尚未安装 Vue 依赖时影响 Next 主站构建。
6. 更新架构文档,说明独立后台、现有 `/admin` fallback、BFF 契约和后续部署方向。
7. 运行专项测试、lint 和 build如失败修到通过再交付。
## 成功标准
- `/api/v1/admin/backoffice` 可被测试调用并返回稳定结构。
- `apps/boss-admin-web` 具备可独立安装运行的 Vue/Vite 工程文件。
- 根工程 lint/build 不受新独立前端影响。
- 文档能说明为什么不整套引入 YuDao 后端,以及后续如何独立部署。

View File

@@ -0,0 +1,405 @@
# Desktop Dialog Guard Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build a cross-platform dialog guard foundation so Boss desktop control can classify macOS and Windows popups, auto-handle safe prompts, and pause for user confirmation on risky prompts.
**Architecture:** Add a local-agent dialog policy engine with platform-neutral snapshots and signatures, expose `needs_user_action` from the computer-use runner, and wire the smoke runtime through the guard before executing desktop actions. macOS and Windows share policy/consent semantics while platform adapters provide snapshots through the same JSON shape.
**Tech Stack:** Node.js ESM, `node:test`, local-agent runtime scripts, Boss `desktop_control` payloads.
---
### Task 1: Policy Engine
**Files:**
- Create: `local-agent/desktop-dialog-guard.mjs`
- Test: `tests/local-agent-desktop-dialog-guard.test.mjs`
- [ ] **Step 1: Write failing tests**
```js
import test from "node:test";
import assert from "node:assert/strict";
import {
buildDialogInterventionResult,
createDialogSignature,
evaluateDialogSnapshot,
normalizeDialogSnapshot,
} from "../local-agent/desktop-dialog-guard.mjs";
test("dialog guard auto-handles safe welcome prompts on macOS and Windows", () => {
for (const platform of ["darwin", "win32"]) {
const decision = evaluateDialogSnapshot({
platform,
appName: platform === "darwin" ? "Google Chrome" : "Microsoft Edge",
title: "Welcome",
text: "Welcome. Not now",
buttons: ["Get started", "Not now"],
});
assert.equal(decision.disposition, "auto_action");
assert.equal(decision.action, "click_button");
assert.equal(decision.button, "Not now");
assert.equal(decision.risk, "safe");
}
});
test("dialog guard pauses for sensitive permission prompts", () => {
const decision = evaluateDialogSnapshot({
platform: "darwin",
appName: "System Settings",
title: "Screen Recording",
text: "BossComputerUseHelper would like to record this computer's screen",
buttons: ["Allow", "Don't Allow"],
});
assert.equal(decision.disposition, "needs_user_action");
assert.equal(decision.risk, "blocked");
assert.equal(decision.kind, "permission_required");
});
test("dialog guard generates stable signatures from normalized content", () => {
const a = createDialogSignature({
platform: "darwin",
deviceId: "macbook-air",
appBundleId: "com.google.Chrome",
title: " Welcome ",
text: "Not now",
buttons: ["Not now", "OK"],
});
const b = createDialogSignature({
platform: "darwin",
deviceId: "macbook-air",
appBundleId: "com.google.Chrome",
title: "Welcome",
text: " Not now ",
buttons: ["Not now", "OK"],
});
assert.equal(a.id, b.id);
assert.equal(a.scopeKey, "darwin:macbook-air:com.google.Chrome");
});
test("dialog guard emits app-safe intervention payload", () => {
const snapshot = normalizeDialogSnapshot({
platform: "win32",
deviceId: "win-node",
appName: "Installer",
title: "User Account Control",
text: "Do you want to allow this app to make changes to your device?",
buttons: ["Yes", "No"],
});
const decision = evaluateDialogSnapshot(snapshot);
const result = buildDialogInterventionResult({
requestId: "desktop-task-1",
snapshot,
decision,
});
assert.equal(result.status, "needs_user_action");
assert.equal(result.kind, "dialog_intervention_required");
assert.equal(result.risk, "blocked");
assert.deepEqual(result.availableActions, ["handled_on_device", "cancel_task"]);
assert.match(result.summary, /Installer/);
});
```
- [ ] **Step 2: Run test to verify it fails**
Run: `node --test tests/local-agent-desktop-dialog-guard.test.mjs`
Expected: FAIL because `local-agent/desktop-dialog-guard.mjs` does not exist.
- [ ] **Step 3: Implement minimal policy engine**
Create `local-agent/desktop-dialog-guard.mjs` with:
```js
import { createHash } from "node:crypto";
const SAFE_DISMISS_BUTTONS = ["稍后", "跳过", "以后再说", "Not now", "Skip", "Later", "Cancel"];
const BLOCKED_TEXT_PATTERNS = [
/screen recording/i,
/accessibility/i,
/input monitoring/i,
/full disk access/i,
/keychain/i,
/administrator/i,
/apple id/i,
/user account control/i,
/make changes to your device/i,
/屏幕录制/,
/辅助功能/,
/输入监控/,
/完整磁盘访问/,
/钥匙串/,
/管理员密码/,
];
export function normalizeDialogText(value) {
return String(value || "").replace(/\s+/g, " ").trim();
}
export function normalizeDialogSnapshot(input = {}) {
const buttons = Array.isArray(input.buttons)
? input.buttons.map(normalizeDialogText).filter(Boolean)
: [];
return {
platform: normalizeDialogText(input.platform || process.platform || "unknown"),
deviceId: normalizeDialogText(input.deviceId || "unknown-device"),
appName: normalizeDialogText(input.appName || input.app || "Unknown App"),
appBundleId: normalizeDialogText(input.appBundleId || input.appId || input.appName || input.app || "unknown-app"),
title: normalizeDialogText(input.title),
text: normalizeDialogText(input.text),
buttons,
};
}
function hash(value) {
return createHash("sha256").update(value).digest("hex").slice(0, 16);
}
export function createDialogSignature(snapshotInput = {}) {
const snapshot = normalizeDialogSnapshot(snapshotInput);
const titleHash = hash(snapshot.title.toLowerCase());
const textHash = hash(snapshot.text.toLowerCase());
const buttonHash = hash(snapshot.buttons.join("|").toLowerCase());
return {
id: hash([snapshot.platform, snapshot.deviceId, snapshot.appBundleId, titleHash, textHash, buttonHash].join("|")),
scopeKey: [snapshot.platform, snapshot.deviceId, snapshot.appBundleId].join(":"),
platform: snapshot.platform,
deviceId: snapshot.deviceId,
appBundleId: snapshot.appBundleId,
titleHash,
textHash,
buttonHash,
};
}
function findSafeDismissButton(buttons) {
return buttons.find((button) =>
SAFE_DISMISS_BUTTONS.some((candidate) => candidate.toLowerCase() === button.toLowerCase()),
);
}
function isBlockedPrompt(snapshot) {
const combined = `${snapshot.title} ${snapshot.text}`;
return BLOCKED_TEXT_PATTERNS.some((pattern) => pattern.test(combined));
}
export function evaluateDialogSnapshot(snapshotInput = {}) {
const snapshot = normalizeDialogSnapshot(snapshotInput);
const signature = createDialogSignature(snapshot);
if (isBlockedPrompt(snapshot)) {
return {
disposition: "needs_user_action",
kind: "permission_required",
risk: "blocked",
action: "pause_for_user",
signature,
};
}
const safeButton = findSafeDismissButton(snapshot.buttons);
if (safeButton) {
return {
disposition: "auto_action",
kind: "safe_dismiss",
risk: "safe",
action: "click_button",
button: safeButton,
signature,
};
}
return {
disposition: "needs_user_action",
kind: "unknown_dialog",
risk: "medium",
action: "pause_for_user",
signature,
};
}
export function buildDialogInterventionResult({ requestId, snapshot: snapshotInput, decision }) {
const snapshot = normalizeDialogSnapshot(snapshotInput);
const signature = decision?.signature || createDialogSignature(snapshot);
const blocked = decision?.risk === "blocked";
return {
status: "needs_user_action",
requestId: requestId || undefined,
kind: "dialog_intervention_required",
dialogId: signature.id,
risk: decision?.risk || "medium",
summary: `${snapshot.appName} 弹窗需要确认:${snapshot.title || snapshot.text || "未知弹窗"}`,
recommendedAction: blocked ? "handle_on_device" : "review",
availableActions: blocked
? ["handled_on_device", "cancel_task"]
: ["allow_once", "allow_for_device_dialog", "deny"],
platform: snapshot.platform,
appName: snapshot.appName,
};
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `node --test tests/local-agent-desktop-dialog-guard.test.mjs`
Expected: PASS.
### Task 2: Runner Result Support
**Files:**
- Modify: `local-agent/computer-use-task-runner.mjs`
- Test: `tests/local-agent-computer-use-runner.test.mjs`
- [ ] **Step 1: Write failing parser test**
Append this test:
```js
test("computer use runner parses dialog intervention runtime payload", () => {
const result = parseComputerUseTaskResult(
JSON.stringify({
status: "needs_user_action",
requestId: "desktop-task-dialog",
kind: "dialog_intervention_required",
dialogId: "dialog-1",
risk: "medium",
summary: "QQ 弹窗需要确认",
recommendedAction: "review",
availableActions: ["allow_once", "deny"],
platform: "darwin",
appName: "QQ",
}),
);
assert.equal(result.status, "needs_user_action");
assert.equal(result.requestId, "desktop-task-dialog");
assert.equal(result.kind, "dialog_intervention_required");
assert.equal(result.dialogId, "dialog-1");
assert.equal(result.risk, "medium");
assert.equal(result.summary, "QQ 弹窗需要确认");
assert.deepEqual(result.availableActions, ["allow_once", "deny"]);
});
```
- [ ] **Step 2: Run test to verify it fails**
Run: `node --test tests/local-agent-computer-use-runner.test.mjs`
Expected: FAIL because `needs_user_action` is not parsed.
- [ ] **Step 3: Implement parser branch**
Update `parseComputerUseTaskResult` so `status === "needs_user_action"` returns a structured object containing requestId, kind, dialogId, risk, summary, recommendedAction, availableActions, platform and appName.
- [ ] **Step 4: Run test to verify it passes**
Run: `node --test tests/local-agent-computer-use-runner.test.mjs`
Expected: PASS.
### Task 3: Runtime Guard Integration
**Files:**
- Modify: `scripts/computer-use-smoke.mjs`
- Test: `tests/browser-desktop-smoke-runtime-scripts.test.mjs`
- [ ] **Step 1: Write failing runtime tests**
Add tests that run `scripts/computer-use-smoke.mjs` with `BOSS_DIALOG_GUARD_ENABLED=true` and `BOSS_DIALOG_GUARD_SNAPSHOT_JSON`.
The safe test should assert the runtime completes and includes a `dialogGuard` artifact entry. The blocked test should assert the runtime returns `needs_user_action` before executing the desktop action.
- [ ] **Step 2: Run tests to verify failure**
Run: `node --test tests/browser-desktop-smoke-runtime-scripts.test.mjs`
Expected: FAIL because the smoke runtime ignores dialog guard env vars.
- [ ] **Step 3: Implement runtime preflight**
Import the dialog guard module, parse `BOSS_DIALOG_GUARD_ENABLED`, parse `BOSS_DIALOG_GUARD_SNAPSHOT_JSON`, evaluate it before desktop automation, return `needs_user_action` for pause decisions, and include auto-action audit info in artifacts for safe decisions.
- [ ] **Step 4: Run tests to verify pass**
Run: `node --test tests/browser-desktop-smoke-runtime-scripts.test.mjs`
Expected: PASS.
### Task 4: Config Defaults
**Files:**
- Modify: `local-agent/config.example.json`
- Modify: `local-agent/config.cloud.json`
- Test: `tests/browser-desktop-runtime-config-defaults.test.mjs`
- [ ] **Step 1: Write failing config test**
Extend the default config test to assert `dialogGuardEnabled`, `dialogGuardPlatformAdapters`, and `dialogGuardConsentRequired` are present.
- [ ] **Step 2: Run test to verify failure**
Run: `node --test tests/browser-desktop-runtime-config-defaults.test.mjs`
Expected: FAIL because the config keys are absent.
- [ ] **Step 3: Add defaults**
Add:
```json
"dialogGuardEnabled": true,
"dialogGuardConsentRequired": true,
"dialogGuardPlatformAdapters": ["darwin", "win32"]
```
- [ ] **Step 4: Run test to verify pass**
Run: `node --test tests/browser-desktop-runtime-config-defaults.test.mjs`
Expected: PASS.
### Task 5: Focused Verification
**Files:**
- No production files.
- [ ] **Step 1: Run focused tests**
Run:
```bash
node --test tests/local-agent-desktop-dialog-guard.test.mjs \
tests/local-agent-computer-use-runner.test.mjs \
tests/browser-desktop-smoke-runtime-scripts.test.mjs \
tests/browser-desktop-runtime-config-defaults.test.mjs
```
Expected: PASS.
- [ ] **Step 2: Run project checks**
Run:
```bash
npm run lint
npm run build
```
Expected: both PASS.
## Self-review
Spec coverage:
1. macOS and Windows are represented by platform-neutral snapshots and adapter-ready config keys.
2. Safe auto handling, sensitive pause, signatures, APP-friendly intervention payloads and audit artifacts are covered.
3. Full native AX/UIA helpers are intentionally deferred behind the adapter interface because this batch establishes the runtime contract first.
Placeholder scan: no unresolved placeholders.
Type consistency: `needs_user_action`, `dialogId`, `risk`, `summary`, `availableActions`, `platform`, and `appName` are consistent across plan tasks.

View File

@@ -0,0 +1,75 @@
# Ruflo Governance And Dialog Guard Completion Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Finish the next Boss control-plane layer: Desktop Dialog Guard user confirmation/audit, plus Ruflo-inspired task ownership, capability grouping, and device trust foundations.
**Architecture:** Keep Ruflo as a reference only, not a runtime dependency. Add small Boss-native modules and route contracts that fit the current file-backed state store, Android realtime channel, local-agent desktop runtime, and existing RBAC/audit patterns.
**Tech Stack:** Next.js route handlers, TypeScript state helpers, Node test runner/tsx tests, Android Java/Robolectric, Boss SSE events, local-agent runtime payloads.
---
## Task A: Dialog Guard Backend Completion
**Files:**
- Modify: `src/lib/boss-data.ts`
- Modify: `src/app/api/v1/master-agent/tasks/[taskId]/complete/route.ts`
- Create: `src/app/api/v1/dialog-guard/interventions/[interventionId]/decision/route.ts`
- Test: `tests/dialog-guard-interventions-route.test.ts`
**Steps:**
- [ ] Add a failing route test proving `status: "needs_user_action"` with `kind: "dialog_intervention_required"` creates a pending intervention and publishes `desktop.dialog_guard.intervention_required`.
- [ ] Add a failing route test proving a user decision updates the intervention, writes a permission audit log, and publishes `desktop.dialog_guard.intervention_resolved`.
- [ ] Add `DialogGuardIntervention` state shape and migration default.
- [ ] Extend the master-agent completion route to preserve `needs_user_action` instead of normalizing it to completed.
- [ ] Implement decision route with allowed decisions: `allow_once`, `allow_for_device_dialog`, `deny`, `handled_on_device`, `cancel_task`.
- [ ] Run the focused backend tests.
## Task B: Android Dialog Guard Confirmation UI
**Files:**
- Modify: `android/app/src/main/java/com/hyzq/boss/BossApiClient.java`
- Modify: `android/app/src/main/java/com/hyzq/boss/BossNotificationRouter.java`
- Modify: `android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java`
- Modify: `android/app/src/main/java/com/hyzq/boss/BossUi.java`
- Test: `android/app/src/test/java/com/hyzq/boss/DialogGuardInterventionUiTest.java`
**Steps:**
- [ ] Add failing Robolectric test for handling `desktop.dialog_guard.intervention_required`.
- [ ] Render a compact confirmation card/dialog using the current Boss/微信-style visual system.
- [ ] For `blocked` risk, show only `我已在电脑上处理` and `取消任务`.
- [ ] For medium/safe risk, show `允许本次`, `当前设备此弹窗允许`, `拒绝` based on `availableActions`.
- [ ] Call `POST /api/v1/dialog-guard/interventions/{interventionId}/decision`.
- [ ] Remove/refresh the card on `desktop.dialog_guard.intervention_resolved`.
- [ ] Run the focused Android test.
## Task C: Ruflo-Inspired Governance Foundation
**Files:**
- Create: `src/lib/boss-work-claims.ts`
- Create: `src/lib/boss-capability-groups.ts`
- Create: `src/lib/boss-device-trust.ts`
- Test: `tests/ruflo-governance-foundation.test.ts`
**Steps:**
- [ ] Add failing tests for claim, handoff, stale claim detection, and stealable work.
- [ ] Add failing tests for grouped capabilities: computer control, Codex development, browser automation, skill operations, admin ops.
- [ ] Add failing tests for device trust tiers and budget/hop limit checks.
- [ ] Implement pure Boss-native modules without importing Ruflo.
- [ ] Keep the API persistence-ready but not UI-bound.
- [ ] Run the focused governance test.
## Integration Verification
- [ ] Run focused backend tests.
- [ ] Run focused Android test if local Gradle supports it.
- [ ] Run `npm run lint`.
- [ ] Run `npm run build`.
## Notes
Ruflo is used as architecture reference only. The Boss implementation must stay deterministic, auditable, RBAC-aware, and safe for multi-tenant enterprise deployment.

View File

@@ -0,0 +1,181 @@
# Codex Desktop 同线程消息镜像设计
目标:当用户在 Boss App 里对一个已绑定 `codexThreadRef` 的单线程会话发消息时,这条用户消息不仅进入 Boss 自己的项目账本和 `conversation_reply` 执行队列,也要被镜像进本机 Codex Desktop 的同一个线程历史里。这样用户稍后回到 Codex Desktop看见的是同一个线程下连续的聊天记录而不是 Boss 与 Desktop 两套割裂历史。
## 背景与现状
当前 Boss 的普通线程单聊主链是:
- Web / Android 调 `POST /api/v1/projects/[projectId]/messages`
- 服务端写入 Boss 项目消息账本
- 服务端排一个 `conversation_reply` 任务
- 本机 `local-agent` 认领任务后调用 `codex exec resume <targetCodexThreadRef>`
- Codex 线程完成后,再把线程回复回写到 Boss 项目账本
这条链现在已经能做到“Desktop 回复被 Boss 看见”,因为 heartbeat 扫描 `~/.codex/sessions/.../rollout-*.jsonl` 时,会把最近桌面 assistant 回复镜像回 Boss。缺口在反方向
- Boss App 发起的用户消息只存在于 Boss 项目账本
- `codex exec resume` 虽然会把 prompt 交给目标线程继续执行,但 Boss 发起的这条消息并不会先出现在 Desktop 线程历史
- 结果就是用户在 APP 和 Desktop 里看到的“同一个线程”并不是同一份完整聊天记录
## 方案对比
### 方案 1直接操控 Codex Desktop GUI 输入并发送
优点:
- 理论上最贴近“像用户在桌面端亲自发了一条消息”
缺点:
- 依赖窗口前台、焦点、输入法、系统权限
- 极易被 Codex Desktop UI 更新打断
- 无法稳定支持后台运行和多线程并发
不推荐作为主方案。
### 方案 2直接把 Boss 用户消息写入对应 Codex rollout JSONL再继续现有 `codex exec resume`
优点:
- 与当前 Desktop/CLI 共用的真实线程存储一致
- 不需要操控 GUI
- 可以保持现有 `local-agent -> codex exec resume` 主链不变
- 能与现有 heartbeat 读取 rollout 的能力形成闭环
缺点:
- 需要谨慎贴合 Codex rollout 事件格式
- 需要处理重复写入和 Desktop 刷新感知
这是本次推荐方案。
### 方案 3单独给 Desktop 再建一条镜像线程
优点:
- 对现有线程文件侵入最小
缺点:
- 用户要的是“同一个线程”,不是“另一个镜像线程”
- 历史会继续分叉
不满足目标。
## 本次设计
### 1. 保持 Boss 账本为移动端/UI 主真相
Boss 的项目消息账本、会话排序、未读数、主 Agent 协同逻辑继续基于现有 `boss-state.json`。这次不把 Boss UI 改成直接读取 `~/.codex`
### 2. 对单线程 `conversation_reply` 任务增加“写入 Desktop 线程历史”的镜像步骤
当任务满足以下条件时,在 `local-agent` 侧做一次 rollout 镜像:
- `task.taskType === "conversation_reply"`
- 存在 `targetCodexThreadRef`
- 存在用户原始消息文本
- 不属于 `relayViaMasterAgent === true` 的接管中转任务
镜像行为:
- 优先通过 `state_5.sqlite``threads.rollout_path` 定位目标 rollout 文件
- 如果本机 Codex 因版本/迁移差异无法稳定解析 `state_5.sqlite`,则回退扫描 `~/.codex/sessions/**/rollout-*-<threadId>.jsonl`
- 向该 rollout 文件追加一组 Codex 用户消息记录:`response_item / message(role=user)``event_msg / user_message`
- 事件内容使用 Boss 原始用户消息文本,而不是执行 prompt
- 事件时间优先使用 Boss 消息的 `sentAt`
- 事件写入成功后,再继续现有 `codex exec resume`
### 3. 任务负载补齐“Boss 原始消息”字段
现在任务里只有:
- `requestMessageId`
- `requestText`
- `executionPrompt`
这还不够稳,因为后续去重和 Desktop 镜像需要区分:
- 哪条 Boss 用户消息已经镜像过
- 这次镜像的真实显示文本是什么
- 这条消息的原始时间戳是什么
因此为 `MasterAgentTask` 增加:
- `sourceMessageId?: string`
- `sourceMessageBody?: string`
- `sourceMessageSentAt?: string`
- `mirrorBossUserMessageToCodexDesktop?: boolean`
对普通线程单聊:
- `sourceMessageId = message.id`
- `sourceMessageBody = message.body`
- `sourceMessageSentAt = message.sentAt`
- `mirrorBossUserMessageToCodexDesktop = true`
对主 Agent 直聊、`@主Agent`、托管中转等不应写进子线程 Desktop 历史的场景,不开启这个标记。
### 4. 去重策略
同一条 Boss 消息可能因为:
- 任务重试
- local-agent 重启
- claim / complete 重放
而被多次处理。为避免在 Desktop 线程里重复写入同一条用户消息本次采用“rollout 末尾去重”:
- 生成稳定镜像 key`boss-user:<threadRef>:<sourceMessageId>`
- 写入的 `event_msg` 中带上 `payload.metadata.bossSourceMessageId`
- 写入前读取 rollout 尾部固定窗口,检查最近是否已经存在同一 `bossSourceMessageId`
- 若存在,则跳过写入,仅继续 `codex exec resume`
这样不需要引入新的状态库,也能与 Codex 原始线程文件保持局部自洽。
### 5. 刷新感知
第一版只写 rollout 还不够稳,因为 Desktop 的线程列表排序和“最近活跃”判断通常还依赖 `threads.updated_at / updated_at_ms / has_user_event`。因此本次实现改为:
- rollout append 成功后,若 `state_5.sqlite` 可写且能命中该 thread则同步刷新
- `updated_at`
- `updated_at_ms`
- `has_user_event = 1`
- 如果当前机器上的 Codex 状态库不可用、字段不兼容或压根没有这条 thread 记录,则只保留 rollout 写入,不把整条消息链路判成失败
这样做的取舍是:
- 先保证 Boss -> Codex Desktop 同线程历史不丢
- 再尽可能提升 Desktop 侧的列表刷新和最近活跃感知
- 不引入 GUI 自动化,不依赖桌面窗口前台
## 涉及文件
- 新增 `local-agent/codex-thread-rollout-writer.mjs`
- 修改 `local-agent/codex-task-runner.mjs`
- 修改 `local-agent/server.mjs`
- 修改 `src/lib/boss-data.ts`
- 修改 `src/app/api/v1/projects/[projectId]/messages/route.ts`
- 修改 `src/lib/boss-master-agent.ts`(如果当前普通线程任务创建逻辑在这里有共用 helper也一起补齐
- 新增测试 `tests/local-agent-codex-rollout-writer.test.mjs`
- 修改测试 `tests/local-agent-codex-task-runner.test.mjs`
- 修改测试 `tests/single-thread-message-execution.test.ts`
## 边界
- 本次只处理“Boss App -> 已绑定 Codex Desktop 同线程”的用户消息镜像
- 不处理群聊镜像到 Desktop
- 不处理主 Agent 自己的回复写入 Desktop 子线程
- 不做 Codex Desktop GUI 自动输入
- 不把 Boss 会话列表直接改成读取 Desktop 原始线程文件
## 验收标准
- 普通单线程会话发消息后,生成的 `conversation_reply` 任务带有完整 `sourceMessage*` 字段
- local-agent 在执行 `codex exec resume` 前,能把这条 Boss 用户消息写进目标 rollout
- 同一 `sourceMessageId` 重试时不会重复写入 rollout
- 若状态库可用,镜像后会同步刷新 thread 的活跃时间和 `has_user_event`
- 若状态库不可用或这台机器上的线程索引不完整,仍可通过 `sessions` 回退找到 rollout 并完成消息镜像
- 现有普通线程回复链不回归Boss 仍能收到 Codex 线程回复
- 若目标线程缺失、只读或 cwd 不合法,仍保持现有 fail-closed 行为

View File

@@ -0,0 +1,399 @@
# Boss 聊天统一电脑控制中枢设计
目标:让用户在 Boss App 里,无论是和 `主 Agent` 对话,还是和某个具体线程对话,都可以稳定驱动这台 Mac/Windows 设备完成三类事情:
- 项目开发与代码执行
- 浏览器/桌面 GUI 操作
- 普通产品讨论、调研和任务协同
并且这三类能力不再割裂成几条旁路,而是统一挂在 Boss 现有的聊天、执行底座和设备心跳体系下面。
## 背景与现状
当前 Boss 已经具备几条关键基础链路:
- `master-agent` 单聊可以通过 `local-agent -> codex exec` 真实产出回复
- 普通单线程聊天已经可以排 `conversation_reply` 任务,并恢复到真实 Codex 线程执行
- 群聊已有 `group_dispatch_plan -> dispatch_execution` 的编排链
- 设备模型已经支持同一台机器的 `GUI + CLI` 双能力声明与默认执行模式切换
- 本机 `local-agent` 已能做 Codex 线程发现、task claim、task complete、Desktop rollout 镜像
但目前缺的不是“再加一个按钮”,而是统一控制中枢:
- `conversation_reply` 只适合“把消息转给 Codex 线程继续聊”
- `dispatch_execution` 主要面向群聊下发和线程编排
- 还没有正式的“桌面控制 / 浏览器控制”任务类型
- 主 Agent 也没有显式的能力路由模型,无法稳定判断当前消息应该走:
- Codex 开发
- Browser automation
- Computer Use
- 单纯讨论/总结
这会导致现在的体验像“能做一些事”,但还不是“可以靠 Boss 聊天控制电脑做事”。
## 目标边界
### 本次要达到的能力
1. 主 Agent 能把用户消息识别成四类执行意图:
- `project_development`
- `thread_collaboration`
- `browser_control`
- `desktop_control`
2. Boss 执行底座能显式表达这四类请求,并把它们路由到正确 runtime。
3. `local-agent` 增加两条新 runtime
- `browser-automation-runtime`
- `computer-use-runtime`
4. Web / Android 前台至少能拿到任务执行方式和当前状态,知道这条消息是:
- 交给 Codex 线程
- 交给浏览器自动化
- 交给桌面控制
- 仅由主 Agent 直接回复
5. 对高风险桌面动作建立最小确认机制,避免“发一句话就直接在电脑上乱点/乱删”。
### 本次不做的事情
- 不做完整远控桌面产品
- 不做视频流式屏幕回传
- 不做跨设备键鼠镜像
- 不把 Codex Desktop 自己纳入 Computer Use 自动点击目标
- 不依赖 GUI 自动化去操控 Codex 自己的窗口
## 方案原则
### 原则 1复用 Boss 现有执行底座,不另起一套“远控系统”
如果我们再单独造一层 `remote-control service`,会把:
- 会话账本
- 任务队列
- 权限与确认
- 前台状态展示
- 设备能力发现
全部再复制一遍。成本高,而且会和当前 Boss 的“聊天即控制入口”相冲突。
所以本次明确采用:
- 用户入口仍然是 Boss 聊天
- 任务记录仍然是 `MasterAgentTask`
- 路由仍然收敛进 `src/lib/execution`
- 执行仍然由绑定设备上的 `local-agent` 落地
### 原则 2先把“控制判断”标准化再扩 runtime
现在最大的问题不是工具不够,而是没有统一的“这条消息该怎么执行”判断结果。
因此要先补一层执行意图:
- `discussion_only`
- `thread_reply`
- `browser_control`
- `desktop_control`
- `development_execution`
然后让不同后端只关心自己该执行哪一种。
### 原则 3危险动作永远要显式分级
Boss 最终要能“做任何事”,但不能把“任何事”理解成“任何时候都自动执行”。
所以本次引入最小风险分级:
- `low`
- 打开页面
- 搜索信息
- 读取项目文件
- 运行只读检查
- `medium`
- 登录态网页操作
- 浏览器表单提交
- 桌面应用点击导航
- 修改非代码业务内容
- `high`
- 删除/覆盖文件
- 系统设置改动
- 批量提交/发布
- 不可逆外部操作
策略:
- `low`:默认直接执行
- `medium`:默认轻确认,可在项目/会话级放行
- `high`:必须明确确认
## 控制中枢设计
## 1. 新的执行意图模型
在当前 `ExecutionRequestKind` 基础上新增:
- `browser_control`
- `desktop_control`
并补充一个统一意图字段,供主 Agent 和前台共用:
- `intentCategory`
- `discussion_only`
- `project_development`
- `thread_collaboration`
- `browser_control`
- `desktop_control`
其中:
- `project_development` 继续优先走现有 Codex 线程 / CLI 执行链
- `thread_collaboration` 继续走 `conversation_reply`
- `browser_control` 新增浏览器自动化 runtime
- `desktop_control` 新增 Computer Use runtime
## 2. 新的 runtime 层
### 2.1 browser-automation-runtime
用途:
- 打开网页
- 登录指定后台
- 提交表单
- 抓取页面信息
- 复现 Web bug
第一版实现直接复用现有 Playwright 能力,不重新造驱动协议。
建议协议:
- 输入:
- `taskId`
- `projectId`
- `requestText`
- `executionPrompt`
- `targetUrl?`
- `riskLevel`
- 输出:
- `status`
- `replyBody`
- `structuredResult?`
- `artifacts?`
落地约束:
- `local-agent/browser-control-task-runner.mjs` 先收口成外部 runtime 桥,不把 Playwright 逻辑硬编码进 `server.mjs`
- 通过 `browserControlEnabled / browserControlCommand / browserControlArgs / browserControlWorkdir / browserControlTimeoutMs` 配置启用
- runtime 进程只需要遵守单行 JSON stdout 协议,后续可以平滑替换成真实 Playwright/OpenClaw/browser adapter
### 2.2 computer-use-runtime
用途:
- 打开本机应用
- 在桌面 GUI 上点击、输入、切换
- 配合浏览器外的桌面软件完成操作
第一版实现直接对接 Codex App 现有的 Computer Use 能力约束:
- 只能操作普通桌面应用
- 需要系统 Screen Recording + Accessibility
- 不把终端/Codex 自己当作自动点击目标
这意味着:
- 项目开发仍然优先走 Codex CLI/线程
- Computer Use 负责 GUI 世界
- 两者由主 Agent 在同一条聊天链里自动选择
落地约束:
- `local-agent/computer-use-task-runner.mjs` 同样先做成外部 runtime 桥
- 通过 `computerUseEnabled / computerUseCommand / computerUseArgs / computerUseWorkdir / computerUseTimeoutMs` 配置启用
- 先统一 Boss 与 runtime 的协议,再按设备情况接 Codex App Computer Use、OpenClaw 或其他 GUI runtime
## 3. MasterAgentTask 扩展
当前 `MasterAgentTaskType` 只有:
- `conversation_reply`
- `attachment_analysis`
- `group_dispatch_plan`
- `dispatch_execution`
- `device_import_resolution`
本次新增:
- `browser_control`
- `desktop_control`
新增字段:
- `intentCategory?`
- `runtimeKind?`
- `riskLevel?`
- `confirmationPolicy?`
- `requiresUserConfirmation?`
- `confirmationScopeKey?`
目的:
- 前台能展示“当前这条消息要走哪条执行链”
- 服务端能统一处理确认/拦截
- `local-agent` 能按 runtimeKind 正确分流
## 4. 主 Agent 路由逻辑
主 Agent 不再简单分成“自己答”或“排 conversation_reply”而是多一步意图判断。
推荐判断顺序:
1. 如果是明显的项目讨论、总结、目标/版本记录、普通问答
- `discussion_only`
2. 如果是“继续开发 / 改代码 / 跑测试 / 看项目状态 / 接手某线程”
- `project_development``thread_collaboration`
3. 如果是“打开网站 / 点网页 / 查后台 / 提交表单 / 看页面”
- `browser_control`
4. 如果是“打开电脑软件 / 操作桌面 / 系统 GUI / 非浏览器界面”
- `desktop_control`
路由结果:
- `discussion_only`
- 主 Agent 直接回复
- `thread_collaboration`
- 继续 `conversation_reply`
- `project_development`
- 优先真实 Codex 线程 / CLI
- `browser_control`
-`browser_control` 任务
- `desktop_control`
-`desktop_control` 任务
## 5. 设备能力模型
当前设备只有:
- `gui`
- `cli`
这对“统一控制电脑”不够精确,所以建议在设备 heartbeat 能力里细化为:
- `cli`
- `gui`
- `browserAutomation`
- `computerUse`
其中:
- `browserAutomation` 可由本机 Playwright/runtime 探测
- `computerUse` 由本机配置和权限状态探测
这样前台与主 Agent 都能知道:
- 当前机器只能写代码
- 还是也能控浏览器
- 还是能做完整桌面 GUI 操作
## 6. 前台产品表现
### 会话页 / 聊天页
每条“触发执行”的用户消息,服务端返回时增加:
- `executionMode`
- `discussion`
- `thread`
- `development`
- `browser`
- `desktop`
- `riskLevel`
- `requiresConfirmation`
前台展示原则:
- 不做厚重控制台 UI
- 保持当前微信式聊天界面
- 只在消息下方补一条轻状态:
- `已交给主 Agent`
- `正在调用浏览器自动化`
- `正在调用桌面控制`
- `等待你确认后执行`
### 会话信息 / 设备详情
补一个轻量能力区:
- `默认开发模式CLI / GUI`
- `浏览器自动化:可用 / 不可用`
- `桌面控制:可用 / 不可用`
不把这些塞回聊天主界面。
## 7. 风险确认设计
### 会话级别
如果当前会话在某个项目下已经对中风险动作做过一次确认,则可以对这个项目保留:
- `禁止`
- `允许本次`
- `当前项目永久放行`
这和现有 GUI/CLI 并行冲突的项目级策略一致,避免用户多学一套规则。
### 任务级别
当主 Agent 判断为高风险时:
- 不直接执行
- 先在聊天里给出极简确认卡
- 用户点确认后再排任务
## 8. 本次实施顺序
### 第一批
- 写设计与计划文档
- 扩展任务类型、执行请求类型、设备能力类型
- 接入 `browser_control / desktop_control` 两类任务基础骨架
- `local-agent` 增加 runtime 分流占位
- 前台返回 `executionMode/riskLevel` 元数据
### 第二批
- 接入 browser automation 真执行
- 接入 computer use 真执行
- 完成确认链
### 第三批
- Android/Web 前台补状态展示
- 真机回归
- 文档回写
## 涉及文件
- 修改 `src/lib/execution/types.ts`
- 修改 `src/lib/execution/tool-registry.ts`
- 修改 `src/lib/execution/permission-policy.ts`
- 修改 `src/lib/boss-data.ts`
- 修改 `src/lib/boss-master-agent.ts`
- 修改 `src/app/api/v1/projects/[projectId]/messages/route.ts`
- 修改 `local-agent/codex-task-runner.mjs`
- 修改 `local-agent/server.mjs`
- 新增 `local-agent/browser-control-task-runner.mjs`
- 新增 `local-agent/computer-use-task-runner.mjs`
- 新增对应 tests
## 验收标准
- 主 Agent 能把聊天输入稳定区分成讨论、开发、浏览器控制、桌面控制四类
- `browser_control / desktop_control` 能以正式任务进入 Boss 队列
- `local-agent` 能识别并分流这两类任务
- 前台能看到当前消息是走哪条执行链
- 中高风险动作不会静默直接执行
- 现有 `conversation_reply / dispatch_execution` 主链不回归

View File

@@ -0,0 +1,151 @@
# Boss To B 总后台重构设计
日期2026-04-30
## 背景
当前 `/admin` 已经具备最高管理员访问控制、总览聚合、账号授权、风险处理和 Skill 生命周期治理能力,但页面仍像“几个数据表拼在一起”。对于 To B 交付场景,平台侧需要的是一套能服务客户成功、运维值守和权限开通的 PC 总后台,而不是一个调试看板。
本次重构不新增大业务边界,优先重组现有 `/api/v1/admin/overview``/api/v1/admin/access``/api/v1/admin/risks/actions``/api/v1/admin/skills/requests` 数据和动作,把后台做成可用、可读、可处置的运营控制台。
## 目标
1. 最高管理员进入后台后,能在 10 秒内看出哪些客户、设备、主 Agent 任务或线程风险需要处理。
2. 客户开通从“多个分散表单”收口成可理解的工作台公司、老板账号、子账号、设备、项目、Skill 授权有清晰入口和状态。
3. 风险处理从“表格按钮”升级为战情室按严重程度、客户影响、负责人、SLA 和下一步动作组织。
4. Skill 治理保留安全约束,但展示成可追踪的生命周期队列。
5. UI 风格从移动端微信效率风改为 PC To B 管理后台:高密度、强层级、清晰状态、少装饰。
## 非目标
- 不引入新的 Umi / Ant Design Pro 工程。
- 不切换 PostgreSQL 或重写状态存储。
- 不改 Android APP 端交互。
- 不绕过 local-agent 的 Skill allowlist、checksum、备份和回滚约束。
- 不把客户侧 Web 控制台和平台总后台混成一个产品。
## 信息架构
后台改为 4 个一级区:
1. `驾驶舱`:平台全局健康、关键风险、客户影响、在线设备、主 Agent 失败、待处理通知。
2. `客户与账号`:公司列表、客户详情、账号开通、角色状态、登录与安全概览。
3. `授权工作台`设备、项目、Skill 授权,权限模板,过期授权,离职回收和审计。
4. `风险与治理`风险战情室、SLA、负责人、修复工单、风险时间线、Skill 生命周期请求。
现有 `账号与授权``Skill 治理` 不是删除,而是拆到更合理的上下文里:账号归客户,授权归权限,风险和 Skill 请求归治理。
## 页面设计
### 驾驶舱
顶部保留平台身份和刷新动作但标题从“Boss 管理后台”升级为“平台运营驾驶舱”。主区域按优先级展示:
- `今日待处理`:关键风险数、超 SLA 通知、离线设备、主 Agent 失败。
- `客户健康排行`:按开放风险、在线设备比例、合同/套餐状态排序。
- `关键风险队列`只展示最值得处理的风险提供负责人、SLA、确认、关闭、工单动作。
- `设备与节点健康`GUI/CLI、Browser、Computer Use 能力状态集中展示。
- `最近事件`:风险时间线和权限审计摘要。
驾驶舱默认不展示大分页表,避免用户一打开就被表格淹没。
### 客户与账号
采用左侧客户列表 + 右侧详情的结构:
- 客户列表显示公司名、套餐、账号数、设备数、开放风险、客户成功负责人。
- 右侧详情显示老板账号、子账号、绑定设备、项目数量和最近风险。
- 新建客户流程拆成三步:创建公司、创建老板账号、绑定设备/项目。
- 子账号管理支持启用/停用、重置密码、MFA 状态和登录会话摘要。
这部分复用现有 `/api/v1/admin/access`,但前台从表单堆叠改成任务流。
### 授权工作台
授权页面按“给谁授权”而不是“授权类型”组织:
- 先选择账号或客户。
- 再选择设备、项目、Skill。
- 最后套用权限模板或手动勾选权限。
页面底部保留最近授权审计和过期授权提醒。高危动作继续二次确认。
### 风险与治理
风险页面采用“战情室”结构:
- 左侧风险队列:按 `critical / warning / info`、客户、负责人、SLA 筛选。
- 中间风险详情:影响对象、错误摘要、最近时间线、建议动作。
- 右侧处理面板:指派、设置 SLA、确认、关闭、创建工单。
Skill 生命周期治理放在同一区域的第二页签,展示为请求队列:
- 待认领、执行中、成功、失败分栏。
- 每条请求展示设备、Skill、动作、来源、checksum、结果摘要。
- 创建请求表单保留,但根据动作动态收敛字段。
## 组件边界
建议拆出以下组件,降低当前 `boss-admin-app.tsx` 的复杂度:
- `AdminShell`PC 后台壳、顶部栏、一级导航。
- `AdminDashboard`:驾驶舱。
- `AdminCustomerWorkspace`:客户与账号工作台。
- `AdminPermissionWorkspace`:授权工作台。
- `AdminRiskCommandCenter`:风险战情室。
- `AdminSkillGovernance`Skill 生命周期治理,可复用并改造当前组件。
- `AdminStatusBadge``AdminMetricCard``AdminActionRail`:统一状态、指标和动作区。
数据请求先继续使用现有 fetch不强制引入新的客户端状态库。
## 数据和接口
第一批不要求新增后端字段,但前台应完整使用现有字段:
- `summary`
- `companies`
- `accounts`
- `devices`
- `risks`
- `notifications`
- `riskTimeline`
- `grantsSummary`
如果发现页面需要客户健康分数,可先在前端由 `openRiskCount / onlineDeviceCount / deviceCount / status` 计算,不改状态 schema。
## 错误处理
- 后台总览读取失败时展示一张明确的恢复卡,提供重试按钮。
- 风险动作失败时保留原行状态,不做乐观关闭。
- 指派负责人和 SLA 不再使用 `window.prompt`,改成右侧处理面板或弹窗表单。
- 空状态要表达下一步,例如“暂无风险,可以查看设备在线情况”,不要只写“暂无数据”。
## 测试策略
- 保留并更新 `tests/admin-refine-page.test.ts`,验证新的一级区和关键文案。
- 增加组件 source 测试,确认不再使用 `window.prompt` 做风险指派和 SLA。
- 复跑 `tests/admin-overview-route.test.ts``tests/admin-risk-actions-route.test.ts``tests/admin-skill-lifecycle-panel-source.test.ts`
- 最后跑 `npm run lint` 和相关 Node 测试。
## 分批落地
第一批直接做到可用:
1. 重构 `BossAdminApp` 外壳和一级导航。
2. 做新版驾驶舱。
3. 做风险战情室,替换 `window.prompt`
4. 账号授权和 Skill 治理先迁入新结构,并压缩视觉层级。
第二批再增强:
1. 客户详情抽屉。
2. 新建客户三步流程。
3. 风险筛选和搜索。
4. 客户健康分数和趋势。
## 自检
- 无 TBD / TODO。
- 范围聚焦 `/admin` PC 总后台,不触碰 APP。
- 没有要求新增大后端能力,优先复用现有接口。
- 关键交互从数据表改成工作台与战情室,解决“后台管理不太好”的主要问题。

View File

@@ -0,0 +1,75 @@
# YuDao 风格企业后台独立化设计
日期2026-04-30
## 背景
Boss 需要从“客户也能用的 Web 页面”升级为平台侧 To B 总后台。这个后台用于平台运营人员管理公司、老板账号、子账号、电脑节点、Skill 授权、风险告警和审计记录。现有 `/admin` 已能展示核心数据,但仍运行在 Next 主站内,信息架构不够像成熟企业后台,后续不适合承载更复杂的租户、权限和治理能力。
调研 `YunaiV/yudao-cloud` 后,结论是:不直接引入它的 Spring Cloud 微服务后端;借鉴它的租户、用户、角色、菜单、日志、工作台和独立前端思路。前端形态参考 YuDao 的 Vben/Vue 管理后台,数据仍由 Boss 现有状态账本和 Admin BFF 提供。
## 目标
第一批目标是完成企业后台独立化的可运行骨架:
- 新增独立 PC 后台工程 `apps/boss-admin-web`,使用 Vue + Vite + Ant Design Vue。
- 新增 `/api/v1/admin/backoffice` 聚合接口,输出 YuDao 风格的菜单、工作台、租户、账号、角色权限、资源授权、风险和审计数据。
- 保留现有 `/admin`,作为 Boss 主站内 fallback不和独立后台互相替代。
- 后台权限继续只允许 `highest_admin` 访问不暴露密码哈希、MFA 密钥和会话令牌。
- 新后台先复用 Boss Cookie 登录态,后续再接独立域名 `admin.boss.hyzq.net`
## 非目标
- 不引入 YuDao Java 后端、MySQL 表结构或微服务网关。
- 不在第一批替换所有现有后台 mutation 页面。
- 不重新设计 Android APP。
- 不改变当前 Boss 文件存储运行时。
## 架构
```mermaid
flowchart LR
A["Boss Admin Web\nVue + Ant Design Vue"] --> B["/api/v1/admin/backoffice\nAdmin BFF"]
B --> C["boss-state.json\n当前状态账本"]
B --> D["buildAdminOverview\n现有后台聚合"]
B --> E["BOSS_PERMISSION_TEMPLATES\n权限模板"]
F["现有 /admin\nNext fallback"] --> G["/api/v1/admin/overview"]
```
`apps/boss-admin-web` 是独立前端工程。它只消费 BFF不直接读取本地文件也不复制业务规则。`/api/v1/admin/backoffice` 是企业后台的新契约层,负责把 Boss 当前状态翻译为更稳定的后台管理模型。
## 数据模型
第一批 BFF 返回:
- `menuTree`工作台、租户管理、账号管理、角色权限、资源授权、Skill 中心、风险告警、审计日志、系统设置。
- `workbench`:总览指标、客户健康、设备健康、风险摘要。
- `tenants`:公司列表、套餐、负责人、账号数、设备数、风险数。
- `users`:账号、昵称、角色、状态、公司、最近登录。
- `roles`:内置角色和权限模板。
- `resourceGroups`:设备、项目线程和 Skill 目录。
- `audit`:风险、风险时间线和权限审计。
- `yudaoMapping`Boss 账本字段到后台概念的映射,便于后续迁移数据库或接 YuDao 风格模块。
## UI 方向
第一批 UI 只做高保真骨架,不新增业务动作:
- 左侧固定菜单,右侧工作区。
- 顶部展示当前账号、后台说明和刷新入口。
- 工作台使用指标卡、风险横幅、客户健康和节点表。
- 租户、账号、角色、资源、风险、审计分别使用独立区块或表格。
- Skill 中心聚合展示 Skill 目录、来源、设备数和治理状态,后续再接完整安装向导。
## 权限与安全
- 未登录返回 `401`
-`highest_admin` 返回 `403`
- BFF 只返回安全账号字段,不返回 `passwordHash``mfaSecret``authSessions` 或任何 session token。
- 所有返回头使用 `private, no-store`,避免后台数据被缓存。
## 验证
- 新增 BFF 路由测试,验证鉴权、菜单结构、数据聚合和敏感字段过滤。
- 新增独立前端源代码测试验证工程骨架、API 契约、核心页面模块和根工程隔离。
-`npm run lint``npm run build`,确认不会破坏现有 Next 主站。