@yolk_vat-y/dsh-project-memory 0.5.12 → 0.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +165 -0
- package/README.md +6 -12
- package/README.zh-CN.md +6 -12
- package/client/client.js +193 -125
- package/client/client.js.map +1 -1
- package/package.json +11 -11
- package/src/audit.js +52 -3
- package/src/auto-inject.js +64 -16
- package/src/client/ShowTaskPanelNode.tsx +51 -0
- package/src/client/TaskPanel.tsx +8 -8
- package/src/client/client.ts +10 -31
- package/src/client/slash.ts +33 -17
- package/src/client/task-ui-store.ts +43 -0
- package/src/index.js +8 -3
- package/src/insight-store.js +2 -17
- package/src/llm.js +4 -1
- package/src/readiness.js +26 -1
- package/src/store.js +8 -22
- package/src/tools/forget.js +1 -1
- package/src/tools/lesson-tools.js +1 -0
- package/src/tools/remember.js +5 -3
- package/src/tools/task-tools.js +8 -7
- package/src/tools/watch-repo.js +1 -1
- package/src/util/fs.js +33 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,168 @@
|
|
|
1
|
+
## 0.5.14 (2026-10-02)
|
|
2
|
+
|
|
3
|
+
`npm test` **540 → 561 项 / 28 → 30 个文件**;`npm run eval:injection` 逐项不变
|
|
4
|
+
(命中 14 / 假阳性 0 / 漏召 0,P/R 1.00/1.00,7 次注入 857 字符)。
|
|
5
|
+
|
|
6
|
+
### 修复:`/` 菜单里「工作流」三行点了没反应
|
|
7
|
+
|
|
8
|
+
同一个病根:**UI 动作被写成了宿主命令**。那三行的实现是
|
|
9
|
+
`remote.commands.execute(sessionId, '/tasks insight list project')` —— 命令在宿主侧确实执行了,
|
|
10
|
+
但客户端渲染命令节点的是按**命令名**分发的 `TaskCommandNode`(`key: 'tasks'`):它拿到
|
|
11
|
+
`name === 'tasks'` 就用**任务**解析器去解**记忆**载荷,`parseTaskPayloadText` 必然返回 null,
|
|
12
|
+
于是对面板零影响,只在对话里留下一个 `/tasks 已执行` 节点。用户看到的就是「点了没反应」。
|
|
13
|
+
|
|
14
|
+
根因是面板的视图页是 `TaskPanel` 组件**内部**的 `useState('task')` —— 组件外面没有任何可寻址
|
|
15
|
+
的落点,所以菜单行只能绕宿主命令,而那条路又够不到面板。
|
|
16
|
+
|
|
17
|
+
- `view` 移进 UI store(`task-ui-store.ts`):新增 `PANEL_VIEWS` / `normalizeView()` 与
|
|
18
|
+
`setView()` / `openView()`,持久化且可从组件外寻址;面板的切页按钮改为读它(不再各抄一份)。
|
|
19
|
+
- `/` 菜单三行改为**纯客户端**:`consumeSpan()` 之后直接 `openView(view)`,不再发宿主命令
|
|
20
|
+
(`SlashSourceDeps.run` 随之删除,`client.ts` 里的 `runCommand` 变成死代码也删掉)。
|
|
21
|
+
- 候选不再携带 `line` 字段。
|
|
22
|
+
- 测试:`test/client-slash.test.mjs` 的点击语义改为断言 **localStorage 里的 `view` / `closed`**
|
|
23
|
+
(旧断言是"命令行映射正确",正是它把 bug 放了过去),并加一条"视图入口不得携带命令行"。
|
|
24
|
+
|
|
25
|
+
### 修复:`show_task_panel` 从来没有打开过面板
|
|
26
|
+
|
|
27
|
+
这个工具读 `exec.ctx` 再 `emit('dsh:task-panel:show')`,而宿主契约里**没有 `ctx`**:
|
|
28
|
+
`ToolRunContext` 只扩了 `deferContext()` / `concludeTurn()` 两个自有成员
|
|
29
|
+
(`packages/core/tools/src/index.ts:418`)。于是它每次都只返回「无法获取上下文」,
|
|
30
|
+
那个事件名也是编出来的 —— 面板从未被它打开过。
|
|
31
|
+
|
|
32
|
+
面板的 `closed` / `minimized` 是**浏览器侧** UI store 的状态,宿主进程碰不到,所以正确的
|
|
33
|
+
位置是宿主给出的扩展点:`ui-tool` 在 `conversation.chat.node`(key `tool-call`)下声明了按
|
|
34
|
+
**工具名**分发的子槽 `tool.call.toolview`(契约原文:*"Any name is allowed, including tools
|
|
35
|
+
registered by your package. Register with `key: '<tool name>'`"*)。
|
|
36
|
+
|
|
37
|
+
- 新增 `src/client/ShowTaskPanelNode.tsx`:认领 `show_task_panel` 这个 key,工具结果一渲染
|
|
38
|
+
就调 `taskUIStore.open()`。**只在现场执行时打开** —— 历史节点(刷新 / 切会话后)会直接以
|
|
39
|
+
`result` 阶段挂载,那时只展示不开面板,否则每次打开会话都弹一次(与 `/tasks` 命令节点的
|
|
40
|
+
`live` 判据同款)。
|
|
41
|
+
- 宿主侧删掉那段触碰不到 `ctx` 的代码,改为只让调用真实发生并返回可读结果。
|
|
42
|
+
- 测试:新增 `test/client-toolview.test.mjs`(5 项:注册 key、历史回放不弹、现场执行弹、
|
|
43
|
+
槽缺失时降级、畸形 ctx 不抛)+ `test/task-view.test.mjs` 补一项(不依赖 `exec`)。
|
|
44
|
+
|
|
45
|
+
### 性能:影子日志瘦身 2×,单项目日志上限 4.5 MB → 1.5 MB
|
|
46
|
+
|
|
47
|
+
`admission-shadow.jsonl` 的体积 **90.6% 是 `candidates`**(实测 210 行 / 965 KB,候选占
|
|
48
|
+
875 KB),而真实 store 单步就能产生 40~60 条(中位 42)。三处都是纯冗余:
|
|
49
|
+
|
|
50
|
+
- `support` / `terms` 是**查询级**量,同一个 pre-step 内逐条恒定(实测 139/139 步)→ 提到行级;
|
|
51
|
+
- 候选只可能来自提示通道(trigger 在 `injected` / `dropped` 里)→ 不再逐条记 `channel`;
|
|
52
|
+
- 候选按分数降序、`decision === 'cand'` 必然在最前 → **全部 cand + 按排名补足到 16 条**,
|
|
53
|
+
截断前的总数记在 `candidatesTotal`,不静默。
|
|
54
|
+
|
|
55
|
+
实测单行 **6071 B → 2935 B(48%)**。同时把 `shadowMaxBytes` 默认 2 MB 降到 512 KB:
|
|
56
|
+
轮转只保留一代 `.1`,所以单项目日志硬上限从 `2×2MB + 2×256KB ≈ 4.5MB` 降到 **≈1.5MB**
|
|
57
|
+
(按每行 ~1.5KB 算仍有 ~680 步历史窗口,远超"离线重放最近历史"所需)。
|
|
58
|
+
日志**本来就是有上限的**(`rotateIfOversized` 覆盖旧的 `.1`,不是无限追加);
|
|
59
|
+
要彻底不要日志,`autoContext.shadowLog: false` 即可。
|
|
60
|
+
|
|
61
|
+
### 修复:会话配额把长会话的后段永久致盲
|
|
62
|
+
|
|
63
|
+
`maxItemsPerSession` / `maxItemCharsPerSession` 从 12 / 4000 抬到 **60 / 24000**。它们是**保险丝**,
|
|
64
|
+
不是节流阀——节流一直由单轮 `maxTokens` 与 `gateCooldownSteps` 负责,但默认值太小、真实用量
|
|
65
|
+
确实到得了:实测 5 个 root 的 2781 个 pre-step(含轮转历史)里 **11/81 个会话打满**,打满之后
|
|
66
|
+
再无条目注入(`session-chars` 1115 步 + `session-items` 119 步),且**全部尾部失明步的 72% 来自
|
|
67
|
+
这 11 个会话**(最坏的一个 223 步里 168 步静默,末次注入停在 step 54)。机制一行未改,显式配小值
|
|
68
|
+
即可复现旧行为。
|
|
69
|
+
|
|
70
|
+
### 修复:配额邻近上限时的「细缝」静默不可诊断
|
|
71
|
+
|
|
72
|
+
配额逼近上限却未触顶时(实测 `4000 − 3962 = 38` 字符),每条候选都过得了全部门槛,却永远塞不下
|
|
73
|
+
最小正文(提示 120 / 触发 48),于是**永久**静默——而日志里只有一条无量纲的 `budget`。
|
|
74
|
+
现在丢弃会带出 `remaining` / `need` 两个数字。
|
|
75
|
+
|
|
76
|
+
### 修复:注入判据的观测缺口(三处)
|
|
77
|
+
|
|
78
|
+
- 会话限流命中时 `hintCands` 被整个置空,静默步**一个候选都不落盘**(实测 1420 步全空)→
|
|
79
|
+
改为照旧评分、只不注入,影子记录才答得出「不限流这一步会注入什么」。
|
|
80
|
+
- `buildInjection` 的空块早退分支漏掉了 `candidates`,把候选一并丢了。
|
|
81
|
+
- 候选只有门槛结论、没有预算结论 → 每个候选新增 `outcome`
|
|
82
|
+
(`injected` / `budget` / `quota` / `idle` / `gate` / `unscheduled`),与 `decision` 正交;
|
|
83
|
+
影子行另记 `scoreQuery`(**实际**用于评分的 intent + 写目标拼合,与人类消息 `query` 不是一回事)
|
|
84
|
+
与 `dropped`。
|
|
85
|
+
|
|
86
|
+
### 性能:每步评分从 O(C²) 降到 O(C)
|
|
87
|
+
|
|
88
|
+
`idfCoverage` 对**每个候选**都重建一遍整个语料的词集合。真实 store(72 条)实测单步
|
|
89
|
+
`buildInjection` **113 ms → 9 ms**;只看覆盖率那段是 147.5 → 1.3 ms(109×),且逐字段一致
|
|
90
|
+
(已固化为回归用例)。评分在每个 pre-step 都跑,所以这是「每条模型消息」级别的开销。
|
|
91
|
+
|
|
92
|
+
### 修复:IDF 语料与检索语料不同源
|
|
93
|
+
|
|
94
|
+
`store.js` 的 `_rebuildIdf` 手抄了一份 `title×5 + keywords + summary`,而检索侧的
|
|
95
|
+
`weightedFieldText` 是 `title×5 + keywords + summary + **terms** + sourcePath`。于是只出现在
|
|
96
|
+
`terms` 里的词 `df=0` → 被当成极稀有词拿虚高 IDF(`terms` 正是为修「只有前 300 字符可检索」
|
|
97
|
+
加的主检索面)。改为直接调 `makeSearchText`,权重自动对齐。
|
|
98
|
+
|
|
99
|
+
### 观察:注入块抬头标注生产者
|
|
100
|
+
|
|
101
|
+
`[Memory Inject] auto-context` → `[Memory Inject] dsh-project-memory · auto-context`。
|
|
102
|
+
`source.kind` 只有宿主看得到(请求序列化只取 `role` / `content`,provider 对 `.source` 零引用),
|
|
103
|
+
抬头是模型与 GUI 用户唯一能看到生产者的地方。
|
|
104
|
+
|
|
105
|
+
### 工具描述修订
|
|
106
|
+
|
|
107
|
+
- `remember` 指向了一个**不存在**的工具(`search_experience`)→ 改为 `query_memory`。
|
|
108
|
+
- `remember` 与 `save_lesson` 职责相邻却都没说清怎么选 → 两处互相点名(`remember` 写独立的
|
|
109
|
+
经验文件;新建内容优先 `save_lesson`,它带 scope / 合并 / 晋升);`forget` 的参数说明同步。
|
|
110
|
+
- `watch_repo` 不再建议「重载插件」(模型做不到这件事)。
|
|
111
|
+
|
|
112
|
+
### 修复:`writeJsonAtomic` 的两份副本已漂移
|
|
113
|
+
|
|
114
|
+
同一个函数在 `store.js` 与 `insight-store.js` 各有一份。`f9a1389` 给前一份补了「失败即删自己的
|
|
115
|
+
`.tmp`」,v0.5.0 后加的那份没有,写成了「失败后重试同一个 rename」—— 瞬时失败下可能重试成功,
|
|
116
|
+
然后照样抛错。两份的父目录契约也不同(一份要求已存在,一份自建)。
|
|
117
|
+
|
|
118
|
+
后果落在 global insight 文件上:它写失败会永久留下 `<file>.<pid>.tmp`,因为
|
|
119
|
+
`cleanStaleTmp()` 只扫项目 store 目录,够不着 `~/.config/dsh-project-memory/`。
|
|
120
|
+
|
|
121
|
+
- 抽成 `src/util/fs.js` 的单一实现:先建父目录,失败时删掉自己的 `.tmp` 并原样抛出。
|
|
122
|
+
- 两份副本删除;`insight-store.js` 清掉随之无用的 import。
|
|
123
|
+
- `store.js` 两处 `mkdirSync(shards)` 已冗余,一并删除。分片写的 mkdir 次数不变(1 次,
|
|
124
|
+
只是挪进函数内)。
|
|
125
|
+
- 测试:新增 `test/atomic-write.test.mjs`(6 项),含「`shards/` 被删后 store 仍写得进去」。
|
|
126
|
+
|
|
127
|
+
## 0.5.13 (2026-09-28)
|
|
128
|
+
|
|
129
|
+
适配 DSH 0.2.x。`npm test` **539 → 540 项 / 28 个文件**。
|
|
130
|
+
|
|
131
|
+
### 修复:0.2.x 上插件被整个停用
|
|
132
|
+
|
|
133
|
+
DSH 在 profile 组合阶段用运行版本核对插件的 `@deepseek-ai/dsh*` peer 范围,对不上就把该行
|
|
134
|
+
`disabled = true`。本插件三段范围的上限都是 `<0.2.0-0`,`0.2.0-rc.1` 落在范围外。后果不是
|
|
135
|
+
"某个功能失效":`cordis.patch.yml` 插入层从未进入组合树,工具 / 命令 / 面板 / 自动注入全部
|
|
136
|
+
消失,插件管理器也拒绝安装或启用。
|
|
137
|
+
|
|
138
|
+
- `@deepseek-ai/dsh-llm` / `@deepseek-ai/dsh-tools` 的 peer 范围追加 `|| >=0.2.0-rc.1 <0.3.0-0`。
|
|
139
|
+
- devDependencies 从 `0.1.5-rc.1` 升到 `0.2.0-rc.1`(`@deepseek-ai/cordis` → `^4.0.4`),
|
|
140
|
+
类型检查与测试对齐运行版本。
|
|
141
|
+
- 验证:DSH 自身的 `evaluatePluginCompatibility()` 判定为兼容;隔离 `DSH_HOME` 下真实挂载,
|
|
142
|
+
12/12 个工具注册进真实 ToolRuntime。
|
|
143
|
+
|
|
144
|
+
### 修复:`BlockAssembler.message(source)` 在 0.2.0 变为必填
|
|
145
|
+
|
|
146
|
+
签名由 `message(source?)` 收紧为 `message(source)`。`chatText()` 原先无参调用:运行时**不抛错**
|
|
147
|
+
(展开 `undefined` 合法),所以测试全绿、故障静默,但组装出的 assistant 消息丢掉了
|
|
148
|
+
`provider`/`model` 归属。改为传入已解析出的路由,并在 `test/llm-route.test.mjs` 补一项断言
|
|
149
|
+
(曾用无参调用复现为红灯)。
|
|
150
|
+
|
|
151
|
+
### 构建:client 产物不再每次构建都变
|
|
152
|
+
|
|
153
|
+
`tsdown.config.ts` 里 CSS 模块的类名映射直接遍历 lightningcss 的 `exports`,而它由 Rust
|
|
154
|
+
`HashMap` 支撑,hasher 每进程随机播种 —— 同一份 CSS 每次构建的键序都不同。类名与哈希本身稳定,
|
|
155
|
+
键序在运行时也只按键取值、不可观测,但 `client/client.js` 是提交进仓库的产物,后果是每次
|
|
156
|
+
`npm run build:client` 都产生纯键序 diff,真实改动淹没在噪音里。改为按键排序输出后,连续三次
|
|
157
|
+
构建产物逐字节一致(本版 `client/client.js` 因此有一次性的键序重排,无语义变化)。
|
|
158
|
+
|
|
159
|
+
### 其余宿主契约
|
|
160
|
+
|
|
161
|
+
逐包比对 0.1.5 / 0.1.7 → 0.2.0 的公共 API,插件用到的部分(`defineTool`、`ToolRunContext`、
|
|
162
|
+
`agent/pre-step`、`session/event`、`fs/observed`、`commands.register`、client 槽位与
|
|
163
|
+
`inputTriggers`、`sessions.list` 快照形状等)均为纯增量,无需改代码。本版唯一需要改源码的
|
|
164
|
+
破坏点就是上面那条 `BlockAssembler.message`。
|
|
165
|
+
|
|
1
166
|
## 0.5.12 (2026-09-26)
|
|
2
167
|
|
|
3
168
|
本版五个修复 + 一个新增,主题是记忆的驻留、索引归属,以及两处让 TS 增强层失效 / 失真的缺陷。`npm test` **476 → 539 项 / 26 → 28 个文件**。
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ A persistent **project development memory** for [DeepSeek Harness](https://githu
|
|
|
35
35
|
|
|
36
36
|
## Installation
|
|
37
37
|
|
|
38
|
-
The plugin relies
|
|
38
|
+
The plugin relies only on stable public APIs (`defineTool`, `llm.stream`, `Schema`) declared through peerDependencies.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
cd dsh-project-memory && dsh plugin --profile web add . -w
|
|
@@ -49,12 +49,6 @@ The plugin is also published on npm as a scoped package:
|
|
|
49
49
|
dsh plugin --profile web add @yolk_vat-y/dsh-project-memory -w
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
A prebuilt tarball is published with each release, installable without a build step:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
dsh plugin --profile web add /path/to/dsh-project-memory.tgz
|
|
56
|
-
```
|
|
57
|
-
|
|
58
52
|
Each indexed project has its own store at `<root>/.dsh-project-memory/`. Add it to `.gitignore` if it should not be committed.
|
|
59
53
|
|
|
60
54
|
## Usage
|
|
@@ -167,15 +161,15 @@ The workflow panel is collapsible, automatically adapts to dsh and theme plugin
|
|
|
167
161
|
| `reflection.enabled` | false | v0.5 LLM reflection, **draft-only at task level** (fires on task switch-away / archive). `cooldownMs` `1800000`, `maxLessonsPerReflect` `3`, `maxDecisionsPerReflect` `2` |
|
|
168
162
|
| `autoContext.enabled` | true | silent injection wrapper (resident task card + gated items). Inert (full passthrough) until the host exposes a resolvable session cwd; `maxTokens` `400`, `editedMax` `3` (how many recently-written "editing now" files the resident task card shows), `signalMinRatio` `0.5` (a hint must reach half of its layer's top score), `skipEchoSelfTodo` `true` (don't echo the task card back when the model itself maintains the task list with no newer human message; relevant insights still inject), `budgetLog` `off` (budget-drop audit on stderr: `off` silent / `once` at most one line per session / `all` one line per changed dropped set), `reinjectItemsAfter` `0` (cooldown, in pre-steps, before the same insight may be injected again), `rootNotice` `true` (when the memory root is inferred from a marker-less working directory, tell the model once where memory lives and how to change it) |
|
|
169
163
|
| `autoContext.gateCooldownSteps` | 2 | **admission knobs.** Minimum number of pre-steps between two *item* injections (the resident task card is exempt — it is a state snapshot and should update when it changes). This is the main "don't inject often" dial |
|
|
170
|
-
| `autoContext.maxItemsPerSession` |
|
|
171
|
-
| `autoContext.maxItemCharsPerSession` |
|
|
164
|
+
| `autoContext.maxItemsPerSession` | 60 | **runaway fuse, not a throttle** — throttling is done by `maxTokens` (per step) and `gateCooldownSteps`. It is a hard per-session ceiling: once reached, the item channel stays silent for the rest of the session. The default sat at 12 until 0.5.14, which real usage did reach (longest observed session: 35 items), permanently blinding the tail of long sessions. Set it lower to reproduce the old behaviour |
|
|
165
|
+
| `autoContext.maxItemCharsPerSession` | 24000 | same, in characters |
|
|
172
166
|
| `autoContext.hintMinCoverage` | 0.45 | **absolute** floor for the statistical (hint) channel: IDF-weighted share of the query's information mass the entry covers. A ratio-only threshold cannot tell signal from "best of a bad lot" (`relative:1.00` on an unrelated entry). Raised from 0.30 in 0.5.8: on a real 43-entry store the control scenario injected 3 unrelated hints at cov 0.32–0.35, because a same-corpus store flattens IDF |
|
|
173
167
|
| `autoContext.hintMinMatched` | 2 | a hint must share at least this many terms with the query — one generic word ("plugin") is not evidence |
|
|
174
168
|
| `autoContext.hintMinSupport` | 0.15 | channel-level silence: if less than this share of the query's terms exist anywhere in the corpus, the hint channel says nothing this round — a long sentence that happens to share one word otherwise reports `cov:1.00` |
|
|
175
169
|
| `autoContext.legacyScope` | `filter` | how to treat a legacy `trigger.scope`: `filter` keeps the old semantics, `ignore` drops it. `npm run selfcheck:triggers` reports entries whose scope values cannot intersect the project tag space |
|
|
176
170
|
| `autoContext.auditLog` | true | append one JSONL line per **actual** injection to `<root>/.dsh-project-memory/injection-audit.jsonl` (what was injected, why it matched, what was dropped, session budget snapshot); rotates to `.1` past `auditMaxBytes` (`262144`). Silent on any I/O error — never affects the host request |
|
|
177
|
-
| `autoContext.shadowLog` | true | append one JSONL line **per step** (including steps that injected nothing) to `admission-shadow.jsonl`:
|
|
178
|
-
| `autoContext.shadowMaxBytes` |
|
|
171
|
+
| `autoContext.shadowLog` | true | append one JSONL line **per step** (including steps that injected nothing) to `admission-shadow.jsonl`: the scored candidates near the head of the ranking (`rel` / `coverage` / `matched` / `decision` / `outcome`) plus the step's `query` / `scoreQuery` / `ops` / `writes`. This is what makes a threshold change answerable offline on real history (`decision` shows which gate rejected each candidate, `outcome` what the budget did with it). Rotates past `shadowMaxBytes` (`524288`), keeping one `.1` generation, so the per-project log ceiling is `2 × shadowMaxBytes + 2 × auditMaxBytes` ≈ 1.5 MB. Disk only — never enters the prompt, costs no tokens |
|
|
172
|
+
| `autoContext.shadowMaxBytes` | 524288 | rotation cap for `admission-shadow.jsonl` (one `.1` generation is kept) |
|
|
179
173
|
|
|
180
174
|
### Injection admission (why it stays quiet)
|
|
181
175
|
|
|
@@ -304,7 +298,7 @@ These commands are for **maintaining the plugin code** — regular users do not
|
|
|
304
298
|
|
|
305
299
|
```bash
|
|
306
300
|
npm install
|
|
307
|
-
npm test #
|
|
301
|
+
npm test # 561 tests (216 core + 16 TaskBridge + 12 insight-store + 9 insight-actions + 8 doc-index + 7 auto-inject + 10 host-contract + 5 reflection + 5 llm-route + 2 client-hints + 10 recall + 15 readiness + 7 insight-derive + 7 readiness-eval + 6 ops + 12 injection-audit + 10 injection-budget + 6 injection-scenarios + 18 bugfix-0.5.7 + 3 client-icons + 10 client-slash + 5 client-toolview + 5 workflow-command + 7 client-session-id + 7 task-view + 79 root-guards + 9 store-gitignore + 6 atomic-write + 22 store-cache + 27 enhancer)
|
|
308
302
|
npm run eval:injection # scenario P/R on the synthetic pool: 14/14 hits, 0 false positives, control group clean
|
|
309
303
|
npm run eval:injection -- --store .dsh-project-memory/insights.json # replay on YOUR store; control group is a hard gate
|
|
310
304
|
npm run selfcheck:triggers # which entries can still push, which declarations are dead (reads your local store)
|
package/README.zh-CN.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
## 安装
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
插件只依赖通过 peerDependencies 声明的稳定公共 API(`defineTool`、`llm.stream`、`Schema`)。
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
cd dsh-project-memory && dsh plugin --profile web add . -w
|
|
@@ -48,12 +48,6 @@ cd dsh-project-memory && dsh plugin --profile web add . -w
|
|
|
48
48
|
dsh plugin --profile web add @yolk_vat-y/dsh-project-memory -w
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
每个版本会附带预构建 tarball,无需构建步骤即可安装:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
dsh plugin --profile web add /path/to/dsh-project-memory.tgz
|
|
55
|
-
```
|
|
56
|
-
|
|
57
51
|
每个被索引的项目在 `<root>/.dsh-project-memory/` 下有独立存储。如无需入库,可加入 `.gitignore`。
|
|
58
52
|
|
|
59
53
|
## 用法
|
|
@@ -164,15 +158,15 @@ TaskPanel (Container)
|
|
|
164
158
|
| `reflection.enabled` | false | v0.5 LLM 反思,**只写任务级草稿**(触发于任务切走/归档)。`cooldownMs` `1800000`、`maxLessonsPerReflect` `3`、`maxDecisionsPerReflect` `2` |
|
|
165
159
|
| `autoContext.enabled` | true | v0.5 静默注入包装(entry 常驻块 + relevance)。宿主无法解析会话 cwd 时完全透传(零副作用);`maxTokens` `400`、`editedMax` `3`(resident 任务卡显示最近"编辑中"文件数)、`signalMinRatio` `0.5`(提示至少要达到该层最高分的一半)、`skipEchoSelfTodo` `true`(模型自己写/维护任务清单后、无新人类消息时不回声任务卡,省 token;相关 insights 仍注入)、`budgetLog` `off`(预算丢弃审计写到 stderr:`off` 静默 / `once` 每会话最多一行 / `all` 丢弃组合每变化一次一行。注入按优先级排程,预算不够时丢掉低优先级条目属于**正常降级而非故障**,所以默认不占用用户终端)、`reinjectItemsAfter` `0`(同一条 insight 重复注入的冷却步数;`0` = 正文没变就不在本会话内再注入——注入消息留在会话历史里,重发只是重复占位)、`rootNotice` `true`(记忆根是从无标记的工作目录**推定**出来时,向模型通告一次根在哪、怎么改) |
|
|
166
160
|
| `autoContext.gateCooldownSteps` | 2 | **准入旋钮**:两次*条目*注入之间至少隔几步(常驻任务卡不受限——它是状态快照,内容变了就该更新)。这是"别频繁注入"的主旋钮 |
|
|
167
|
-
| `autoContext.maxItemsPerSession` |
|
|
168
|
-
| `autoContext.maxItemCharsPerSession` |
|
|
161
|
+
| `autoContext.maxItemsPerSession` | 60 | **runaway 保险丝,不是节流阀** —— 节流由 `maxTokens`(单轮)与 `gateCooldownSteps` 负责。它是每会话硬上限:一旦触顶,本会话余下部分条目通道持续沉默。0.5.14 之前默认 12,而真实用量确实到得了(实测最长会话 35 条),于是长会话的后段被永久致盲。配小值可复现旧行为 |
|
|
162
|
+
| `autoContext.maxItemCharsPerSession` | 24000 | 同上,按字符计 |
|
|
169
163
|
| `autoContext.hintMinCoverage` | 0.45 | 提示通道的**绝对**下限:条目覆盖了查询多少 IDF 加权信息量。只用相对阈值分不出"有信号"和"矮子里拔将军"(实测无关条目也拿 `relative:1.00`)。0.5.8 从 0.30 上调:真实 43 条 store 上对照组以 cov 0.32~0.35 注入了 3 条无关提示——同源语料会把 IDF 分辨力拉平 |
|
|
170
164
|
| `autoContext.hintMinMatched` | 2 | 提示还必须至少共享这么多个词:单个通用词("插件")不构成证据 |
|
|
171
165
|
| `autoContext.hintMinSupport` | 0.15 | 通道级沉默:查询里能在语料中找到对应的词占比低于此值时,提示通道本轮整体不出声——否则一句只碰巧共享一个词的长句子会报出 `cov:1.00` |
|
|
172
166
|
| `autoContext.legacyScope` | `filter` | 旧 `trigger.scope` 的处理:`filter` 保留旧语义,`ignore` 丢弃。`npm run selfcheck:triggers` 会列出 scope 值与项目画像 tag 空间不可能相交的条目 |
|
|
173
167
|
| `autoContext.auditLog` | true | 每次**真实**注入往 `<root>/.dsh-project-memory/injection-audit.jsonl` 追加一行(注入了什么、为什么命中、丢了什么、会话额度快照);超过 `auditMaxBytes`(`262144`)轮转 `.1`。任何 IO 失败都静默,绝不影响宿主请求 |
|
|
174
|
-
| `autoContext.shadowLog` | true | **每步**(含什么都没注入的步)往 `admission-shadow.jsonl`
|
|
175
|
-
| `autoContext.shadowMaxBytes` |
|
|
168
|
+
| `autoContext.shadowLog` | true | **每步**(含什么都没注入的步)往 `admission-shadow.jsonl` 追加一行:排名靠前的被评分候选(`rel` / `coverage` / `matched` / `decision` / `outcome`)+ 场景(`query` / `scoreQuery` / `ops` / `writes`)。它让"换个阈值会怎样"可以在真实历史上离线回答(`decision` 指出每条候选卡在哪一关,`outcome` 指出预算拿它怎么办)。超过 `shadowMaxBytes`(`524288`)轮转,只保留一代 `.1`,所以单项目日志硬上限 ≈ `2 × shadowMaxBytes + 2 × auditMaxBytes` ≈ 1.5 MB。只写盘,不进 prompt、不花 token |
|
|
169
|
+
| `autoContext.shadowMaxBytes` | 524288 | `admission-shadow.jsonl` 的轮转上限(保留一代 `.1`) |
|
|
176
170
|
|
|
177
171
|
### 注入的准入化(为什么它保持安静)
|
|
178
172
|
|
|
@@ -301,7 +295,7 @@ node scripts/bench.mjs /你的/项目路径 [--json] [--samples 100] [--no-pdf]
|
|
|
301
295
|
|
|
302
296
|
```bash
|
|
303
297
|
npm install
|
|
304
|
-
npm test #
|
|
298
|
+
npm test # 561 项测试(核心 216 + TaskBridge 16 + insight-store 12 + insight-actions 9 + doc-index 8 + auto-inject 7 + host-contract 10 + reflection 5 + llm-route 5 + client-hints 2 + recall 10 + readiness 15 + insight-derive 7 + readiness-eval 7 + ops 6 + injection-audit 12 + injection-budget 10 + injection-scenarios 6 + bugfix-0.5.7 18 + client-icons 3 + client-slash 10 + client-toolview 5 + workflow-command 5 + client-session-id 7 + task-view 7 + root-guards 79 + store-gitignore 9 + atomic-write 6 + store-cache 22 + enhancer 27)
|
|
305
299
|
npm run eval:injection # 合成池上的场景 P/R:命中 14/14、假阳性 0、对照组零注入
|
|
306
300
|
npm run eval:injection -- --store .dsh-project-memory/insights.json # 用你自己的 store 重放;对照组是硬闸门
|
|
307
301
|
npm run selfcheck:triggers # 哪些条目还推得动、哪些声明是死的(读你本地的 store)
|