首页
/ claude-mem Phase 08 排障手册:UI/UX 与开发体验的六项修复——ID 一致性、SSE 重连、模型徽标与插件自愈

claude-mem Phase 08 排障手册:UI/UX 与开发体验的六项修复——ID 一致性、SSE 重连、模型徽标与插件自愈

2026-09-04 12:04:18作者:凤尚柏Louis

claude-mem 的 Phase 08(Triage-08)专项聚焦于 Web UI、插件安装体验与开发者行为中六类"不丢数据但侵蚀用户信任"的中优先级问题:观察 ID 不一致、/reload-plugins 后 SSE 直播中断、模型名缺失、Claude Code 升级导致插件丢失、失效的 setup hook 引用等。本文以仓库中的分诊剧本 .maestro/playbooks/2026-03-12-CM-Issues-PRs/2026-03-12-Issues-PRs-Triage/TRIAGE-08-UI-UX-DX.md 为骨架,逐项给出排查路径、修复方案,并结合当前仓库源码(MCP 服务SSE 客户端hook 配置测试)说明每项问题在代码中的真实落点,读完后可独立完成该阶段的修复与回归验证。

Phase 08 的定位与前置条件

Phase 08 处理的是"Medium — UI/UX & Developer Experience"类别的问题。剧本开头明确指出:这些问题都不是数据丢失级 bug,但"错位的 ID、失效的直播更新、静默的安装失败会让 claude-mem 显得不可靠"。涉及 issue 为 #1339、#1331、#1265、#1268、#1340、#1332,并要求 Phases 01–07 已完成(即 同目录下的 TRIAGE-01 至 TRIAGE-07 阶段已落地)才进入本阶段。

六项任务可归纳为三条主线:

  • 数据一致性主线:Web UI 展示的 observation ID 与 get_observations MCP 工具接受的 ID 必须统一(#1339);
  • 实时性主线/reload-plugins 之后 SSE 直播必须能自动恢复(#1331);
  • 安装与配置健壮性主线:卡片展示模型名(#1265)、插件升级后自愈(#1268)、清理失效的 setup.sh 引用(#1340,顺带核查 OpenClaw 插件配置 #1332)。

修复 #1339:Web UI 观察 ID 与 get_observations 不一致

问题本质

Web viewer 中显示的 observation ID 与 get_observations MCP 工具返回/接受的 ID 对不上,导致会话上下文中"按 ID 访问记忆"的提示变成误导。剧本给出的判断是:错位大概率发生在展示 ID(行号或数组下标)数据库 id 主键列之间。修复目标是让 UI 显示 get_observations 实际接受的那个 ID——即数据库主键 observations.id,而非索引;如果 UI 目前展示的是顺序展示编号,应把真实 ID 一并显示出来(例如 #58640 这种与会话上下文索引一致的格式),同时核对 SSE 广播中的 ID 是否也一致

源码落点

get_observations 工具的定义在 src/servers/mcp-server.ts 中,其 inputSchema 明确声明 ids数字数组items: { type: 'number' })且为必填项,handler 将参数转发到 worker 的 /api/observations/batch 端点:

{
  name: 'get_observations',
  description: 'Step 3: Fetch full details for filtered IDs. Params: ids (array of observation IDs, required), orderBy, limit, project',
  inputSchema: {
    type: 'object',
    properties: {
      ids: {
        type: 'array',
        items: { type: 'number' },
        description: 'Array of observation IDs to fetch (required)'
      }
    },
    required: ['ids'],
    ...
  },
  handler: async (args) => {
    return await callWorker('/api/observations/batch', { body: args });
  }
}

该 worker 端点在 src/services/worker/http/routes/DataRoutes.ts 中注册,并对请求体做 schema 校验:

app.post('/api/observations/batch', validateBody(observationsBatchSchema), this.handleGetObservationsByIds.bind(this));

也就是说,ID 契约的权威定义在 MCP 工具 schema 与 worker 的 observationsBatchSchema 校验之间。排查时应先读 src/ui/viewer/ 下的 viewer 源码,确认卡片组件渲染的是哪个字段;再读上面这条工具链路,确认 /api/observations/batch 按什么列(主键 id)查询。只要 UI 与 SSE 事件(new_observationdata.observation.id)统一使用主键列,#1339 即闭环。

另需注意运行时前提:src/servers/mcp-server.ts 中存在运行时守卫逻辑,当 CLAUDE_MEM_RUNTIME=serverworker 两种运行时切换时,legacy 工具(search/timeline/get_observations)的可用性会受约束,回归测试时应固定运行时模式再验证 ID。

修复 #1331:/reload-plugins 之后 SSE 直播停止

问题机制

Claude Code 的 /reload-plugins 会触发 hook 重连,连带把 viewer 的 SSE 连接打断,而 UI 侧若无自动重连,观察的直播更新就永久停摆。剧本给出的排查锚点是在 worker HTTP 路由中搜索 SSEEventSourcetext/event-stream;修复优先放在 viewer 客户端

  1. 在 SSE 客户端代码里添加 EventSource.onerror 处理器,在 2 秒延迟后自动重连;
  2. 重连成功后通过 REST 拉取最新 observations 补齐断档期间漏掉的数据;
  3. 若 SSE 端点本身在 reload 时被销毁,则服务端要保证 SSE 端点的生命周期独立于插件 reload;
  4. 动手前先搜索 viewer 里已有的重连逻辑,避免重复实现。

当前仓库的实现状态

当前仓库中,viewer 的 SSE 客户端 src/ui/viewer/hooks/useSSE.ts 已具备自动重连骨架,可以据此对照剧本要求做差距分析:

  • 连接目标为 API_ENDPOINTS.STREAM,其值为 /stream(见 src/ui/viewer/constants/api.ts);
  • onerror 中先 close() 旧连接,再经 setTimeout 延时后调用 connect() 重建;
  • 重连延迟常量 SSE_RECONNECT_DELAY_MS 当前取值为 3000 mssrc/ui/viewer/constants/timing.ts),而剧本建议的是 2 秒——两者都是合理的工程取值,若按剧本调参只需改这一处常量;
  • 消息分发覆盖五类 StreamEventinitial_load(项目列表)、new_observationnew_summarynew_promptprocessing_status(处理状态与队列深度),新事件一律 unshift 到列表头部。

从源码结构看,剧本第 2 点"重连后走 REST 补洞"是当前实现中可补强的一环:onopen 里目前只清理重连定时器,尚未额外发起 REST 全量补齐请求;initial_load 事件承担了初始项目列表的填充,但 observations 的断档补齐依赖服务端重连时的初始推送是否完整。此外 src/services/worker/http/routes/ViewerRoutes.ts 中存在 text/event-stream 相关实现,是服务端"让 SSE 端点独立于插件 reload 存活"的修改落点。

需求 #1265:在 observation/summary 卡片上显示模型名

剧本给出的实现路径是一条先查存储、再查入口、最后打通管线的数据流排查:

  1. 先确认 DB 是否已有模型信息:在 src/services/sqlite/ 的 observation 类型定义与 store 中搜索 model。当前仓库的 SQLite 存储层以 src/services/sqlite/SessionStore.ts 为核心,模型字段是否已在 observations 表结构中,需要以该 store 的实际 schema 为准;
  2. DB 里没有,再看 hook 输入:在 src/cli/types.ts 中搜索 model,确认 NormalizedHookInput 是否携带了当前会话使用的模型名——hook 是 observation 写入管线的第一站,输入里有的字段才有资格被透传;
  3. 可用但未存储时:给 observations 表加列,并沿 handler 链路把字段线程化(thread through)到写入点;
  4. UI 呈现:在 viewer 卡片组件上以低调徽标(subtle badge)形式展示模型名,剧本给出的示例文案是 claude-sonnet-4-6

仓库中已存在"observed model"相关的基础设施线索,例如 tests/transcripts/observed-model-extraction.test.ts 验证的模型名提取逻辑,说明模型识别在转录解析链路中已有部分能力可以复用;但在动手改卡片组件前,仍应以第 1、2 步的搜索结果决定是"读现有列"还是"加列并透传",避免凭空假设字段存在。

修复 #1268:Claude Code 升级后插件消失的自愈机制

问题与修复方案

Claude Code 更新可能破坏插件的符号链接或安装结构,导致插件"消失"。剧本要求的修复是在 SessionStart hook 中加一个轻量自检,在正常操作之前:

  1. 检查插件文件是否还在预期安装路径 ~/.claude/plugins/marketplaces/thedotmack/
  2. 若缺失,自动重跑 marketplace 同步;
  3. 记录警告日志:Plugin installation repaired after Claude Code update

关键约束是轻量:只允许 existsSync() 级别的检查,禁止每次启动都做全量 sync。同步逻辑本体在 scripts/sync-marketplace.cjs,配套还有 scripts/restart-marketplace-worker.cjs 与发布流程里的 build-and-sync 脚本(见下文验证章节)。

从现有 hooks.json 看插件定位机制

plugin/hooks/hooks.json 中每条 hook 命令都内嵌了一段"插件根目录发现"shell 逻辑,这为自愈设计提供了现成的参照:它按优先级枚举候选目录——CLAUDE_PLUGIN_ROOT / PLUGIN_ROOT 环境变量指向的路径、~/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 下按版本号数字排序(含 .orphaned_at 孤儿标记过滤)的缓存版本、以及 ~/.claude/plugins/marketplaces/thedotmack/plugin 兜底路径——然后选择第一个包含 scripts/ 与关键脚本(如 bun-runner.jsworker-service.cjsversion-check.js)的目录,找不到时以 claude-mem: plugin scripts not found 报错退出。

从源码结构看,#1268 的自愈逻辑正可以挂接在这套发现机制之上:发现阶段本身已经能识别"缓存版本损坏、只剩 marketplaces 路径"的降级情况,因此自检只需在 SessionStart 的 worker-service.cjs start 之前确认关键脚本 existsSync() 成立,不成立时触发 scripts/sync-marketplace.cjs 重新同步即可,与现有 shell 定位逻辑天然兼容。

修复 #1340:清理 hooks.json 中失效的 setup.sh 引用

问题与排查步骤

hooks.json 曾引用一个在 v10.5.5 中已不存在的 scripts/setup.sh。剧本给出的处理分支:

  • 若脚本是有意删除的,就从 hooks.json 里删掉该 setup hook 条目;
  • 若是误删,就用 git log --oneline --all -- scripts/setup.sh 查历史,确认其功能是否已迁移到其他脚本(剧本推测大概率是 smart-install.js),再把 hook 指向正确的脚本;
  • 同时核查 OpenClaw 插件配置(#1332)是否受同一缺失脚本问题影响——OpenClaw 侧的配置见 openclaw/openclaw.plugin.jsonopenclaw/install.sh,可对照检查其中是否有指向已删除脚本的入口。

当前仓库的落地状态

这一项在仓库中已可见完整闭环:

  • CHANGELOG.md 中明确记载 Removed legacy setup.sh script
  • 当前 plugin/hooks/hooks.jsonSetup hook 已不再引用任何 .sh 脚本,而是直接调用 version-check.js(即 plugin/scripts/version-check.js),走的是上面提到的插件根目录发现 + node "$_P/scripts/version-check.js" 的路径;
  • 回归保障由 tests/infrastructure/plugin-distribution.test.ts 提供,测试用例 should not reference removed setup.sh in Setup hook 直接断言 hooks.json 内容不包含 setup.sh,相邻用例还断言 Setup hook 必须调用 version-check.js

这套"删除脚本 + 更新 hook 指向 + 用测试锁住引用"的组合,正是 #1340 类"悬空引用"问题的标准处理范式,处理 #1332 时可复用同一思路。

收尾验证:测试、构建与 UI 回归

剧本要求的验收清单三步:

  1. npm test,全部通过。以 package.json 为准,仓库实际脚本定义为 bun test tests(即 npm script test 底层跑的是 bun 测试器),所有新增行为(如 SSE 重连、插件自愈日志)建议补充对应测试用例;
  2. npm run build-and-syncpackage.json 中该脚本展开为 npm run build && npm run sync-marketplace && node scripts/restart-marketplace-worker.cjs——构建、市场同步、重启 marketplace worker 一条龙,恰好覆盖 #1268 自愈涉及的分发链路;
  3. 打开 http://localhost:37777 的 viewer UI,验证 observation 以正确 ID 展示。仓库中 37777 号端口在 src/npx-cli/cmem-memory-credentials.ts 中被定义为 HOST_OBSERVER_DEFAULT_PORT 默认端口,与剧本给出的验证地址一致;验证时重点核对卡片 ID 与 get_observations 返回 ID 的逐一相等,以及 /reload-plugins 之后 SSE 是否在 3 秒左右自动恢复推送。

小结

Phase 08 的六个条目虽然分散在 UI、hook、MCP、安装脚本不同层面,但共享同一个工程原则:用户可见的标识符(ID、模型名)、实时通道(SSE)与安装状态(插件路径)必须在客户端展示与服务端契约之间保持单一事实来源。ID 对齐以 src/servers/mcp-server.tsget_observations schema 为锚,SSE 恢复以 src/ui/viewer/hooks/useSSE.ts 的重连常量为锚,安装自愈以 plugin/hooks/hooks.json 的插件发现逻辑与 scripts/sync-marketplace.cjs 为锚,悬空引用则用 tests/infrastructure/plugin-distribution.test.ts 这类断言测试长期锁定。按剧本顺序逐项落地并通过三步验收后,这一阶段对"用户信任"的损耗即被系统性修复。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384