# 北极星记忆 · 版本线策略(VERSION LINES) > **2026-09-11 定案(用户):取消双线,只保留一条线,版本号定为 `0.1.3`,暂不发布。** > 插件**不再为旧版本核心做适配**,只跟最新的 DSH 核心走(0.1.5-rc.1 及更新)。 > 双线时期的版本号 `0.1.4` / `0.1.5` **作废**(从未对外发布过,本地标签已删除)。 > 旧的自用稳定线(legacy 0.1.4 代码)已**归档**:`D:\Agent共享\DSH插件\归档-legacy线-20260911\` > (含完整 git bundle `北极星legacy-v0.1.4-all-refs.bundle`,已 `git bundle verify` 校验)。 --- ## 1. 单线是什么 | 项 | 值 | |---|---| | 包名 | `@dsh-external/dsh-project-memory`(加载身份 = package.json name;补丁行 name、node_modules 目录名三处必须一致) | | 版本 | **0.1.3**(暂不发布) | | 源码目录 | `D:\DeepSeek\project-memory-bundle`(原 `polaris-next`,2026-09-11 归并改名) | | git | 分支 **`main`** + 标签 **`v0.1.3`**(指向当前 HEAD);远程 `origin` = `github.com/LAYZR114/dsh-project-memory`(**尚未推送**) | | 目标核心 | **DSH 0.1.5-rc.1 及更新**(桌面端 2.0.7 / 2.0.9);旧核(0.1.2-rc.1 等)**不再适配** | | 安装包 | `D:\Agent共享\DSH插件\dsh-external-dsh-project-memory-0.1.3.tgz` | | 记忆数据 | 各项目目录下的 `.dsh-memory.json`(store v2/v3),换版本不丢记忆、无需迁移 | ## 2. 版本号策略(沿用 2026-09-10 用户定调) - 同属 **0.1.x** 系列:纯核心适配、bugfix、兼容补丁、小功能 → 只加补丁位。 - **只有出现较大优化或新功能才升 `0.2.0`**。 - 版本号全局唯一(只一条线,天然满足)。 - ⚠️ 双线时期用过的 0.1.4 / 0.1.5 已作废且从未发布,**下一个补丁位从 0.1.4 继续**。 ## 3. 铁律 1. **一个 profile 只装一份**(同包名挂两份 → `memory_*` 工具重名注册冲突)。 2. 补丁行不用改;换装只改 junction 指向的目录(现在只有唯一目录)。 3. 记忆文件只允许 `memory_*` 工具或设置页修改(用户红线)。 4. 改 `index.js` / `api.js` → **重启桌面端**;只改 `client.js` → 刷新页面(F5);**补丁里新增插件行也必须重启**。 ## 4. 安装 / 卸载(单线) - 安装(二选一): - junction(推荐,改代码即生效): `mklink /J "C:\Users\35211\.dsh\profiles\desktop\node_modules\@dsh-external\dsh-project-memory" "D:\DeepSeek\project-memory-bundle"` - tarball:`dsh plugin --profile desktop add "D:\Agent共享\DSH插件\dsh-external-dsh-project-memory-0.1.3.tgz"` - 卸载:删 junction(`cmd /c rmdir <链接>`,**只删链接**)+ 删除 profile 补丁里的 insert 行。 - ⚠️ **建 junction 一律用 `New-Item -ItemType Junction -Path <链接> -Target <目标>`**;不要用 `cmd /c mklink` 并在双引号里写 `"$obj.Prop"`(Windows PowerShell 会把它展开成 `System.Collections.Hashtable.Prop`,链接指向坏路径——2026-09-11 实测踩到)。 ## 5. 发布前三件套(每次发布都要跑齐) ```sh node --test # 51 项(含 client 真行为测试) node tools/verify-api-0.1.5.mjs # 29 项静态 API 核对(需要 DSH 0.1.5 源码树,见下) node tools/smoke-apply.mjs # 25 项 apply() 冒烟(含"全新安装 = 0 条记忆") ``` - `verify-api-0.1.5.mjs` 依赖解压出来的核心源码树,默认路径 `D:\DeepSeek\_src_inspect\dsh-v0.1.5-rc.1\deepseek-harness-dsh-v0.1.5-rc.1`。 需要时用 zip 重新解压即可(`D:\DeepSeek\deepseek-harness-dsh-v0.1.5-rc.1.zip`,约 25MB)。 **源码树不在时该脚本打印提示并跳过(不判失败)**——2026-09-11 已把源码树从磁盘清掉 (它含 `AGENTS.md`/`CLAUDE.md`,一读就触发 DSH 仓库规范注入,实测 23,431 字符,白烧上下文)。 - 发布包内不得含任何记忆数据(`.gitignore`/`.npmignore` 已挡)。 ## 6. 变更记录 - 2026-09-12:**界面修复第三轮 + 结构审计**(用户逐条实测驱动)。① 「点目录框却输入到搜索框」根治:先删 `autoFocus`、再发现回调 ref 的 `focusEnd()` 每次渲染都执行 `focus()`,最终**结构性根治**——搜索框收起时从 DOM 卸载(`searchOpen ? slot : null`),元素不存在即物理上无法抢焦点(该问题曾复发两次,逻辑补丁不够)。② 目录框「点一下就闪」修复:onFocus 开下拉 + onBlur 150ms 关下拉形成闪烁循环,改为幂等加载 + 有匹配项才渲染。③ 记忆胶囊展开时缩成纯数字(88→44px)+ 搜索框 130→100px → 展开态 612→540px,不再被顶出屏幕;并修好数字与胶囊的居中(特异性需 `.pm-stat.pm-stat-mini b` 压过 `.pm-stat b` 的 `margin-left:3px`)。④ 结构审计采纳:合并文件末尾"补丁组"(消除"改了不生效")、删 18 条死规则、修好静默失效的拖拽抓手、统一 `commitEdit` 使编辑/新增/删除也做 `verified` 回读校验、撤销按钮不再依赖提示消息存在。⑤ 新增守卫断言:焦点守卫 / CSS 冲突守卫 / 反引号守卫 / 渲染块唯一性 / 数字居中 / 静态布局验证器(手算 flex 坐标,含"展开态必须 ≤540px 面板宽")。全量 **115/115** 通过。 - 2026-09-11:**设置页第二轮 UI 微调**(用户逐条要求):① 筛选胶囊文字**单行横排**(`pm-tab` 加 `white-space:nowrap;flex:0 0 auto;word-break:keep-all`);② 保存 + 「记忆 N」**左移贴近目录输入框**(工具条顺序 输入→保存→记忆→最近,去掉 `margin-left:auto`);③ 搜索改为**默认收起的图标按钮**(在「已归档」右侧,Feather 放大镜),点击**向右展开**输入框(`pm-search-in` 动画;Esc 先清词、空词收起);④ 排序下拉**文案不减**(全角冒号 + `max-width:190px`)压窄。新增 4 项断言(含"顺序正确""搜索在四个胶囊之后""文案必须保留"),全量 **93/93** 通过。 - 2026-09-11:**撤销「选择目录」+ 设置页布局紧凑化**(用户决定):① 该按钮在桌面端拿不到任何可用的目录选择能力(宿主 `directoryPicker.capability()` 只给 browse 描述、无 `list` 实现;客户端 `uiWorkspace` 取不到/调用失败),按用户要求**整体撤销**——客户端按钮/handler/样式、宿主 `pickDirectory`/`browseDirectories`/`directoryPickerCapability`、API 动作 `pickdir`/`browse` 全部删除,不留死代码;切目录仍是"输入框回车 / 下拉选择"。② 设置页重排为三行(标题+按钮组 / 工具条[目录+保存+统计] / 操作条[标签页+搜索+排序]),统计并入工具条、"最近"单行省略,间距收紧。测试 98→90(删掉 12 项 picker 用例,新增 4 项"已移除/布局紧凑"断言),全量 **90/90** 通过。 - 2026-09-11:**「选择目录」三级兜底 + 惰性取服务**(用户实测:"还是提示这个"——说明 apply 时抓的 `uiWorkspace` 是空的/晚注册):① `getWsPicker()` **每次点击惰性重取** `clientCtx.get('uiWorkspace')`(apply 只记下 ctx,不再依赖快照);② 宿主 `pickDirectory()` 抽出 `directoryPickerCapability()` 共用;③ 新增宿主 `browseDirectories(path)`(官方 browse 能力 `list()`)+ API 动作 **`action:'browse'`**;④ `browse-only` 时不再只提示,而是**弹出插件自带的文件夹浏览对话框**(面包屑可点回上级、点条目进子目录、"选这个文件夹"确认)。`test/dir-typeahead.test.mjs` 扩到 23 项,全量 **97/97** 通过。 - 2026-09-11:**「选择目录」改用更普适的官方入口 + 按钮尺寸统一**(用户实测:桌面端提示"没有系统文件夹对话框"):桌面端实现的是 **browse 式**目录选择(没有系统原生 `pick`),所以改为三级优先:① 客户端服务 `uiWorkspace.pickDirectory()`(即 DSH 应用自带"选文件夹"对话框);② 退回宿主 `ctx.directoryPicker` 的 `native pick()`(经 `action:'pickdir'`);③ 都没有则如实提示。取消一律静默。按钮改为 `pm-save pm-pick`(**与「保存」同 padding/字号**,只多一个 Feather 文件夹图标)——用户要求:以后做按钮尽量减少尺寸/风格差异。 - 2026-09-11:**「选择目录」按钮 + 历史污染修正**(用户需求/反馈):①输入框右侧新增「选择目录」,走官方宿主 seam `ctx.directoryPicker.capability()` —— `kind:'native'` 时 `pick(signal)` 弹**系统原生文件夹对话框**,选中即切项目并加载;取消 → `cancelled`(静默);只有 `browse` 能力时如实上报 `browse-only`(不假装成功);经新增 API 动作 `action:'pickdir'` 暴露。②**修历史污染**(用户实测:下拉被 `D:/D`、`D:/DS` 灌满):去掉"输入即自动加载"(`useEffect` 只挂载跑一次)、`load()` 不再记历史(只有回车/保存/选择目录/下拉选择这些**明确提交**才记)、`collectProjects()` **只列真有记忆文件的目录**、新增纯函数 `cleanRecentDirs()` 清理旧的半截路径。`test/dir-typeahead.test.mjs` 扩到 20 项,全量 **94/94** 通过。 - 2026-09-11:**项目目录 Typeahead**(用户需求):输入框**回车即加载**该目录记忆;聚焦弹**可搜索下拉**列出"现有项目"——宿主新增 `collectProjects()`(本进程见过的 cwd(`noteCwd` 由 `ensureCwd`/`readDoc` 记录)+ 活跃会话 `agents.list()` 的工作目录,每条附 `count` 记忆条数与 `updatedAt` 文件时间),经新增 API 动作 `action:'projects'` 暴露;客户端合并本地"最近使用"(localStorage),输入即过滤、↑↓/鼠标选择、Enter/Esc,选中即切换项目。 ⚠️ 兼容性注意:`readDoc` 内的 `noteCwd(cwd)` 用 `typeof noteCwd === 'function'` 守卫——老测试会把 `readDoc` 单独抽出来跑(其作用域里没有 `noteCwd`)。 - 2026-09-11:**新增导入向导**(用户需求):设置页「导入」选好 JSON 后**先弹确认框**(不再直接落盘)——插件对每条自动判断**分类**(关键词打分;合法显式 type 优先)与**重要等级**(义务语义「必须/禁止/每次…」→ 长期有效 + obligation,否则沿用原 ttl),按**原始正文首行**生成标题/简介(≤40/60 字,剥掉 "1、/- " 前缀;正文用 `organizedText` 自动排版),逐条给出分类/等级下拉与可编辑标题、简介;点「确定导入」才写盘,成功后**置顶**(分类分组后即显示在各组顶部),id 与现有记忆或本批内重复时自动换新;失败/回读不一致按磁盘顺序重载界面。新增 `test/import-classify.test.mjs`(12 项:判定真单测 10 + 接线 2)。 - 2026-09-11:**统一优先级:拖动排序 = 「保存排序」**(用户定调)。两者本就同一条写盘路径(`persist → /save`),但拖动那条**不看服务端回读校验**,可能"界面是新顺序、文件是旧顺序"。现在拖动提交也走 `verified` 门槛:失败/回读不一致 → 如实提示 + 按磁盘真实顺序重载界面(绝不谎报成功),成功后挂 **10 秒撤销**并提示"顺序已保存(拖动即保存)"。手动(默认)模式渲染的就是文件真实顺序 → **重启后永远是你最后摆的样子**。新增接线回归 `test/client-drag-save-wiring.test.mjs`(5 项)+ 20 轮耐久压测(`save-order-survives-writes.test.mjs`)。 - 2026-09-11:**修「保存的排序一有写入就被冲掉、重启后回退」**(用户实测发现)。病根:`writeThrough` 是唯一写入口,但所有「顺带写入」——召回热度自增(`tools.js` memory_recall)、记忆增删改(tools/commands 多处)——都是"默认读 `readDoc`(按最新重排)→ 原样写回",于是手动顺序当场被重排。修法:①`store.parseDoc/readDocSync` 支持 `keepOrder`;②`writeThrough(cwd, memories, opts)` **默认保序**(把要写的集合套回磁盘现有顺序;磁盘上没有的新记忆放最前、保持调用方相对顺序),只有 `opts.explicitOrder===true`(设置页 `/save`)才按调用方顺序落盘;③新增回归测试 `test/save-order-survives-writes.test.mjs`(6 项,含"修复前必然失败"的反证:保存 a,c,b → 3 次热度自增 → 修复前变 c,b,a、修复后仍 a,c,b)。 - 2026-09-11:**单线定型 0.1.3(暂不发布)**:取消双线后沿用"单线 + 最新核心"策略,双线版本号 0.1.4/0.1.5 作废;本地标签 `v0.1.4`/`v0.1.5` 删除、`v0.1.3` 重新指向当前 HEAD;`polaris-next` 归并回规范目录 `project-memory-bundle`,分支统一 `main`;`origin` 从"本地 legacy 目录"改指 GitHub(尚未推送)。 - 2026-09-11:桌面端升到 **2.0.9**(核心 0.1.5-rc.1)后插件实测通过:上下文注入正常、模型工具注册可用、HTTP `capabilities` 中 `tools/commands/fs/webServer/systemPromptContext/invertedIndex` 全 ok、**LLM 精排真生效**(`diagRerankRun=1 / diagRerankFallback=0`)。2.0.9 已修 2.0.7 那个"Windows Job runner 立刻 exit 0 → 所有子进程能力全挂"的回归。 - 2026-09-11:修复 `切换北极星版本线.ps1`(已随双线一起归档)的真 bug:`cmd /c mklink /J "$link" "$target.Dir"` 中 `"$target.Dir"` 被 Windows PowerShell 展开成 `System.Collections.Hashtable.Dir` → 链接指向坏路径;且后续读版本抛错会中断整个脚本。 - 2026-09-10:分版落地(legacy 冻结 0.1.2);新增设置页「保存排序」;修「手动顺序存不住」真因(`readDoc` 每次读盘重排 → `keepOrder` + `/save` 回读校验 verified);修 `checkSanity` 作用域错误(「确认保存」无反应);成功弹窗 3 秒。