ソースを参照

统一部署文档与更新提示并完善 Docker 安装

LSamien 1 ヶ月 前
親
コミット
97677acdd3

+ 21 - 29
.dockerignore

@@ -1,30 +1,22 @@
-.git
-.gitignore
-.codegraph
-.DS_Store
+# Only send the inputs consumed by Dockerfile to the builder.
+**
+!package.json
+!package-lock.json
+!release.json
+!tsconfig.json
+!tsconfig.client.json
+!tsconfig.client.build.json
+!tsconfig.server.json
+!vite.config.ts
+!index.html
+!public/
+!public/**
+!scripts/
+!scripts/**
+!src/
+!src/**
 
-node_modules
-dist
-dist-server
-coverage
-playwright-report
-test-results
-
-.env
-.env.*
-docker.env
-*.log
-*.pem
-*.key
-
-.hermes-yaoyao
-# The runtime only needs the published Dashboard plugin as an offline install
-# payload. Keep all other plugin sources out of the image context.
-hermes-plugins/*
-!hermes-plugins/yaoyao
-hermes-plugins/yaoyao/*
-!hermes-plugins/yaoyao/plugin.yaml
-!hermes-plugins/yaoyao/dashboard
-!hermes-plugins/yaoyao/dashboard/**
-docs
-tests
+**/.DS_Store
+**/*.log
+**/*.pem
+**/*.key

+ 19 - 6
README.md

@@ -2,7 +2,7 @@
 
 当前发布版本:**v0.3.29**,配套 iOS **1.3(188)**。详见 [发布说明](docs/releases/v0.3.29.md)。
 
-夭夭 Web 为网页和 iOS 提供统一的 Agent、群聊、文件库及语音配置服务。Hermes 通过标准 9119 HTTP/WebSocket 接口执行任务;无需安装 Yaoyao 插件。
+夭夭 Web 为网页和 iOS 提供统一的 Agent、群聊、文件库及语音配置服务。Hermes 通过标准 9119 HTTP/WebSocket 接口执行任务。
 
 ## 聊天与 Agent
 
@@ -30,19 +30,32 @@ npm start
 HERMES_YAOYAO_UPSTREAM=http://服务器:9119 npm start
 ```
 
-Web 数据默认保存在 `~/.hermes-yaoyao`,可用 `HERMES_YAOYAO_HOME` 指定。备份应包含整个数据目录及加密密钥。Docker 使用 `/var/lib/hermes-yaoyao` 持久化卷,不需要 Python、Hermes 文件系统挂载或插件安装载荷。
+Web 数据默认保存在 `~/.hermes-yaoyao`,可用 `HERMES_YAOYAO_HOME` 指定。备份应包含整个数据目录及加密密钥。
 
 由 Web 或 iOS 创建的普通聊天会按登录用户、Profile 和 Session ID 在 `chat-cache.sqlite3` 中登记所有权并持久化;后续续聊与列表展示以这份服务端登记为准,不再单独依赖 Hermes 的 `source` 标记。Web 的只读历史记录不进入该数据库,继续按需读取 9119。可通过 `HERMES_YAOYAO_CHAT_CACHE_MODE=upstream-only|shadow|prefer-local` 切换策略,默认 `prefer-local`。
 
+## Docker 安装
+
+准备 Docker Engine 或 Docker Desktop,以及容器可访问的 Hermes 9119 服务。在仓库目录执行:
+
+```sh
+cp docker.env.example docker.env
+# 按实际环境修改 docker.env 中的上游地址和发布地址
+docker compose --env-file docker.env config --quiet
+docker compose --env-file docker.env up -d --build
+```
+
+默认访问 `http://127.0.0.1:15300`。应用数据保存在 `yaoyao-data` 命名卷,容器内路径为 `/var/lib/hermes-yaoyao`。首次打开页面创建管理员账号,并在系统设置中配置 Hermes 连接。
+
+宿主机连接、局域网访问、验证及升级步骤见 [Docker 部署说明](docs/docker-install.md)。
+
 ## iOS
 
 iOS 统一连接 Web 地址,通过设置中的手机登录二维码或账号密码登录。不能再直接填写 9119 地址;旧 15300 Web 账号和本机聊天缓存继续保留。
 
 ## 数据与升级
 
-新体系从空数据开始,不导入旧插件的团队、话题、文件或配置。旧 Hermes 数据及已安装插件原地留存,Web 不再访问、升级或卸载它们。发布清单只记录 Web 版本,Web 自身升级功能保留。首次切换请整体替换 Web 部署并配套更新 iOS。
-
-Kanban 仍是可选的独立功能,其插件不在本次迁移范围内。
+发布版本由 `release.json` 记录。macOS 本机服务支持在系统设置中升级 Web 或回滚到上一个版本;其他源码部署更新代码、重新构建并重启服务,Docker 部署通过重新构建镜像并重建容器更新。升级前备份 Web 数据目录,客户端版本要求见对应发布说明。
 
 ## 开发验证
 
@@ -52,7 +65,7 @@ npm test
 npm run build
 ```
 
-新体系契约见 [聊天接口与运行模型](docs/workspace-chat.md),安装步骤见 [部署说明](docs/agent-install.md)。
+接口契约见 [聊天接口与运行模型](docs/workspace-chat.md),安装步骤见 [部署说明](docs/agent-install.md)。
 
 ## 许可证
 

+ 2 - 2
bin/hermes-yaoyao-updater.mjs

@@ -274,7 +274,7 @@ async function runUpdate(jobPath, job) {
       finalRoot,
       commit,
     })
-    updateJob(jobPath, { state: 'succeeded', message: `已升级 Web ${target.webVersion};插件由 9119 管理` })
+    updateJob(jobPath, { state: 'succeeded', message: `已升级 Web ${target.webVersion}` })
   } catch (error) {
     const message = error instanceof Error ? error.message : String(error)
     if (transitioned) {
@@ -318,7 +318,7 @@ async function runRollback(jobPath, job) {
   })
   await verifyRuntime()
   rmSync(recordPath, { force: true })
-  updateJob(jobPath, { state: 'rolled_back', message: '已回滚 Web 服务;插件继续由 9119 管理' })
+  updateJob(jobPath, { state: 'rolled_back', message: '已回滚 Web 服务' })
 }
 
 async function main() {

+ 3 - 3
docker.env.example

@@ -2,12 +2,12 @@
 HERMES_YAOYAO_BIND_ADDRESS=127.0.0.1
 HERMES_YAOYAO_PUBLISHED_PORT=15300
 
-# 9119 由项目外部的 Hermes Dashboard 提供,Compose 不会创建、启动或停止它。
+# 部署步骤见 docs/docker-install.md;使用 docker compose --env-file docker.env 启动。
+# 填写容器可访问的 Hermes Dashboard/Gateway 地址。
 # Docker Desktop 可用这个地址访问宿主机;Linux 上的 9119 还必须监听容器可达的宿主机地址。
 HERMES_YAOYAO_UPSTREAM=http://host.docker.internal:9119
 HERMES_YAOYAO_CHAT_CACHE_MODE=prefer-local
-# HERMES_YAOYAO_UPSTREAM_USERNAME=yaoyao-service
-# HERMES_YAOYAO_UPSTREAM_PASSWORD_FILE=/run/secrets/hermes_dashboard_password
+# 首次登录后在 Web 系统设置中保存 Hermes 连接凭据。
 
 # 使用域名访问时填写域名,多个值以英文逗号分隔;localhost 和私网 IP 无需填写。
 HERMES_YAOYAO_ALLOWED_HOSTS=

+ 16 - 9
docs/agent-install.md

@@ -2,9 +2,8 @@
 
 ## 前提
 
-- Node.js 24。
+- 源码安装需要 Node.js 24;容器安装需要 Docker Engine 或 Docker Desktop。
 - 可访问的 Hermes Dashboard/Gateway(通常为 9119),支持会话创建、恢复、提示词提交、附件及审批 RPC。
-- 不需要 Yaoyao 插件,不会修改外部 Hermes 的插件目录或重启外部 Hermes。
 
 ## 源码安装
 
@@ -14,22 +13,30 @@
 
 首次打开 Web 时创建管理员账号和至少 8 位的密码。服务不会生成固定的默认账号或密码;iOS 使用 Web 账号或手机登录二维码。
 
-## 局域网与容器
+## 局域网
 
 局域网部署可设置 `HERMES_YAOYAO_HOST=0.0.0.0` 和 `HERMES_YAOYAO_ALLOW_INSECURE_LAN=1`,并在 `HERMES_YAOYAO_ALLOWED_HOSTS` 中列入访问地址。公网部署配置 TLS。
 
-容器保持 `HERMES_YAOYAO_SUPERVISE_DASHBOARD=0`,使用外部 Hermes 上游。数据目录 `/var/lib/hermes-yaoyao` 必须持久化;无需挂载 Hermes 文件系统或 Docker socket。
+## Docker 安装
+
+复制 `docker.env.example` 为 `docker.env`,填写容器可访问的 `HERMES_YAOYAO_UPSTREAM`,然后执行:
+
+```sh
+docker compose --env-file docker.env config --quiet
+docker compose --env-file docker.env up -d --build
+```
+
+Compose 将 Web 的 15300 端口发布到宿主机,使用 `yaoyao-data` 命名卷保存 `/var/lib/hermes-yaoyao`。宿主机连接、访问配置、备份及升级见 [Docker 部署说明](docker-install.md)。
 
 ## 验收
 
 - `/healthz` 检查 Web 自身;`/readyz` 检查 Hermes 上游。
-- 登录后 `/api/app/capabilities` 声明新聊天功能。
-- 创建角色、发送消息、上传并下载附件、创建固定成员群聊。
+- 登录后 `/api/app/capabilities` 声明聊天功能。
+- 创建角色、发送消息、上传并下载附件、创建群聊并管理成员。
 - 用同一账号在 iOS 和 Web 查看相同历史;另一账号看不到这些聊天。
-- 全过程不应访问 `/api/plugins/yaoyao/`、插件安装或插件升级接口。
 
 ## 数据和发布
 
-备份整个 `HERMES_YAOYAO_HOME`,包含 SQLite、上传与归档文件、用户凭据和密钥。正常的数据库持久化不依赖旧插件存储维护工具。
+备份整个 `HERMES_YAOYAO_HOME`,包含 SQLite、上传与归档文件、用户凭据和密钥。运行中的 SQLite 使用数据库备份工具,或停止 Web 后复制整个目录。
 
-本次升级不迁移旧数据。旧插件及数据文件保留在原处,不自动卸载或删除。首次切换整体部署新 Web 和 iOS;此后只升级 Web 自身版本。
+macOS 本机服务可通过系统设置中的“更新与回滚”管理版本。其他源码部署更新代码后执行 `npm ci`、`npm run build` 并重启 Web。Docker 部署更新源码后重新构建镜像并重建容器,继续使用已有数据卷。配套客户端要求见对应发布说明。

+ 79 - 0
docs/docker-install.md

@@ -0,0 +1,79 @@
+# Docker 部署夭夭 Web
+
+## 准备
+
+- 安装 Docker Engine 和 Compose,或 Docker Desktop。
+- 准备容器可访问的 Hermes Dashboard/Gateway,通常使用 9119 端口。
+- 获取本项目源码,在仓库目录执行后续命令。
+
+## 配置与启动
+
+```sh
+cp docker.env.example docker.env
+```
+
+编辑 `docker.env`:
+
+| 配置 | 用途 |
+| --- | --- |
+| `HERMES_YAOYAO_UPSTREAM` | Hermes 上游地址,默认 `http://host.docker.internal:9119` |
+| `HERMES_YAOYAO_BIND_ADDRESS` | Web 的宿主机发布地址,默认 `127.0.0.1`;局域网访问可设为 `0.0.0.0` |
+| `HERMES_YAOYAO_PUBLISHED_PORT` | 宿主机 Web 端口,默认 `15300` |
+| `HERMES_YAOYAO_ALLOWED_HOSTS` | 使用域名访问时填写对应域名,多个值用英文逗号分隔 |
+| `HERMES_YAOYAO_CHAT_CACHE_MODE` | 普通聊天缓存策略,默认 `prefer-local` |
+
+Docker Desktop 可通过 `host.docker.internal` 访问宿主机。Linux 上 Compose 将该名称映射到宿主机网关;Hermes 需要监听容器可访问的宿主机地址。远程 Hermes 直接填写其可访问地址。
+
+```sh
+docker compose --env-file docker.env config --quiet
+docker compose --env-file docker.env up -d --build
+docker compose --env-file docker.env ps
+```
+
+默认打开 `http://127.0.0.1:15300`。局域网设备使用宿主机 IP 和发布端口访问。首次打开页面创建管理员账号,再到系统设置配置 Hermes 连接凭据。通过域名提供公网访问时,在反向代理上配置 HTTPS,并将域名加入允许列表。
+
+## 验证
+
+以下命令使用默认发布端口;修改端口后同步调整 URL:
+
+```sh
+curl --fail http://127.0.0.1:15300/healthz
+curl --fail http://127.0.0.1:15300/readyz
+docker compose --env-file docker.env logs --tail=100 web
+```
+
+`healthz` 检查 Web 服务,`readyz` 检查 Hermes 上游。若上游不可达,检查 `HERMES_YAOYAO_UPSTREAM`、Hermes 监听地址及网络连通性;若需要认证,在 Web 系统设置中保存连接凭据。
+
+登录后创建会话、收发消息、上传并下载附件,验证实际使用流程。
+
+## 数据与备份
+
+Compose 使用 `yaoyao-data` 命名卷,挂载到 `/var/lib/hermes-yaoyao`。账号、SQLite 数据库、聊天缓存、文件及密钥随数据卷持久保存。
+
+备份时先停止 Web,然后复制完整数据目录,再启动服务:
+
+```sh
+mkdir -p backups
+docker compose --env-file docker.env stop web
+docker compose --env-file docker.env cp web:/var/lib/hermes-yaoyao/. ./backups/
+docker compose --env-file docker.env start web
+```
+
+为每次备份使用独立目录,并保留文件权限。恢复时将完整备份放回数据卷,确认容器内 `node` 用户可以读写后再启动服务。
+
+## 升级与停止
+
+更新仓库源码后重新构建和启动:
+
+```sh
+docker compose --env-file docker.env up -d --build
+docker compose --env-file docker.env ps
+```
+
+新容器继续使用已有的命名卷。升级前完成备份,并按发布说明更新配套客户端。
+
+```sh
+docker compose --env-file docker.env down
+```
+
+上述停止命令保留数据卷;`down --volumes` 会删除数据,应仅在明确清空部署时使用。

+ 2 - 4
docs/releases/v0.3.0.md

@@ -2,7 +2,7 @@
 
 团队、角色和聊天记录现在由 Web 服务直接保存和运行。基于已有 Hermes Profile 创建角色并设置提示词,角色单聊与群聊显示在同一列表;群成员创建后固定,不再提供独立话题列表。
 
-文件归档、语音配置、上下文快照、节点管理与团队推送迁入 Web。移除 Yaoyao 插件及其安装、版本检查和升级流程。原生 Hermes 对话保留独立入口。
+文件归档、语音配置、上下文快照、节点管理与团队推送由 Web 提供。原生 Hermes 对话保留独立入口。
 
 ## 配套客户端
 
@@ -10,9 +10,7 @@
 
 ## 升级方式
 
-这是不兼容旧接口的版本。首次切换请整体替换 Web 部署,不通过旧版插件升级流程更新。新体系从空数据库开始,旧团队、话题和插件配置不自动导入,旧文件原地保留。
-
-Web 上游仍为标准 Hermes 9119 服务。无需安装 Yaoyao 插件;Kanban 仍是独立可选功能。
+首次切换请整体部署 Web v0.3.0,并更新配套 iOS。应用数据保存在 Web 数据目录中,上游使用标准 Hermes 9119 服务。
 
 ## 验证
 

+ 1 - 1
docs/releases/v0.3.15.md

@@ -7,6 +7,6 @@ Web 与配套 iOS 1.3(176)的内置头像完整采用 OpenMausBot 的轮廓
 - 旧内置头像一次性归一为绿色 `#00C875`、圆形、默认表情;旧照片保留,默认圆角。已保存的 v2 设置不会再次重置。基础 Agent 元数据通过现有 Profile 读取与保存接口归一化。
 - 群头像继续根据实际成员资料合成;执行、排队、待确认与完成/失败/新消息状态驱动对应头像动画。
 - 小尺寸空闲列表头像静止;活动头像、聊天头部与设置预览支持动态。Web 支持指针跟随。离屏、后台和减少动态效果时暂停。
-- 新增版本化头像描述,沿用原保存接口、图片存储、鉴权和大小限制;不需要 OpenMausBot 服务或插件升级。
+- 新增版本化头像描述,沿用原保存接口、图片存储、鉴权和大小限制。
 
 来源、许可与移植说明见 [THIRD_PARTY_NOTICES.md](../../THIRD_PARTY_NOTICES.md)。验证方法见 [头像验收记录](../verification/avatar-v2.md)。

+ 1 - 1
docs/releases/v0.3.16.md

@@ -7,4 +7,4 @@
 - 设置中心的账号页显示登录账号;Agent 身份和模型页显示当前正在设置的 Profile。
 - 登录账号暂未提供自定义头像字段,使用统一的绿色圆形默认头像;各模式显示一致。
 
-配套 iOS 继续为 1.3(176),无需插件升级。
+配套 iOS 继续为 1.3(176)。

+ 1 - 1
docs/releases/v0.3.17.md

@@ -6,4 +6,4 @@
 - 用户名变化时,字母与颜色会随用户名重新计算,不再使用固定的 OpenMausBot 默认头像。
 - Agent、单聊和群聊头像保持 OpenMausBot 头像体系。
 
-配套 iOS 继续为 1.3(176),无需插件升级。
+配套 iOS 继续为 1.3(176)。

+ 1 - 1
docs/releases/v0.3.18.md

@@ -7,4 +7,4 @@
 - 新建 Agent 未主动选择头像时,由创建流程生成并保存随机 v2 内置头像;颜色、形状/造型和基础表情均参与随机。
 - Web、iOS 创建界面进入时即可看到本次随机结果;服务端同时兜底处理未携带头像的客户端请求。
 
-配套 iOS 为 1.3(177),无需插件升级。
+配套 iOS 为 1.3(177)。

+ 1 - 1
docs/releases/v0.3.19.md

@@ -7,4 +7,4 @@
 - 随机结果写入 Agent 记录及对应单聊快照;迁移完成后记录独立标记,重启不会再次变化。
 - 新建 Agent 继续使用 v0.3.18 的创建时随机头像规则。
 
-配套 iOS 继续为 1.3(177),无需插件升级。
+配套 iOS 继续为 1.3(177)。

+ 1 - 1
docs/releases/v0.3.20.md

@@ -9,4 +9,4 @@
 - Bot 模式继续使用 8800 自有 Agent/群聊,不增加历史记录入口。
 - Profile 名称和头像读取重新可用,不再回退为 `default` 和绿色默认头像。
 
-配套 iOS 继续为 1.3(177),无需插件升级。
+配套 iOS 继续为 1.3(177)。

+ 1 - 1
docs/releases/v0.3.21.md

@@ -5,4 +5,4 @@
 - 历史记录未选中会话时显示“选择历史记录”,不再出现聊天页的“聊点什么”。
 - 延续 v0.3.20 的独立聊天、只读历史和 Bot 模式边界。
 
-配套 iOS 继续为 1.3(177),无需插件升级。
+配套 iOS 继续为 1.3(177)。

+ 1 - 1
docs/releases/v0.3.4.md

@@ -10,7 +10,7 @@
 - 头像支持圆形、椭圆、圆角方形、胶囊、小三角、六边形、云朵和水滴,提供 14 种颜色、随机外形、重置与图片上传。
 - 扩展头像在 iOS、Web 和群聊组合中同步保存、渲染;会话名称旁不再显示额外的 Agent 字样。
 
-固定群成员、独立角色规则、Web 服务所有权保持不变,不需要 Yaoyao 插件。
+固定群成员、独立角色规则、Web 服务所有权保持不变。
 
 配套 iOS 1.3(169)。
 

+ 1 - 1
docs/releases/v0.3.5.md

@@ -8,7 +8,7 @@
 - 用户和 Agent 都支持在中文句中直接 @ 成员,例如“请@瑶儿继续”;按最长成员名称匹配,排除邮件、链接、代码和引用中的提及。
 - 保持原有聊天页面布局,群成员仍然固定。
 
-配套 iOS 1.3(170)。本版本只更新 Web 服务,无需 Yaoyao 插件。
+配套 iOS 1.3(170)。本版本更新 Web 服务。
 
 ## 验证
 

+ 1 - 1
docs/verification/avatar-v2.md

@@ -38,4 +38,4 @@ node scripts/seed-avatar-fixture.mjs
 
 本次 Web 全量单元/服务测试 506 项通过,类型检查与生产构建通过;iOS 相关单元测试 62 项通过。当前 Bot 模式完整浏览器流程、28 组头像对照与两条 iOS UI 流程通过。
 
-通用旧浏览器套件仍包含已移除的团队/主题入口及插件升级状态文案;本次运行在这些旧断言上失败(7 条),停止后其余 30 条未执行,1 条中断。没有恢复旧入口以满足旧断言,也不将这次通用套件记为全量通过。当前 Bot 流程由 `playwright.workspace.config.ts` 的实际新建、设置、群聊与持久化流程验证;普通聊天与媒体另行回归。
+通用旧浏览器套件包含过时的页面与状态断言;本次运行失败 7 条,停止后其余 30 条未执行,1 条中断,不将这次通用套件记为全量通过。当前 Bot 流程由 `playwright.workspace.config.ts` 的实际新建、设置、群聊与持久化流程验证;普通聊天与媒体另行回归。

+ 3 - 4
docs/workspace-acceptance.md

@@ -11,7 +11,7 @@
 
 ## 首次迁移记录
 
-验收日期:2026-09-03。涉及 `hermes-yaoyao` 与 `hermes-mobile`,旧插件数据未导入或删除。
+验收日期:2026-09-03。涉及 `hermes-yaoyao` 与 `hermes-mobile`。
 
 ## 自动验证
 
@@ -23,13 +23,13 @@
 
 服务端回归覆盖用户隔离、固定成员、规则更新、执行中改名、管理员调度、轮数限制、审批、澄清、重复提交、断线不确定状态、按历史恢复且不重发、失效节点的可见失败、附件归档、安全预览、语音密钥和上下文快照。
 
-浏览器用例覆盖创建两个角色、创建群聊、三项混合列表、不可编辑成员、角色单聊隔离、群聊发送、第二页面同步、归档恢复、文件来源返回新聊天,以及全过程不访问 Yaoyao 插件接口。
+浏览器用例覆盖创建两个角色、创建群聊、三项混合列表、不可编辑成员、角色单聊隔离、群聊发送、第二页面同步、归档恢复及文件来源返回新聊天。
 
 iOS 新协议用例覆盖应用写入的 Origin/CSRF、跨账号令牌刷新、拒绝直连 9119、新聊天通知路由、归档文件呈现、语音时间戳,以及上游无 Profile 时仍可登录 Web。
 
 ## 界面联调
 
-使用独立 Web 数据目录和未提供插件接口的标准 Gateway 测试节点;未使用用户当前服务的数据。
+使用独立 Web 数据目录和标准 Gateway 测试节点;未使用用户当前服务的数据。
 
 已在浏览器和独立的 `Yaoyao Workspace QA` 模拟器中核对:同一账号显示相同的两个角色及一个群聊;iOS 发出的群聊消息、回复及历史在 Web 中可见。浏览器确认已建群的成员选择框禁用,服务端也拒绝成员变更。
 
@@ -49,4 +49,3 @@ iOS:使用 `YaoYaoAI` scheme 和可用模拟器,运行 `-only-testing:YaoYao
 - 2026-09-03:完整 Web 测试 85 个文件、460 项通过;发布清单校验、类型检查和生产构建通过。
 - `npx playwright test -c playwright.workspace.config.ts`:当前聊天完整端到端流程通过。
 - 本次包含原有聊天组件恢复、HTTP 发送修复、置顶修复、动态成员头像、头像状态联动、列表消息时间和扩展头像。
-- 旧插件与旧话题协议已退役,不将其浏览器场景作为当前聊天发布条件。

+ 0 - 4
docs/workspace-chat.md

@@ -37,10 +37,6 @@
 
 断开客户端不取消运行。提交丢失确认、连接中断或服务重启时,不自动重发可能已执行的请求。核对上游会话及带运行标识的历史后继续;无法核对时显示不确定状态并要求显式停止或核对。
 
-## 退出旧插件
-
-旧 Yaoyao API 返回 410;没有安装、reconcile、版本要求或升级流程。新数据不导入旧插件目录。旧插件数据原地保留。原生对话和可选 Kanban 继续使用各自的独立接口。
-
 ## 15300 子节点
 
 Bot 模式的远程节点由当前主服务器按用户保存。通过 `POST /api/app/nodes`

+ 2 - 2
docs/workspace-orchestration-parity.md

@@ -1,6 +1,6 @@
 # 团队协作迁移验收清单
 
-对照迁移前 v0.2.31 的 `group_store.py`、`group_orchestrator.py` 与主持流程契约测试,将调度行为迁入 Web。保持当前创建的 Agent、统一聊天列表、可变群成员和管理员保护,不恢复旧主题接口、插件依赖或名称兼容层。
+Web 负责团队执行调度,使用当前创建的 Agent、统一聊天列表、可变群成员和管理员保护。以下条目说明协作行为及验收范围。
 
 - 管理员模式:所有用户消息先交管理员;管理员可串行委派或并行委派一批成员,整批终结后只复核一次。
 - 成员成功、失败或中断均形成可复核结果;管理员复核不增加轮数。
@@ -20,4 +20,4 @@
 
 iOS 的 `testTeamWorkspaceStaysInsideOriginalDrawer` 验证原有页面结构、群内成员管理、模板分工、执行中发送并排队、完成后继续回复与不限轮数设置。成员并发头像状态另有 `WorkspaceChatTests` 回归。
 
-验收使用独立标准 Hermes 协议测试服务,不依赖旧插件,不修改生产用户聊天记录。实际远端模型和那台机器的部署状态需以其运行日志为准。
+验收使用独立标准 Hermes 协议测试服务,不修改生产用户聊天记录。实际远端模型和那台机器的部署状态需以其运行日志为准。

+ 1 - 1
src/client/components/app/DuplexVoicePanel.vue

@@ -96,7 +96,7 @@ onMounted(() => { void load() })
   <section class="voice-panel" aria-label="双流语音">
     <div class="voice-heading"><div><h3>yaoyao 双流语音</h3><p>这是整个 yaoyao 安装共享的全局设置,不随当前 Agent 切换。</p></div><span>全局</span></div>
     <p v-if="error" class="voice-error" role="alert">{{ error }}</p><p v-else-if="notice" class="voice-notice" role="status">{{ notice }}</p>
-    <p v-if="loading" class="voice-empty">正在读取 yaoyao 插件设置…</p>
+    <p v-if="loading" class="voice-empty">正在读取语音设置…</p>
     <form v-else :aria-busy="busy" @submit.prevent="save">
       <label>API Key<input v-model="apiKey" type="password" :disabled="busy" :placeholder="hasApiKey ? '已保存;留空保持不变' : '输入双流语音 API Key'" autocomplete="new-password" /></label>
       <div class="voice-list-heading"><strong>音色列表</strong><button type="button" :disabled="busy || voices.length >= 100" @click="addVoice"><AppIcon name="plus" :size="13" />增加音色</button></div>

+ 3 - 3
src/client/components/app/SystemUpdateDialog.vue

@@ -60,7 +60,7 @@ async function poll(next: UpdateJob) {
 
 async function applyUpdate() {
   const target = status.value?.latest
-  if (!target || !window.confirm(`仅升级 Web 到 ${target.webVersion}?无需连接 9119,不会更新插件。`)) return
+  if (!target || !window.confirm(`将 Web 升级到 ${target.webVersion}?`)) return
   busy.value = true
   error.value = ''
   try {
@@ -73,7 +73,7 @@ async function applyUpdate() {
 }
 
 async function rollback() {
-  if (!window.confirm('仅回滚到上一次 Web 版本?无需连接 9119,插件保持不变。')) return
+  if (!window.confirm('回滚到上一个 Web 版本?')) return
   busy.value = true
   error.value = ''
   try {
@@ -110,7 +110,7 @@ onBeforeUnmount(stopPolling)
             <button class="icon-button" type="button" aria-label="关闭系统更新" :disabled="!!active" @click="emit('close')"><AppIcon name="close" /></button>
           </header>
 
-          <p class="system-update-intro">Web 服务独立升级与回滚,9119 离线或认证失败也不影响。这里只检查 Web 发布源,不检测或更新插件;插件由 9119 独立管理。</p>
+          <p class="system-update-intro">查看 Web 版本、检查更新或回滚到上一个版本。更新完成后刷新页面即可使用新版本。</p>
           <p v-if="error" class="system-update-error"><AppIcon name="alert" :size="15" />{{ error }}</p>
 
           <section v-if="status" class="version-grid">

+ 3 - 3
src/client/components/app/SystemUpdatePanel.vue

@@ -81,7 +81,7 @@ async function loadAndResume(token: number) {
 
 async function applyUpdate() {
   const target = status.value?.latest
-  if (!target || !window.confirm(`仅升级 Web 到 ${target.webVersion}?无需连接 9119,不会更新插件。`)) return
+  if (!target || !window.confirm(`将 Web 升级到 ${target.webVersion}?`)) return
   const token = lifecycleToken
   operationStarting.value = true
   busy.value = true
@@ -102,7 +102,7 @@ async function applyUpdate() {
 }
 
 async function rollback() {
-  if (!window.confirm('仅回滚到上一次 Web 版本?无需连接 9119,插件保持不变。')) return
+  if (!window.confirm('回滚到上一个 Web 版本?')) return
   const token = lifecycleToken
   operationStarting.value = true
   busy.value = true
@@ -144,7 +144,7 @@ onBeforeUnmount(() => { lifecycleToken += 1; operationStarting.value = false; st
 
 <template>
   <section class="system-update-panel" aria-label="更新与回滚">
-    <p class="system-update-intro">Web 服务独立升级与回滚,9119 离线或认证失败也不影响。这里只检查 Web 发布源,不检测或更新插件;插件由 9119 独立管理。</p>
+    <p class="system-update-intro">查看 Web 版本、检查更新或回滚到上一个版本。更新完成后刷新页面即可使用新版本。</p>
     <p v-if="error" class="system-update-error" role="alert"><AppIcon name="alert" :size="16" />{{ error }}</p>
 
     <section v-if="status" class="version-grid" aria-label="版本信息">

+ 1 - 1
src/client/views/GroupsView.vue

@@ -821,7 +821,7 @@ watch(() => auth.activeProfile?.name, profile => { if (profile) restoreShowThink
     </template>
 
     <div v-if="groups.availability === 'unsupported' || groups.availability === 'unavailable'" class="groups-unavailable">
-      <EmptyState icon="alert" :title="groups.availability === 'unsupported' ? '团队协议版本不兼容' : '团队服务暂不可用'" :description="groups.error || `请确认 9119 已安装 YaoYao 团队协议 ${SUPPORTED_GROUP_PROTOCOL_VERSION_LABEL} 插件。`" action-label="重新检查" @action="groups.refresh" />
+      <EmptyState icon="alert" :title="groups.availability === 'unsupported' ? '团队协议版本不兼容' : '团队服务暂不可用'" :description="groups.error || '请检查团队服务连接后重试。'" action-label="重新检查" @action="groups.refresh" />
     </div>
     <div v-else class="groups-workspace">
       <MessageTimeline

+ 2 - 2
tests/client/systemUpdatePanel.test.ts

@@ -69,13 +69,13 @@ describe('SystemUpdatePanel', () => {
     const confirm = vi.spyOn(window, 'confirm').mockReturnValue(true)
     const wrapper = mount(SystemUpdatePanel, { global: { stubs: { AppIcon: true } } })
     await flushPromises()
-    expect(wrapper.text()).toContain('9119 离线或认证失败也不影响')
+    expect(wrapper.text()).toContain('查看 Web 版本、检查更新或回滚到上一个版本')
     expect(wrapper.text()).not.toContain('当前插件')
     expect(wrapper.find('.version-warning').exists()).toBe(false)
     const apply = wrapper.find<HTMLButtonElement>('.solid-button')
     expect(apply.element.disabled).toBe(false)
     await apply.trigger('click'); await flushPromises()
-    expect(confirm).toHaveBeenCalledWith('仅升级 Web 到 0.3.0?无需连接 9119,不会更新插件。')
+    expect(confirm).toHaveBeenCalledWith('将 Web 升级到 0.3.0?')
     expect(api.applySystemUpdate).toHaveBeenCalledWith('0.3.0')
     expect(wrapper.text()).toContain('更新完成')
     wrapper.unmount()