# dsh-evolve-in-git
面向 DeepSeek Harness 的 Git 长效记忆与演化插件。 ## 目录 - [简介](#简介) - [快速安装](#快速安装) - [使用方式](#使用方式) - [架构](#架构) - [数据布局](#数据布局) - [配置](#配置) - [Harness 入口](#harness-入口) - [浏览器端](#浏览器端) - [开发](#开发) - [发布说明](#发布说明) - [许可证](#许可证) ## 简介 这个插件把用户指定或预配置的 Git 仓库当作记忆存储:把会话笔记、分支记录、 可复用的技能草稿写进仓库,再作为普通 Git 历史提交。 ## 快速安装 ```sh # 1) 安装到某个 profile(例如 web) dsh plugin --profile web add github:Kytolly/dsh-evolve-in-git # 2) 重启该 profile,并让它指向你自己的记忆仓库 # (编辑 ~/.dsh/evolve-in-git.json,或用 Settings → 演进记忆 表单) dsh --profile web ``` 安装后先验证组合是否生效: ```sh dsh --profile web --dump-config # 应能看到 evolve-git 这一行 dsh --profile web # 启动 profile;加载后模型能看到 evolve_* 工具 ``` ## 使用方式 ### 自然语言使用 不需要记工具名:直接描述你想要的结果,模型会自动选择 `evolve_*` / `memory_*` 工具: | 你这样说(或类似) | 模型会调用 | | --- | --- | | "记住:每次 X 发生就做 Y" | `evolve_remember` / `memory_save` | | "有没有关于部署流程的记忆?" | `evolve_recall` / `memory_search` | | "读一下我最近的记忆历史" | `evolve_timeline` | | "把这条警告变成可复用技能" | `evolve_skill_draft` → `evolve_skill_promote` | | "记忆仓库现在是什么状态?" | `evolve_status` / `evolve_branches` | | "撤销上次的记忆提交" | `evolve_rollback` | ### 指令调用(/evolve) 需要确定性的手动控制时,直接输入 `/evolve <子命令>`: ```sh /evolve remember warning "坑" :: <内容> /evolve search deploy /evolve skill list /evolve skill promote evolve-process /evolve status /evolve help ``` 完整命令参考见 [Harness 入口](#harness-入口)。 ## 架构 代码拆成 **无框架 core** 和薄薄的 **DSH adapter** 两层: - `src/core.ts`(`GitMemoryCore`)是可移植边界:只依赖 Node 内置模块与同级 core 模块,不依赖任何 `@deepseek-ai/*` 包;它在宿主提供的配置之上叠加磁盘 配置文件来解析最终配置。 - `src/index.ts`(`GitEvolutionService`)是 adapter:注册 Cordis 工具、 `/evolve` 命令、system-prompt 段落、技能 provider 和配置路由,然后把所有 入口映射到 `GitMemoryCore`。 | 模块 | 职责 | | --- | --- | | `src/git.ts` | 调用 `git`:clone/open、status、分支操作、push/fetch、commit、`git mv`、冲突、回滚。 | | `src/memory.ts` + `src/memory-index.ts` | Markdown + YAML frontmatter 扫描;元数据索引缓存(HEAD + mtime 签名);带预算的召回;时间线。 | | `src/update.ts` | 版本化更新:新 active 记录 + `supersedes`/`supersededBy`;旧文件永不删除。 | | `src/forget.ts` | 软删除(移到 `archiveRoot`)与恢复。 | | `src/privacy.ts` | 敏感内容检测、敏感级分类、脱敏、导出过滤。 | | `src/skill.ts` | `drafts/` ↔ `enabled/` 技能发现;用 `git mv` 提升/降级;内置技能同步。 | | `src/strategy.ts` | slug/段名清洗、由记忆生成草稿、演化建议、预览。 | | `src/harness.ts` | `/evolve` 命令归一化/解析,以及 help/usage/safety 文案。 | | `src/config.ts` + `src/defaults.ts` | 配置文件读写/合并与插件默认值。 | | `src/invariant.ts` | 无运行时不变量(事实源是已配置的 Git 仓库)。 | | `src/loopback.ts` + `src/config-route.ts` | 仅供 loopback 访问的 `/api/evolve-git/config` 路由,给配置文件编辑器用。 | | `src/client/` | 浏览器设置分区(`evolve-git` slot)与配置文件编辑器。 | ## 数据布局 - **记忆**:`` 用的是同一套元数据索引召回,返回 > 同样的排序结果,而不是另一种匹配器。 > > **归档约束。** `archiveRoot` 必须保持在 `memoryRoot` 之外(默认 > `.dsh-evolve/archive` 满足)。如果把 `archiveRoot` 指向 `memoryRoot` 内部, > 被遗忘的记录仍会被扫描,不会消失。 ### 用户配置文件 每个 DSH 用户在 `$DSH_HOME/evolve-in-git.json`(默认 `~/.dsh/evolve-in-git.json`)保留一份本地配置。它**只属于用户本地、永远不进入 任何 Git 仓库**——不要提交它。它是**唯一用户配置层**:Web Settings → 演进记忆 表单读写的正是这个文件(显示默认值叠加文件值,保存即写文件), `/evolve config show|open|refresh|set` 命令也编辑它,内嵌的 配置文件编辑器直接打开原始 JSON。 示例: ```json { "repoPath": "/absolute/path/to/your/local-memory-checkout", "repoUrl": "https://github.com/ / .git" } ``` > **永远不要把访问 token 放进这个文件**——用 `auth.tokenEnv` 指向环境变量, > 或用 Web 设置里的 token 字段(只写)。 Web Settings → 演进记忆 分区还内嵌一个 **配置文件编辑器**,直接打开该文件、 以原始 JSON 编辑,并通过 loopback-only 的 `/api/evolve-git/config` 路由保存 (保存立即生效)。 ## Harness 入口 插件面向当前 Harness `0.1.1-rc.2` 的 commands/tools/system prompt/invariants 宿主契约(peerDependencies 为 `^0.1.1-rc.2`)。装进 profile 后重启该 profile, 让 bundle 层完成组合。 ### 工具 - `evolve_connect` - `evolve_status` - `evolve_remember` - `evolve_update` - `evolve_forget` - `evolve_restore` - `evolve_show` - `evolve_export` - `evolve_branches` - `evolve_branch_switch` - `evolve_branch_diff` - `evolve_skill_draft` - `evolve_skill_list` - `evolve_skill_promote` - `evolve_skill_demote` - `evolve_rollback` - `evolve_conflicts` - `evolve_resolve` - `evolve_timeline` - `evolve_recall` - `evolve_help` - `memory_search`(`evolve_recall` 的别名) - `memory_save`(`evolve_remember` 的别名) - `memory_update`(`evolve_update` 的别名) - `memory_delete`(`evolve_forget` 的别名) ### 命令(/evolve) - `/evolve connect` - `/evolve status` - `/evolve branches` - `/evolve remember [--expires ] :: ` - `/evolve update [--merge] :: ` - `/evolve forget ` - `/evolve restore ` - `/evolve config show|open|refresh|set ` - `/evolve skill draft :: ` - `/evolve skill list` - `/evolve skill promote ` - `/evolve skill demote ` - `/evolve skill sync` - `/evolve rollback [--dry]` - `/evolve conflicts` - `/evolve resolve ` - `/evolve timeline` - `/evolve search [--kind k] [--tag t]` - `/evolve branch switch` \| `/evolve branch diff [b]` \| `/evolve branch revert ` - `/evolve help` ### 内置技能 包内 `skills/` 自带 `evolve-process` 技能。插件加载时会把它物化到仓库的 ` /drafts/evolve-process/`(仅在缺失时创建);`/evolve skill sync` 可按需覆盖为内置副本。用 `/evolve skill promote evolve-process` 提升它。 adapter 把仓库的 ` /enabled/` 目录注册为 DSH skill provider,所以 提升后的技能无需复制到 `~/.dsh/skills` 即可被调用。 ## 浏览器端 - `src/client/` - 浏览器 bundle(`lib/client.js`),由 `tsc -p tsconfig.client.json && tsdown` 编译(见 `tsdown.config.ts`);注册为 `settings.section` slot,让 Web 设置页渲染配置表单。 - `package.json` - `exports["./client"]` + `dsh.client`(`platform: "web"`)是 `dsh-client-modules` 扫描的清单契约,用于把 bundle 纳入 `window.__DSH_BOOT__`。 ## 开发 需要 Node.js 与 pnpm。工作区设为 `nodeLinker: hoisted` 并允许 `esbuild` 构建。 ```sh pnpm install pnpm build # tsc(服务端)+ tsc(客户端)+ tsdown 浏览器 bundle npx pnpm test # 重新生成 @deepseek-ai/dsh-tools stub,然后跑测试 npx pnpm typecheck # 两个项目各自 tsc --noEmit npx pnpm check # build + test(CI 使用该命令) ``` `prepack` 脚本会跑 `pnpm build`,所以发布的 `lib/` 产物总是最新的。测试位于 `tests/*.spec.ts`,用 `node --test` 经 `tsx` 运行。 ## 发布说明 `v0.6.3` 定稿了 MVP:带预算的元数据索引召回、版本化更新(`supersedes`/ `supersededBy`)、带过期的软删除/恢复、把仓库 `enabled/` 目录注册为 DSH 技能 provider 的可逆技能草稿、`block`/`redact`/`ask` 隐私写入闸门,以及 `memory_*` 别名与会话开始的 `persona`+`warning` 摘要。 验证:`npx pnpm check`(build + test;`build` 也会做类型检查)通过。 ### 已知的非阻塞 TODO - `getMemoryIndex` 在命中缓存时仍会重扫记忆根目录(正确性优先于速度);基于 watcher 的低成本签名是后续工作。 - 隐私闸门覆盖记忆写入(`writeMemoryRecord`/`updateMemory`);技能草稿写入 (`writeSkillDraft`/`saveSkillDraftFromRecord`)刻意在闸门之外(文档化的 仅记忆范围)。 - `classifySensitivity` 从不赋 `internal`;只有手工在 frontmatter 里写该值时 `internal` 导出级别才可达。 ## 许可证 MIT — 见 [LICENSE](LICENSE)。