Skip to content

dsh-go 上没有记忆库面板:手机端只能靠 memory_* 工具读写 #564

Closed

Description

@SternChiri

@modusensus

现象

手机上跑 DSH + mneme 时没有记忆库面板。dsh-go(DSH 的 Android 客户端:Flutter 原生壳,手机本机跑引擎,也能遥控电脑)不挂载 Web 客户端,现有的「记忆库设置」面板在那边打不开,只剩 11 个 memory_* 工具可用。看不到库里有几条、最近注入了什么、有没有待裁决的冲突,也改不了画像 / 规则 / 功能开关——这些都得回到电脑上的 Web 面板。

范围与形态见 Discussion #563。

方案

面板作为包内模块随 @modusensus/dsh-mneme 发布:

  • package.json 增加 dshGo 清单(v: 1,contributes.panels 一项 mneme,placement: ["session.tab", "features"]);
  • src/index.js 在已有的 webServer 分支里 ctx.inject(["dshGo"], (dshCtx) => mountDshGoPanel(dshCtx))。没有 dsh-go 桥的宿主里该服务不存在,回调不会被调度,src/dsh-go/** 不加载;
  • 代码落 src/dsh-go/(host.js 进程内派发、panel.js 状态机、views/*),由 npm run sync 进 lib/。

呈现层对齐电脑端:三个原生页签(记忆 / 实体 / 设置),「状态」并入设置页用两格开关切换(dsh-go 页签每格有 80dp 下限,四个页签会折行);功能开关直接铺在设置页;文案取 lib/client.js 里 memory.settings.*Hint、conflictQueue.applyHint 的原句。

与现有实现的关系

取数与写回复用 src/api.js 已注册的路由 handler。src/dsh-go/host.js 用 ctx.get("webServer").match(pathname) 取出 handler,再用一对伪造的 req/res 在进程内调用。不新开端口、不新增鉴权路径、不直连 SQLite、不复制 service 逻辑,错误码与字段和 HTTP API 一致。

记忆库仍按宿主独立存放:面板读写的是它所在那台宿主的 memory.db,手机与电脑两端互不连通,也没有在线同步——跨设备目前只能靠分享包 mneme.share/v1 手动迁移,且非实时。本改动不涉及同步能力。

dsh-go 的面板数据是推送式(data() 每实例只跑一次,refresh 只重画),所以每个动作后由面板把新 payload 推给打开的 feed。另外不读 GET /external-api——它会顺带生成并落库 Bearer token。

验证

  • 视图预算:19 种面板状态全部通过检查,1.7–7.4 KB(上限 120 节点 / 8 层 / 32 KiB)。
  • node scripts/check-sync.js 一致(src/ 与 lib/ 94 个文件)。
  • 附带 docs/DSH-GO.md、test/dsh-go-panel.test.js(视图预算、三页签、开关内联、文案回归、清单合法性)。

实现口径

  • 新增用户可见开关:无。面板是既有功能的另一种呈现,读写仍走既有路由与既有设置项,没有新 flag 要注册白名单。

  • schema 变更:无。不建表、不迁移,package.json 只增清单字段。

  • 回归测试:已带(见上)。

  • 新行为开关应 opt-in 默认关,注册进 settings 白名单 / new toggles opt-in by default + settings whitelist

  • 涉及 schema 变更时需配幂等迁移 / idempotent migration for schema changes —— 不适用,本改动不涉及 schema

  • 接受带回归测试的验收线 / acceptance includes regression tests

  • 本提案由 AI 辅助整理(人工审核后提交)/ Drafted with AI assistance, reviewed by a human

维护

Scope 提到的长期维护可以承担:dsh-go 侧 dshGo 服务或视图 schema 变更引发的兼容问题由我跟进;面板与后端 API 口径不一致也由我处理。

如有与上游设计不符的地方,请直接指出。

Activity

  1. SternChiri commented on Nov 4, 2026

    @SternChiri
    ContributorAuthor

    认领该 issue。计划如下,若对形态或命名有意见,我先改再动 PR。

    面板面向 dsh-go(DSH 的 Android 客户端:Flutter 原生壳,手机本机跑引擎,也能遥控电脑)。

    改动范围(26 个文件)

    • package.json:增加 dshGo 清单(mneme 面板,placement: ["session.tab", "features"])。
    • src/index.js:webServer 分支内 ctx.inject(["dshGo"], (dshCtx) => mountDshGoPanel(dshCtx)),加一个 import。
    • src/dsh-go/(新增):host.js 进程内派发既有路由 handler;panel.js 状态机、loaders、actions、推送式 feed;text.js 类型与图标表;views/{root,common,memory,entity,settings,status}.js。
    • lib/**:npm run sync 产物,与 src/ 一致。
    • test/dsh-go-panel.test.js(新增):视图预算(≤120 节点 / 8 层 / 32 KiB)、三页签结构、开关内联、文案回归、清单合法性。
    • 文档:docs/DSH-GO.md、根 AGENTS.md 模块地图一行、README.md 一段、CHANGELOG.md 的 [Unreleased]。

    不碰的部分

    不改 src/api.js 的任何路由与鉴权策略,不加端口,不直连 SQLite,不复制 service 逻辑;不新增用户可见开关,因此没有 settings 白名单要注册。也不涉及跨设备同步:面板读写的是本机那份 memory.db。

    验收

    视图预算检查通过;check-sync 一致;新增 test/dsh-go-panel.test.js 全绿。

    维护

    dsh-go 侧 dshGo 服务或视图 schema 变更引发的兼容问题由我跟进修复。

    如有与上游设计不符的地方,请直接指出。

  2. changed the title [-]feat(dsh-go): 手机端原生记忆库面板(包内模块,随插件发布)[/-] [+]dsh-go 上没有记忆库面板:手机端只能靠 memory_* 工具读写[/+] on Nov 4, 2026
  3. SternChiri commented on Nov 6, 2026

    @SternChiri
    ContributorAuthor

    面板已按 #565 的复核意见更新,并 rebase 到 main 最新 b9217635:补上 0.11.0 的「Agent 眼中的你」与代码库地志两块面板面、三个新开关与「其它」动态分组,修掉「翻开关被弹回记忆页」和 nestFlags 枚举透传;host.js 的超时守卫从 unref() 改成显式 cancel(),node 22 / 24 各跑一遍 91 项全绿。PR #565 已由维护者转 ready 并请求评审。方向需要调整的话我随时改。

  4. modusensus commented on Nov 7, 2026

    @modusensus
    Member

    这条已经由 @SternChiri 认领并在 PR #565 里实现了,我这边按只读复核记录了当前进度,供后续决定用。

    PR #565 当前状态(实测,2026-11-07)

    项 值
    head 7c3fc6a5c6e872c2eb13d99ce33230584aeb6ad3(分支 dsh-go/panel,fork SternChiri/mneme)
    规模 32 文件 +7756 −12
    合并态 MERGEABLE / CLEAN,非 draft
    CI 13 项 12 pass + 1 skipping(osv-scanner 恒跳过),fail 0

    CI 那两腿原本是红的(test (ubuntu-latest, 22) 与 test (windows-latest, 22)),新 head 上已经转绿:ubuntu 22 用 1m14s、windows 22 用 3m53s,node 24 两腿与 test-host-legacy 两腿也全 pass。

    根因与修法复核(这是本轮唯一需要看代码的地方)

    上一轮我在 #565 定位过红的原因:dsh-mneme/src/dsh-go/host.js 的超时守卫用了 timer.unref?.(),handler 永不响应时它是唯一还挂在事件循环上的东西,unref 之后 node 22 的 test runner 判定循环已空、把用例记成 cancelled。

    新 head 的 dsh-mneme/src/dsh-go/host.js:96-104 已经按这个结论改掉,注释也把原因写在了代码里:

    // 超时定时器不能被 unref():handler 永不响应时,它是唯一还挂在事件循环上的
    // 东西;unref 之后 node 22 的 test runner 会判定循环已空,把用例记成 cancelled
    // (CI 的 node22 两腿就是这么红的)。改成显式 cancel —— 成功路径也不白挂 5 秒。
    function timeout(ms) {
      ...
      return { promise, cancel: () => clearTimeout(timer) };

    并且 :144 在 finally 里显式 guard.cancel(),所以成功路径也不白挂 5 秒定时器——这正是我上轮建议的形态,不只是删掉 unref。

    附带的两处共用面改动(值得单独看一眼)

    这个 PR 除了新增 src/dsh-go/**,还动了两个所有入口都在用的文件:

    1. dsh-mneme/src/store.js 的 listEntities({ limit, q }) 把名字过滤下推到 SQL(WHERE name LIKE ? ESCAPE '\',%/_ 做了转义)。理由是原来调用方取回 limit 条再本地过滤,排在 limit 之外的实体永远搜不到;src/service.js:3038 是 listEntities: (o) => store.listEntities(o) 原样转发,所以老宿主不传 q 时行为不变。
    2. dsh-mneme/src/api.js 的 GET /external-api 新增 ?token=omit:只读配置、不顺手 materialize Bearer 并写进 user_settings。不传这个参数的老客户端行为完全不变。

    两处都保留了向后兼容的回落,且都有测试(新增 test/api-routes-gaps.test.js 46 行、test/dsh-go-host.test.js 134 行、test/dsh-go-panel.test.js 251 行、test/dsh-go-panel-actions.test.js 586 行)。

    无关文件核查

    32 个文件的清单全部落在 dsh-mneme/{src,lib,test}/** + dsh-mneme/docs/DSH-GO.md + dsh-mneme/package.json + dsh-mneme/CHANGELOG.md + 根 AGENTS.md(加了一行模块地图指向 docs/DSH-GO.md)。没有 .mimosa、tools/、临时日志或本机路径产物。

    怎么验证的

    没有跑本地测试——这是外部贡献者的分支,我只做只读复核(gh pr checks / gh api 取 raw 与 diff),没检出、没改代码。上面每条结论都能用对应的 gh 命令复现:

    • gh pr checks 565 --repo slow-stack/mneme → 13 行,fail 0;
    • gh api 'repos/slow-stack/mneme/contents/dsh-mneme/src/dsh-go/host.js?ref=7c3fc6a5...' -H 'Accept: application/vnd.github.raw' → 第 96-104 行即上面的注释与 cancel;
    • gh pr view 565 --json files → 32 条路径,逐条对得上上面的清单。

    状态说明

    合并与否由维护者决定,我不在这个 issue 上替它下结论。补一条排期事实供参考:0.12.0 的发版 PR #599 已经开着,这个 PR 若在它之后合并,会顺延到下一个版本才进 npm。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions