dsh-evolution
Local-first self-evolution plugin for DSH:把开发会话记成本地账本,用你自己已配好的模型做跨会话复盘,将踩过的坑与有效做法沉淀成本地知识;默认不联网、不上传、可一键导出。 适合需要对开发会话进行复盘、沉淀本地知识库且注重隐私的用户。
Other repositories with this package name
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:wycto/dsh-evolutionREADME
Read the full README ↗配置项
配置文件是 ~/.dsh-evolution/config.json,也可以用面板改。面板是纯数据驱动渲染的:
配置项的说明、范围、可选值都在 lib/config.js 的 SCHEMA_FIELDS 里,
加一个配置项不需要动面板代码。
主要分组:总开关 / 会话账本 / 自动复盘 / 隐私与脱敏 / 本地 skill 落点 /
接口对接(可选) / 数据库对接(可选) / 检索 / 注入 / 导出与草稿。
关于自动复盘(默认关)
自动复盘 这一组里,除了总开关还有几个真正影响"会不会花钱、花多少"的项:
| 配置项 | 默认 | 作用 |
|---|---|---|
review.enabled | ❌ 关 | 自动链路的唯一总闸。关着时手动「现在复盘」仍然可用 |
review.provider / review.model | 空 | 留空 = 用你当前会话用的模型;也可以指定一个更便宜的。面板里不用手填模型名:配置页顶部的选择器会列出宿主里真实可用的模型,选一个就把这两项一起写好(这两个字段在面板上不显示输入框) |
review.extractAfterTurns | 10 | 攒够多少轮才考虑跑一次 |
review.idleDebounceMs | 60000 | 会话静默多久才触发(避免和你抢模型) |
review.dailyTokenBudget | 200000 | 每日 token 预算(默认 20 万,约够跑四十多次复盘),0 = 不限。超了当天直接拒绝,并把原因写进返回值 |
review.maxInsightsPerRun | 5 | 一次最多收几条 —— 这是质量阀门,不是省钱开关 |
review.minNewRecordsPerRun | 20 | 同一会话两次复盘之间至少新增多少条记录(防连点按钮重复烧钱) |
review.timeoutMs | 120000 | 单次调用超时,到点 abort 并标成 TIMEOUT |
review.countUsageAgainstBudget | ✅ 开 | 这次用量是否计入每日预算(关掉只影响统计) |
review.pauseUntil | 空 | 「暂停 24 小时」写的就是它 |
复盘用哪个模型:必须从列表里选一个,不选就不复盘
花谁的钱必须是你自己说的。 复盘曾经"跟随你当前会话用的模型",现在删掉了:
- 会话模型往往正是你正在用的、最贵的那一个。后台功能悄悄顺着它跑,等于为一个你没同意的模型付费;
- 它随你在 DSH 里随手切模型而变,于是"复盘花多少"变成一个你既看不见也控制不了的量;
- 面板上写着"跟随当前会话",而这条信息在你没打开面板时随时会变 —— 事后没人能复现"当时为什么花这个钱"。
所以语义只剩两种:配了就用配的,没配就一次都不调(自动链路直接跳过,手动按钮给出"去配置"的提示)。 只填一半(provider 有而 model 没有,或反过来)同样按"没配"处理 —— 宁可不复盘,也不拿半截配置去猜模型名。
配置页「自动复盘」组顶部的选择器会把宿主里真实注册的 provider × model 列出
(对应 /dsh-evolution/models 这个只读能力),选一个就同时写好 review.provider 与 review.model;
面板还会直接告诉你这次会用哪个、来源是"配置里指定的"还是"未配置,不会复盘"。
这一项只有一个下拉,没有任何手填框 —— 能填的入口就会有人填错,而"哪些模型真的可用"
只有宿主知道。所以配置页也不再显示 review.provider / review.model 两个输入框
(它们仍在配置文件里,由选择器写入)。
几个刻意的细节:
- 列表拿不到就说清楚:某个提供方的模型列表取不到(超时/401)时,只有它变空, 其余提供方照常列出,并在下面写明原因 —— 整页空掉会被误读成"一个模型都没有";
- 单个提供方列模型最多等 4 秒,目录缓存 60 秒(「刷新」按钮强制取新的), 所以打开配置页不会卡在一次远端查询上;
- 已有的旧值不会被静默改掉:如果你之前手改过
config.json、填了一个宿主目录里没有的 model id,下拉里会把它作为「当前配置里的值」显示出来并原样保留(选一个列表里的模型即可覆盖); - 试跑页的成本估算用的是同一个解析结果,不会出现"按 A 报价、按 B 计费"。
关于检索与注入
retrieval.candidatePool(默认 30)先按打分取一个候选池,再按各段预算渲染;retrieval.minRecurrenceToInject(默认 1)是"至少见过几次才允许注入";retrieval.perScopeLimit(默认 12)防止某一类条目把别的段挤掉;inject.*是四段各自的条数与字数上限(约束 3 条 / 项目洞察 3 条 / 团队 2 条 / 个人 1 条)。
打分是确定性的(同库同配置必然同顺序),否则"试跑看到的"和"真正注入的"会漂移。
排序权重、90 天半衰期、pin 加分这些都写在 lib/retrieve.js 里,面板上每条能看到自己的分数构成。
关于导出与草稿
- 导出是纯本地行为:
exports/下生成一对insights-.md/.json, markdown 默认带证据链(export.includeEvidence),单次上限export.maxEntries(500 条)。 - 导入(「导出与草稿」页):选一份导出的 JSON 恢复。语义是按 id 恢复: 字段(复现次数、证据链、时间戳、人工状态)原样保留,库里已有的 id 自动跳过 —— 重复导入同一份文件零副作用,不会把复现次数越导越高(这是它与"复盘写入" 的本质区别)。适合换机器、误清空后把数据搬回来。
- skill 草稿的门槛刻意高:默认要求 复现 ≥2 次(
export.skillMinRecurrence) 且 你已采纳(export.skillRequireAccepted),最多一次 3 个(export.skillMaxDrafts)。 skill 是"可执行流程",比一条提醒重得多;把模型的一次性猜测写成流程,比什么都不写更糟。 - 生成的
SKILL.md会先按宿主解析规则自检一遍再允许写盘 —— 格式错了宿主只会静默跳过,表现为"技能没生效",一个静默失效的生成器比没有这个功能更糟。
关于晋升(个人提醒 / 团队规范)
注入的第三、四段(团队规范 / 个人提醒)只能由你手动晋升填进去:
promotion.personMinRecurrence(默认 2):在几次会话里复现过才列为候选。 跨仓库提醒会出现在每个仓库的上下文里,所以门槛比"进本仓库"高。promotion.pinOnPromote(默认关):晋升只表示"适用范围更广",不等于"更重要"。- 插件不会自动做跨工作区聚合。 那会把同一台机器上不同雇主/项目的经验混在一起 (DESIGN 决策 5),所以「洞察」页只列出够格的候选与不够格的原因,点一下才发生。
- 晋升是移动不是复制,来源记在条目里,随时可退回原作用域。
- 晋升为团队规范会进入跨项目的第三段,影响面更大,所以面板会再要一次确认。
关于 skill 落点
面板里可选三种:
| 选项 | 实际路径 | 说明 |
|---|---|---|
| 插件数据目录(默认) | ~/.dsh-evolution/skills/ | 不碰你的仓库、不需要改任何 DSH 配置 |
仓库内 .agents/skills | /.agents/skills/ | DSH 原生发现,随 git 走,团队天然共享 |
仓库内 .dsh/skills | /.dsh/skills/ | DSH 最高优先级的项目根 |
| 自定义路径 | 你填 | ⚠️ 需要你在 DSH 配置里额外加 customSkillDirs,否则写了不生效 |
⚠️ DSH 的 skill 发现根按 rank 顺序扫描(
dsh-skill-filesystem文档实测):
rank 来源 路径 100 project-dsh/.dsh/skills200 project-agents/.agents/skills300 customConfig.customSkillDirs400 user-dsh/skills500 user-agents/skills600 bundled$DSH_BUNDLED_SKILL_DIR项目根 = 包含
.git的最近祖先目录(没有则用当前 cwd)。 用列表外的目录名(比如.agent单数)不会被自动发现 —— 这时要么选customSkillDirs并在 DSH 配置里加一行,要么就落插件数据目录。 这是选"自定义路径"时面板会提醒的原因。
关于接口与数据库(默认关)
本插件不实现、也不托管任何服务端。
- 接口(远程存储已实现):
api.enabled + storageBackend + baseUrl三者就位后, 账本与洞察整体读写到该服务(⚠️ 这等于把数据交给那台服务,是显式的隐私决定)。 token 从api.tokenEnv指名的环境变量读;401/403 后客户端停止发送。 服务端可以用仓库附带的参考实现跑起来:node scripts/reference-server.mjs [端口] [--token ]; 协议细节见docs/API-CONTRACT.md。改完配置需重启。 - 数据库(SQLite 已实现):
database.enabled + driver=sqlite打开后,数据 搬进 Node 内置node:sqlite的单文件数据库(默认/index.sqlite, 零依赖、无需编译)。首次启用会把存量 NDJSON 一次性导入(原文件保留不动, 删掉数据库文件再重启即可完整回退);之后数据库就是真相源,本地文件不再读写。postgres驱动只有契约(docs/DB-CONTRACT.md),打开会得到显式警告并回退文件。 面板「总览」页的"数据落点"会如实显示当前用的是哪个后端、数据在哪个文件。 改数据目录 / 数据库路径后需要重启宿主才生效(后端在启动时装配一次)。
用途是把知识存进你更放心的地方 / 共享给团队,不是把数据交给作者。