From cc644c59f622c2aa956f85212bda54bde0f43ad3 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 19 Oct 2026 00:23:19 +0800 Subject: [PATCH] Phase 008: close the test and CI loop around the migration Adds the checks that make the constraints from Phase 001-007 mechanical instead of tribal knowledge, and clears the legacy brand text that was still reachable at runtime. New red-line tests: - no-legacy-brand mirrors the harness scan under vitest, and asserts its allow-list has not drifted from harness-check.mjs - hermes-db-readonly classifies every new DatabaseSync call site by following the path it opens, and fails if a state.db handle drops readOnly. It also pins the one legitimately writable database. - i18n-parity compares the raw zh/en locale objects both ways. The existing coverage test merged en into zh at import time, so a key missing from zh could never fail there. harness:check gains the four missing gates from the phase brief - retired package directories, retired package scripts, a single UI library, and the required root files. Each was verified to fail by mutating the repo. The online-update channel had hardcoded upstream URLs. It now reads HERMES_WEB_UI_VERSION_MANIFEST_URL and friends and degrades with a named error, because a reimplementation has nowhere to pull releases from. The remaining legacy strings are deliberate and each carries a reason in the allow-list: the global-agent relay address and the OpenRouter referer are load-bearing, the socket role identifier is a wire contract, and the pre-rename DB filenames would orphan existing deployments if changed. AGENTS.md now says so explicitly, so a future agent does not "clean them up". Also removes a dead electron mock alias, an i18n exemption that had stopped exempting anything, and a teardown race in plugins-view.test.ts where a-spin animation frames outlived the jsdom environment. Verified self-contained: with reference_code/ moved aside, harness:check, build, test and test:e2e all pass, so the directory can now be deleted. --- .github/ISSUE_TEMPLATE/config.yml | 7 - .github/workflows/build.yml | 6 + AGENTS.md | 10 + ARCHITECTURE.md | 3 + docs/harness/worktree-runbook.md | 8 +- docs/known-issues.md | 194 +++++++++++ .../src/services/runtime-version-manager.ts | 27 +- scripts/harness-check.mjs | 148 ++++++-- tests/client/i18n-coverage.test.ts | 9 +- tests/client/i18n-parity.test.ts | 110 ++++++ tests/client/markdown-rendering.test.ts | 4 +- tests/client/plugins-view.test.ts | 24 +- tests/mocks/electron.ts | 6 - .../handle-bridge-run-session-ended.test.ts | 2 +- tests/server/hermes-db-readonly.test.ts | 320 ++++++++++++++++++ tests/server/no-legacy-brand.test.ts | 312 +++++++++++++++++ vitest.config.ts | 1 - 17 files changed, 1135 insertions(+), 56 deletions(-) create mode 100644 docs/known-issues.md create mode 100644 tests/client/i18n-parity.test.ts delete mode 100644 tests/mocks/electron.ts create mode 100644 tests/server/hermes-db-readonly.test.ts create mode 100644 tests/server/no-legacy-brand.test.ts diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 48c662e..0086358 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1 @@ blank_issues_enabled: true -contact_links: - - name: Documentation - url: https://github.com/EKKOLearnAI/hermes-studio#readme - about: Please check the documentation first - - name: GitHub Discussions - url: https://github.com/EKKOLearnAI/hermes-studio/discussions - about: Use GitHub Discussions for questions that don't fit as issues diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc7a555..2ab1270 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,5 +44,11 @@ jobs: - name: Test with coverage run: npm run test:coverage + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: End-to-end tests + run: npm run test:e2e + - name: Build run: npm run build diff --git a/AGENTS.md b/AGENTS.md index a4fb3b0..f315b52 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,6 +56,16 @@ Use the smallest relevant check while iterating. Before a broad PR, run `services/hermes/context-engine/` are the chat chain: changes require a `docs/chat-chain-changes/-.md` fragment. - `packages/desktop` and `packages/website` are removed; do not reintroduce them. +- This repo is a reimplementation. A few upstream service addresses are load-bearing + and are deliberately kept, each with a whitelist entry in + `scripts/harness-check.mjs`: the global-agent relay (`api.hermes-studio.ai`), the + OpenRouter referer, and the ESP32 purchase link. Do not "clean them up" as legacy + brand text — removing them breaks those features. Do not read the relay address as + project identity: this deployment is not affiliated with the upstream operator. +- The online-update channel (`runtime-version-manager.ts`) has no default URL. It reads + `HERMES_WEB_UI_VERSION_MANIFEST_URL` / `HERMES_WEB_UI_DOWNLOAD_BASE_URL` / + `HERMES_WEB_UI_GITHUB_REPO` and degrades with a named error when unset. Do not + reintroduce a hardcoded upstream URL. - ArkScope vendor (`packages/client/src/vendor/arkscore/`) is decorative only: login-page title, Journey graph background, first-load / empty states. Never in chat, forms, tables, or click-dense areas. Decorative layers must be diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3d7bfc2..4db9e84 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -44,6 +44,9 @@ should not duplicate server persistence rules. - The project's own SQLite store under `packages/server/src/db` is the only writable store for sessions, messages, and usage. There is no startup import sync from Hermes state. +- Every `state.db` handle in Node-side code opens with `readOnly: true`; + `tests/server/hermes-db-readonly.test.ts` classifies each `new DatabaseSync` call + site and fails if one of them drops the flag or opens it writable. - Uploads default to `config.uploadDir`, which is derived from the Web UI home unless `UPLOAD_DIR` is set. - Runtime data directories must also live under the Web UI home, not beside built `dist` assets. - Profile-scoped Hermes data should use existing profile helpers instead of manually joining paths. diff --git a/docs/harness/worktree-runbook.md b/docs/harness/worktree-runbook.md index 325db81..9f3565a 100644 --- a/docs/harness/worktree-runbook.md +++ b/docs/harness/worktree-runbook.md @@ -7,8 +7,8 @@ untouched. ```bash git fetch origin --prune -git worktree add -b codex/ ../worktrees/hermes-web-ui- origin/main -cd ../worktrees/hermes-web-ui- +git worktree add -b codex/ ../worktrees/hermes-ui- origin/main +cd ../worktrees/hermes-ui- ``` If the repository uses a fork remote, push to the remote requested by the task. @@ -27,7 +27,7 @@ Use per-worktree state and ports to avoid colliding with a running local app: ```bash export PORT=18648 -export HERMES_WEB_UI_HOME="$PWD/.tmp/hermes-web-ui" +export HERMES_WEB_UI_HOME="$PWD/.tmp/hermes-ui" export HERMES_WEBUI_STATE_DIR="$HERMES_WEB_UI_HOME" export UPLOAD_DIR="$PWD/.tmp/uploads" npm run dev @@ -52,7 +52,7 @@ requirements only when the behavior cannot be represented with mocks. After a PR is pushed and no more local work is needed: ```bash -git worktree remove ../worktrees/hermes-web-ui- +git worktree remove ../worktrees/hermes-ui- ``` Only remove the worktree you created. diff --git a/docs/known-issues.md b/docs/known-issues.md new file mode 100644 index 0000000..a4eae5b --- /dev/null +++ b/docs/known-issues.md @@ -0,0 +1,194 @@ +# 已知问题与迁移遗留 + +记录 UI 库迁移(Phase 006-007,naive-ui → Arco Design Vue)过程中**发现但按规则未修**的问题,以及自动化测试**测不到、只能靠手工验证**的风险点。 + +用法:日常使用时遇到异常表现,先来本文档搜关键词。确认命中后按「证据」栏定位,确认是同一个问题再修。 + +新增条目请追加到对应分区末尾,不要重排已有条目。 + +--- + +## 一、已确认的业务逻辑缺陷 + +这些是读代码时确认存在的真实缺陷,与迁移无关(迁移前就存在),但迁移过程中被注意到。修它们属于逻辑改动,需单独开分支。 + +### 1. ModelSelector 的 computed 里有副作用 + +- **现象**:切换模型时 provider 选择偶尔「自己跳」,或 `customProvider` 状态被莫名改写 +- **位置**:`packages/client/src/components/layout/ModelSelector.vue`,`providerOptions` computed 的 getter +- **证据**:computed 的 getter 内部给 `customProvider.value` 赋值。computed 应当是纯读。副作用是:任何其它 computed 或渲染逻辑读到 `providerOptions`,都会顺带改写 `customProvider` +- **修法**:把赋值移到 `watch` 或显式的 setter 里 + +### 2. ProfileSelector 把 i18n key 当文案用 + +- **现象**:某些运行时状态提示里显示原始 key(如 `profiles.runtime.checking`)而不是中文/英文文案 +- **位置**:`packages/client/src/components/layout/ProfileSelector.vue`,`gatewayStatusText` / `bridgeStatusText` +- **证据**:`message.warning(t('profiles.runtime.checking'))` —— `t()` 的结果(一个 key 字符串)被直接当消息正文,缺了外层再套一次 `t()` +- **修法**:改成 `message.warning(t('profiles.runtime.checking'))`(让 `t()` 返回字符串函数的结果),即检查是否需要 `t(t(key))` 或改用 `te()` + 手动查表 + +### 3. McpManagerView 的 `_autoRetryCount` 赋值可能静默失效 + +- **现象**:MCP 失败后点「重试」,自动重试计数似乎没有正确归零 +- **位置**:`packages/client/src/views/hermes/McpManagerView.vue`,`let _autoRetryCount`(模块级) +- **证据**:在 header 按钮的内联表达式 `@click="_autoRetryCount = 0; loadServers()"` 里被重置。`