Procházet zdrojové kódy

发布 v0.2.5 并修复话题刷新恢复

LSamien před 2 měsíci
rodič
revize
866be09cfa

+ 2 - 2
README.md

@@ -9,7 +9,7 @@
 插件安装接口安装。默认源为
 `https://git.samien.cn/samien/hermes-yaoyao.git#hermes-plugins/yaoyao`。
 
-当前发布版本:**Git `v0.2.1` / 夭夭 Web `0.2.1` / Hermes Dashboard 插件 `1.7.1`**。版本组合由仓库根目录的 `release.json` 唯一声明,并由 `npm run release:verify` 校验。
+当前发布版本:**Git `v0.2.5` / 夭夭 Web `0.2.5` / Hermes Dashboard 插件 `1.7.2`**。版本组合由仓库根目录的 `release.json` 唯一声明,并由 `npm run release:verify` 校验。
 
 需要由自动化 Agent 部署或升级时,请直接使用 [Agent 安装手册](docs/agent-install.md)。其中包含固定版本校验、备份、同步、单一 Dashboard 重载与验证步骤。
 
@@ -153,7 +153,7 @@ npm run dev
 
 ## 手机扫码与跨节点 Agent
 
-插件 `1.7.1` 与当前 Web 服务共同提供 Hermes 节点配对。每台参与设备都需要安装相同版本的夭夭插件并运行 Web 服务:
+插件 `1.7.2` 与当前 Web 服务共同提供 Hermes 节点配对。每台参与设备都需要安装相同版本的夭夭插件并运行 Web 服务:
 
 1. 在目标 Hermes 的夭夭 Web 左下角打开“手机与节点”。
 2. 输入一次 Hermes 密码并生成两分钟有效、只能使用一次的二维码;密码只用于创建独立设备会话,不会保存。

+ 8 - 8
docs/agent-install.md

@@ -6,9 +6,9 @@
 
 | 项目 | 版本 | 校验位置 |
 | --- | --- | --- |
-| Git 发布标签 | `v0.2.1` | `release.json` 的 `gitTag` 与 `git describe --tags --exact-match HEAD` |
-| 夭夭 Web | `0.2.1` | `release.json` 与 `package.json` 的 `version` |
-| Hermes Dashboard 插件 | `1.7.1` | `hermes-plugins/yaoyao/dashboard/manifest.json` 的 `version` |
+| Git 发布标签 | `v0.2.5` | `release.json` 的 `gitTag` 与 `git describe --tags --exact-match HEAD` |
+| 夭夭 Web | `0.2.5` | `release.json` 与 `package.json` 的 `version` |
+| Hermes Dashboard 插件 | `1.7.2` | `hermes-plugins/yaoyao/dashboard/manifest.json` 的 `version` |
 
 以下步骤以仓库根目录为工作目录。不要使用浮动分支替代发布标签。
 
@@ -81,13 +81,13 @@ curl --fail --silent --show-error http://127.0.0.1:9119/api/auth/providers
 ## 1. 获取并校验指定发布版本
 
 ```bash
-RELEASE_VERSION=v0.2.1
+RELEASE_VERSION=v0.2.5
 git fetch --tags
 git checkout "$RELEASE_VERSION"
 
 test "$(git describe --tags --exact-match HEAD)" = "$RELEASE_VERSION"
-test "$(node -p \"require('./package.json').version\")" = "0.2.1"
-test "$(node -e \"console.log(require('./hermes-plugins/yaoyao/dashboard/manifest.json').version)\")" = "1.7.1"
+test "$(node -p \"require('./package.json').version\")" = "0.2.5"
+test "$(node -e \"console.log(require('./hermes-plugins/yaoyao/dashboard/manifest.json').version)\")" = "1.7.2"
 npm run release:verify
 ```
 
@@ -117,7 +117,7 @@ test -f "$PLUGIN_DIR/manifest.json"
 test -f "$PLUGIN_DIR/plugin_api.py"
 test -f "$PLUGIN_DIR/group_plugin_api.py"
 test -f "$PLUGIN_DIR/dist/index.js"
-test "$(node -e \"console.log(require(process.argv[1]).version)\" "$PLUGIN_DIR/manifest.json")" = "1.7.1"
+test "$(node -e \"console.log(require(process.argv[1]).version)\" "$PLUGIN_DIR/manifest.json")" = "1.7.2"
 ```
 
 `rsync --delete` 的范围严格限于 `$PLUGIN_DIR`,不会删除其他 Hermes 插件或用户数据。若目标目录已有额外的本机定制文件,应先将其移出目录或改用不带 `--delete` 的同步命令。
@@ -227,7 +227,7 @@ launchctl load -w ~/Library/LaunchAgents/com.samien.hermes-yaoyao.plist
 
 ## 7. 通过受管服务进行配套升级
 
-首次按第 6 步安装 Web `0.2.1` 后,可在左下角 Agent 菜单打开“系统更新”。
+首次按第 6 步安装 Web `0.2.5` 后,可在左下角 Agent 菜单打开“系统更新”。
 检查更新只读取固定的 `HERMES_YAOYAO_RELEASE_SOURCE`,并锁定最新 `vX.Y.Z`
 标签解析到的 Git 提交;执行升级前仍会检查插件持久目录是否安全。
 

+ 1 - 1
hermes-plugins/yaoyao/dashboard/manifest.json

@@ -3,7 +3,7 @@
   "label": "夭夭",
   "description": "文件归档、Agent 名称、语音设置与多设备群聊",
   "icon": "FolderOpen",
-  "version": "1.7.1",
+  "version": "1.7.2",
   "tab": { "path": "/yaoyao-files", "position": "after:files" },
   "entry": "dist/index.js",
   "css": "dist/style.v1.4.0.css",

+ 1 - 2
hermes-plugins/yaoyao/plugin.yaml

@@ -1,5 +1,4 @@
 name: yaoyao
-version: "1.7.1"
+version: "1.7.2"
 description: "YaoYao Dashboard extension for files, Agent identity, voice, and multi-device teams"
 author: samien
-

+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "hermes-yaoyao",
-  "version": "0.2.4",
+  "version": "0.2.5",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "hermes-yaoyao",
-      "version": "0.2.4",
+      "version": "0.2.5",
       "license": "BSL-1.1",
       "dependencies": {
         "@koa/bodyparser": "^5.0.0",

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "hermes-yaoyao",
-  "version": "0.2.4",
+  "version": "0.2.5",
   "private": true,
   "license": "BSL-1.1",
   "description": "夭夭 Web:直连 Hermes 9119 的聊天、团队、文件库与产物工作台",

+ 4 - 4
release.json

@@ -1,7 +1,7 @@
 {
   "schemaVersion": 1,
-  "releaseVersion": "0.2.4",
-  "webVersion": "0.2.4",
-  "pluginVersion": "1.7.1",
-  "gitTag": "v0.2.4"
+  "releaseVersion": "0.2.5",
+  "webVersion": "0.2.5",
+  "pluginVersion": "1.7.2",
+  "gitTag": "v0.2.5"
 }

+ 12 - 2
src/client/views/GroupsView.vue

@@ -603,7 +603,10 @@ onMounted(async () => {
     const requested = typeof route.params.roomId === 'string' ? route.params.roomId : ''
     const requestedTopic = typeof route.params.topicId === 'string' ? route.params.topicId : undefined
     if (requested) {
-      try { await groups.selectRoom(requested, requestedTopic) }
+      try {
+        await groups.selectRoom(requested, requestedTopic)
+        topicListRoomId.value = requested
+      }
       catch {
         if (groups.selectedRoomId) await router.replace(groupRoute())
         return
@@ -624,8 +627,15 @@ onBeforeUnmount(() => {
 watch(() => [route.params.roomId, route.params.topicId] as const, async ([roomValue, topicValue]) => {
   const roomId = typeof roomValue === 'string' ? roomValue : ''
   const topicId = typeof topicValue === 'string' ? topicValue : undefined
+  if (!roomId) {
+    topicListRoomId.value = null
+    return
+  }
   if (roomId && (roomId !== groups.selectedRoomId || (groups.topicProtocol && topicId && topicId !== groups.selectedTopicId))) {
-    try { await groups.selectRoom(roomId, topicId) }
+    try {
+      await groups.selectRoom(roomId, topicId)
+      topicListRoomId.value = roomId
+    }
     catch { if (groups.selectedRoomId && route.fullPath !== groupRoute()) await router.replace(groupRoute()) }
   }
 })

+ 19 - 18
tests/e2e/workspace.spec.ts

@@ -194,41 +194,41 @@ test('edits every protocol v5 Agent setting with one inspector close control', a
   await expect(page.getByRole('button', { name: '关闭团队管理' })).toHaveCount(1)
   await expect(page.getByRole('button', { name: '关闭预览' })).toHaveCount(0)
   await expect(page.getByLabel('最多回复轮数')).toHaveValue('-1')
-  await page.getByRole('button', { name: '设置夭夭' }).click()
+  await page.getByRole('button', { name: '设置瑶儿' }).click()
 
-  const editor = page.getByRole('dialog', { name: '夭夭 Agent 设置' })
+  const editor = page.getByRole('dialog', { name: '瑶儿 Agent 设置' })
   await expect(page.locator('.group-manager .agent-editor')).toHaveCount(0)
-  await expect(editor.getByLabel('显示名称')).toHaveValue('夭夭')
-  await expect(editor.getByLabel('职责说明')).toHaveValue('主 Agent')
+  await expect(editor.getByLabel('群内名称')).toHaveValue('瑶儿')
+  await expect(editor.getByLabel('职责说明')).toHaveValue('评审 Agent')
   await expect(editor.getByLabel('模型')).toHaveValue(JSON.stringify(['openai', 'gpt-5.6']))
-  await expect(editor.getByLabel('推理强度')).toHaveValue('high')
-  await expect(editor.getByLabel('快速模式')).toHaveValue('true')
+  await expect(editor.getByLabel('推理强度')).toHaveValue('medium')
+  await expect(editor.getByLabel('快速模式')).toHaveValue('false')
 
-  await editor.getByLabel('显示名称').fill('所有人')
+  await editor.getByLabel('群内名称').fill('所有人')
   const rejectedResponse = page.waitForResponse(response => response.request().method() === 'PATCH' && /\/api\/app\/groups\/rooms\/[^/]+\/agents\/[^/]+$/.test(new URL(response.url()).pathname))
   await editor.getByRole('button', { name: '保存 Agent 设置' }).click()
   expect((await rejectedResponse).status()).toBe(409)
   await expect(editor.getByRole('alert')).toContainText('成员名称不能使用“所有人”')
   await editor.getByRole('button', { name: '关闭 Agent 设置' }).click()
-  await page.getByRole('button', { name: '设置夭夭' }).click()
-  await expect(editor.getByLabel('显示名称')).toHaveValue('所有人')
-  await editor.getByLabel('显示名称').fill('夭夭')
+  await page.getByRole('button', { name: '设置瑶儿' }).click()
+  await expect(editor.getByLabel('群内名称')).toHaveValue('所有人')
+  await editor.getByLabel('群内名称').fill('瑶儿')
 
   await editor.getByLabel('模型').selectOption(JSON.stringify(['openai', 'gpt-5.5']))
   await editor.getByLabel('推理强度').selectOption('xhigh')
-  await editor.getByLabel('快速模式').selectOption('false')
-  await editor.getByLabel('无需 @ 也回复').uncheck()
+  await editor.getByLabel('快速模式').selectOption('true')
+  await editor.getByLabel('无需 @ 也回复').check()
   const updateRequest = page.waitForRequest(request => request.method() === 'PATCH' && /\/api\/app\/groups\/rooms\/[^/]+\/agents\/[^/]+$/.test(new URL(request.url()).pathname))
   await editor.getByRole('button', { name: '保存 Agent 设置' }).click()
   expect((await updateRequest).postDataJSON()).toMatchObject({
-    model: 'gpt-5.5', provider: 'openai', reasoningEffort: 'xhigh', fastMode: false, replyWithoutMention: false,
+    model: 'gpt-5.5', provider: 'openai', reasoningEffort: 'xhigh', fastMode: true, replyWithoutMention: true,
   })
   await expect(editor.getByLabel('模型')).toHaveValue(JSON.stringify(['openai', 'gpt-5.5']))
 
   await editor.getByLabel('模型').selectOption(JSON.stringify(['openai', 'gpt-5.6']))
-  await editor.getByLabel('推理强度').selectOption('high')
-  await editor.getByLabel('快速模式').selectOption('true')
-  await editor.getByLabel('无需 @ 也回复').check()
+  await editor.getByLabel('推理强度').selectOption('medium')
+  await editor.getByLabel('快速模式').selectOption('false')
+  await editor.getByLabel('无需 @ 也回复').uncheck()
   const restoreResponse = page.waitForResponse(response => response.request().method() === 'PATCH' && /\/api\/app\/groups\/rooms\/[^/]+\/agents\/[^/]+$/.test(new URL(response.url()).pathname))
   await editor.getByRole('button', { name: '保存 Agent 设置' }).click()
   expect((await restoreResponse).status()).toBe(200)
@@ -758,8 +758,9 @@ test('renders context compaction as a collapsed timeline event', async ({ page }
 
 test('renders model changes as a collapsed system event', async ({ page }) => {
   await page.goto('/chat/session-demo')
-  await expect(page.getByText('模型已切换:gpt-5.6-terra', { exact: true })).toBeVisible()
-  await expect(page.locator('.system-event')).not.toHaveAttribute('open', '')
+  const modelEvent = page.locator('.system-event').filter({ hasText: '模型已切换:gpt-5.6-terra' })
+  await expect(modelEvent.getByText('模型已切换:gpt-5.6-terra', { exact: true })).toBeVisible()
+  await expect(modelEvent).not.toHaveAttribute('open', '')
 })
 
 test('opens a local message file link as a floating preview card', async ({ page }) => {

+ 1 - 1
tests/fixtures/fake-hermes.mjs

@@ -71,7 +71,7 @@ const messages = [
   { id: 'message-system', role: 'user', content: '[System: The active model for this chat has changed to gpt-5.6-terra via provider openai.]', timestamp: now() - 130 },
 ]
 const groupAgent = { id: agentId, roomId, profile: 'yaoyao', displayName: '夭夭', description: '主 Agent', enabled: true, replyWithoutMention: true, isHost: true, model: 'gpt-5.6', provider: 'openai', reasoningEffort: 'high', fastMode: true, status: 'idle', createdAt: now() - 2000, updatedAt: now() }
-const secondGroupAgent = { id: secondAgentId, roomId, profile: 'yaoer', displayName: '瑶儿', description: '评审 Agent', enabled: true, replyWithoutMention: false, isHost: false, model: 'gpt-5.6', provider: 'openai', reasoningEffort: 'medium', fastMode: false, status: 'idle', createdAt: now() - 1900, updatedAt: now() }
+const secondGroupAgent = { id: secondAgentId, roomId, profile: 'yaoer', nodeId: 'remote-node', nodeLabel: '远程节点', displayName: '瑶儿', description: '评审 Agent', enabled: true, replyWithoutMention: false, isHost: false, model: 'gpt-5.6', provider: 'openai', reasoningEffort: 'medium', fastMode: false, status: 'idle', createdAt: now() - 1900, updatedAt: now() }
 const groupAgents = [groupAgent, secondGroupAgent]
 const groupMessage = { seq: 1, id: '44444444-4444-4444-8444-444444444444', roomId, topicId, senderKind: 'human', senderId: 'demo-user', senderName: '验收用户', content: '大家好,检查一下群聊输入框。', status: 'completed', createdAt: now() - 120, updatedAt: now() - 120 }
 const groupAssistantMessage = { seq: 2, id: '55555555-5555-4555-8555-555555555555', roomId, topicId, senderKind: 'agent', senderId: agentId, senderName: '夭夭', content: '历史兼容:MEDIA:/brand/AppIcon-1024.png', status: 'completed', createdAt: now() - 100, updatedAt: now() - 100 }