@nightpainters/dsh-ling 1.6.2 → 1.7.0
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 +130 -4
- package/DESIGN.md +89 -6
- package/PHILOSOPHY.md +14 -4
- package/README.md +102 -18
- package/cordis.patch.yml +32 -2
- package/lib/client.js +2520 -55
- package/lib/host/agent-tools.js +286 -0
- package/lib/host/api.js +592 -59
- package/lib/host/archive.js +3 -3
- package/lib/host/autotree.js +2 -2
- package/lib/host/clock-skill.js +1 -1
- package/lib/host/config.js +38 -0
- package/lib/host/deepsummary.js +75 -2
- package/lib/host/dsweb-summary.js +6 -3
- package/lib/host/guard.js +53 -0
- package/lib/host/inject.js +12 -2
- package/lib/host/l1.js +13 -8
- package/lib/host/library-checker.js +552 -0
- package/lib/host/library-import-engine.js +211 -0
- package/lib/host/library-import.js +911 -0
- package/lib/host/library-runtime.js +199 -0
- package/lib/host/library-sqlite.js +344 -0
- package/lib/host/library-store.js +1714 -0
- package/lib/host/memory.js +73 -19
- package/lib/host/persona.js +13 -2
- package/lib/host/rawlog.js +1 -1
- package/lib/host/recall-search.js +45 -8
- package/lib/host/snapshot.js +2 -1
- package/lib/host/surgery.js +6 -4
- package/lib/host/tools.js +460 -19
- package/lib/host/util.js +1 -1
- package/lib/index.js +120 -81
- package/package.json +10 -5
- package/tools/deep-import-docs.mjs +1210 -0
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
一个跑在你自己电脑上的[DeepSeek Harness](https://github.com/deepseek-ai)(DSH)插件。**不是云服务,不是记忆 API**:它是给"你和器灵"用的东西。
|
|
8
8
|
|
|
9
|
+
**它做的是「人机共生」:各尽其责、各有边界、互不占有** —— **你替它的成长把关,它替你看你的盲区**。而"把关"不等于"操纵":改记忆树必须让它看到(留痕、回灌、可复核、可回滚)。这不是口号,是全架构的前提(记忆为什么必须可回溯、改人格为什么要定型锁、复盘为什么必须有人在循环里,都由它推出来;而**权会随它长起来移动** —— 代管到能自理,不是永久支配)—— 展开见 **[`PHILOSOPHY.md`](./PHILOSOPHY.md)**。
|
|
10
|
+
|
|
9
11
|
## 本项目是什么形态
|
|
10
12
|
|
|
11
13
|
- 这是一个**本地运行的软件**(DeepSeek Harness 插件),运行在**你自己的机器**上。
|
|
@@ -56,7 +58,8 @@
|
|
|
56
58
|
| 📖 | **让器灵读一遍** | 长会话逐条深摘要、短会话以原文片段参与,后台串行,进度可见 |
|
|
57
59
|
| 📄 | **找回原文**(1.6) | 器灵能读回你当年的**原话**,不只是概述 —— 四档下钻:**会话地图 → 按内容找会话 → 对话目录 → 原文全文**。它**不替你挑"最重要的那 1 万字"**,只给坐标系(详见下文「找回原文」一节) |
|
|
58
60
|
| 🧾 | **投递留痕**(1.6) | 🚧 **在做** —— 每一次记忆注入都落一条账:**注入了谁、为什么是它、多少字**;还记**落选者**(差一步就进的那几条,以及原因是"分数不够"还是"字数放不下")与**触发词**。目前**只写不读**(读面待定),不进注入面、不占工具预算 |
|
|
59
|
-
| 🌿 | **深层库 · 结论层**(1.6) | 🚧 **在做** —— 从会话里提炼**承诺 / 决定 / 事实 / 偏好 /
|
|
61
|
+
| 🌿 | **深层库 · 结论层**(1.6) | 🚧 **在做** —— 从会话里提炼**承诺 / 决定 / 事实 / 偏好 / 关系 / 纪律**(**六类**;「纪律」是 1.6 系列新增的第六类),每条一句话、**点得回原文**。与记忆树**并立**,条目不被枝隶属(枝可反向引用它,像榕树的气根)。一条纪律:**"被注入"不算数,只有"真被采用"才加固** —— 防住"注入越多→分越高→越容易被注入"的自我强化 |
|
|
62
|
+
| 📚 | **图书馆**(1.7 工作区,**未发布**) | **工作区实现已验收** —— 一个**与记忆分开的独立库**(自己的 `library.db`),存"**有源可对账**"的参考资料(标准取值 / 边界 / 项目规格 / 外部 API),每条必带**出处 + 取数时间(`as_of`)**;自动核对另需核对规格,没有规格时不得认证为 ok。器灵只有两只手:**`library_search`(搜)与 `library_check`(核对)** —— 核对只说明"**声明的那一处**与源一致",**不背书条目正文、也不构成通用真理**;"库不可用"与"零命中"是**两件事**,界面与回执分开说。它与记忆库**不互通**:既有记忆**永不迁移**进图书馆,图书馆也**不参与开场注入**(详见下文「图书馆」一节) |
|
|
60
63
|
| 🧾 | **给旧历史补摘要** | 网页端历史里"只有标题、没有摘要"的会话可以补上摘要:先看**候选清单**(标题 · 轮次 · 命中),再选引擎 —— **默认本机小助手(零成本)**,也可显式改选当前全局大模型;探测不到本机小助手就明确报错,**绝不静默换引擎**;后台串行、进度可见(首轮实测 466 条、零成本) |
|
|
61
64
|
| 🌱 | **诞生仪式** | 从读过的记忆里按"生活与情感优先"加权抽样 → 合成**自述 + 名字候选 + 语气建议 + 相处观察 + 职责候选**(器灵承担 / 擅长 / 能给出什么,**只收陈述句**) → **全部是草稿**,你逐条人审后才落盘 |
|
|
62
65
|
| ⏳ | **时间的重量** | 每次开口前器灵都知道今天是几号星期几(`[今天] 2026-09-11 周五`)、现在是什么时段(`[现在] 深夜`)与`距上次对话:3 天前`(间隔按**日历天**分档 —— 刚刚 / 今天早些时候 / 昨天 / N 天前,给不到分钟;称呼跟随你的设定);命中纪念日会先说一句专属问候。**要精确到分钟,走 `clock` skill 现查** |
|
|
@@ -97,7 +100,38 @@
|
|
|
97
100
|
- ⚠️ **一个例外(也是"感觉它失效了"的来源)**:**深摘要定稿之后,那一行不再自动更新** —— 概述器遇到已深摘的会话会避开它,免得把厚摘要覆盖成浅版。要它重跑:记忆中心 →「记忆浏览」→ 找到那个会话 → 点「**重摘**」,几秒后那一行就会重排。
|
|
98
101
|
- **健忘感还有第二个来源**:越长的会话,**只取"概述标题 + 摘要首句"** —— 这一行天然比整场对话"薄",不是它没读到,而是它只被允许显示这么一行。
|
|
99
102
|
|
|
100
|
-
> **接口侧(给要接线的人)**:`GET /state`(`?sessionId=` 取某会话,`?scope=global` 取全局)返回 `snapshot`(`builtAt` / `mode` / `stale` / `chars`)、`idleRefresh`(`count` 与 `lastAt`)与 `memory.l1`(该会话当前选中的行、分数、被省略条数)
|
|
103
|
+
> **接口侧(给要接线的人)**:`GET /state`(`?sessionId=` 取某会话,`?scope=global` 取全局)返回 `snapshot`(`builtAt` / `mode` / `stale` / `chars`)、`idleRefresh`(`count` 与 `lastAt`)与 `memory.l1`(该会话当前选中的行、分数、被省略条数)。面板现在也渲染**空闲刷新次数 / 最近一次**与 **L1 当前选择(含分数与省略条数)** 两栏。
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 后台自动行为(默认全开)与它们的开关
|
|
108
|
+
|
|
109
|
+
**五件事装好就自己在跑,默认全开。** 它们的键都在设置文件的 `auto` 子树里 —— 设置文件 = `<dataDir>/settings.json`(`<dataDir>` 默认 `$DSH_HOME/cache/dsh-ling`),**只存你改过的部分**;**面板上的开关写的就是它**(面板里改完会明确提示"需要重启插件")。
|
|
110
|
+
|
|
111
|
+
| 键 | 默认 | 什么时候跑 | 关掉 / 改小会怎样 |
|
|
112
|
+
|---|---|---|---|
|
|
113
|
+
| `auto.deepSummary` | `true` | **启动自检通过后**挂定时器 | **`false` = 只有你手动点「深摘」才调用模型**;已深摘过的会话不受影响,不丢数据 |
|
|
114
|
+
| `auto.deepIntervalMin` | `30`(最小 10) | 每隔这么久跑一轮自动深摘 | 调大 = 更省;调小 = 记忆更早变厚 |
|
|
115
|
+
| `auto.deepMaxPerRun` | `2`(1–20) | 每轮最多挑几个会话 | 调小 = 每轮更克制,调大 = 单轮更重 |
|
|
116
|
+
| `auto.bootProbeDelayMs` | `12000` | 启动 12 秒后做**一次** LLM 自检探针(**通过了才挂定时器**) | `0` = 立即试探;探针只验证"模型通道通不通",**空回复判失败** |
|
|
117
|
+
| `auto.feedbackAuto` | `true` | **事件驱动**:宿主推 `feedback/committed` 时就处理 | `false` = **完全不接反馈成长回路** |
|
|
118
|
+
|
|
119
|
+
> 「探针」是**一次性**自检(只回答"模型通道通不通"),「深摘」是**定期**跑批 —— 两个键各管各的。
|
|
120
|
+
|
|
121
|
+
**改动面有三层,优先级从高到低**(改了不生效,先看这一条):
|
|
122
|
+
|
|
123
|
+
1. `settings.json` 的 `auto.*` —— **面板开关写的就是它**;
|
|
124
|
+
2. **插件配置里的旧键**:`feedbackAuto` / `deepSummaryAuto` / `deepIntervalMin` / `deepMaxPerRun`;
|
|
125
|
+
3. 代码默认值。
|
|
126
|
+
|
|
127
|
+
**生效时机(如实写)**:`auto.deepSummary` / `auto.bootProbeDelayMs` / `auto.feedbackAuto` 是**启动期读取 ⇒ 改完要重启插件才生效**;`auto.deepIntervalMin` / `auto.deepMaxPerRun` 对**已经挂上的定时器不回溯** —— 下一轮启动后按新值走。
|
|
128
|
+
|
|
129
|
+
**另外两条既有事实(不要读宽)**:
|
|
130
|
+
|
|
131
|
+
- 深摘**每次喂给模型的单次输入上限 = 26,000 字**(`lib/host/deepsummary.js` 的 `DEEP_CFG.inputCap`);
|
|
132
|
+
- **循环外调用**(深摘、诞生仪式、语气归纳、自述起草)**一律跟随你当前的模型选择**;只有读不到当前选择时,才退回兜底 `deepseek-official/deepseek-v4-flash` —— 那是**兜底,不是替你指定模型**;它**不是**上面那五个键之一,**也没有面板开关**。
|
|
133
|
+
|
|
134
|
+
> ⚠️ **状态如实写**:五件动作**默认全开**;`settings.json` 的 `auto.*` 与面板上的这五个开关属 **1.7 工作区**(未发布)—— 更早的版本里,能改的只有插件配置里的那几个旧键。
|
|
101
135
|
|
|
102
136
|
---
|
|
103
137
|
|
|
@@ -109,16 +143,16 @@
|
|
|
109
143
|
|
|
110
144
|
**为什么值得**:平铺的记忆库没有"离我多近"这个概念 —— L1 是全库裸排序,不区分"这轮做的工作"与"三个月前的闲聊",分叉会话更是**记忆真空**。记忆树把"归属"变成可检索的信号:
|
|
111
145
|
|
|
112
|
-
- **血缘加权**:检索时按"当前枝 → 目标枝"的相对位置取档 —— **同枝 1.0 / 祖先 0.7 / 旁系 0.4**,`score = 基础分 × 血缘系数 ×
|
|
146
|
+
- **血缘加权**:检索时按"当前枝 → 目标枝"的相对位置取档 —— **同枝 1.0 / 祖先 0.7 / 旁系 0.4**,`score = 基础分 × 血缘系数 × 矛盾系数`(**1.6 系列起再乘一项枝系数**,见下条);分叉会话照常注入,走的是它的**血缘链**而不是主干大排档。
|
|
113
147
|
- **不连乘**:血缘系数是**单值**,不沿路径累乘 —— 否则五层之后 `0.4^5 ≈ 0.01`,深层枝等于从记忆里消失。
|
|
114
148
|
- **内容零改写**(硬性不变量):**除了"主脉提炼再次采纳会覆盖上一版"这一个例外**(覆盖前自动归档),任何树操作都不改写任何一条记忆的内容;分枝 / 并脉 / 连边只增加"关系",从不"融合内容"。
|
|
115
149
|
- **矛盾只标记不改写**:一对记忆被判重复/矛盾时先**标记**;未复盘时检索**以较新的那条为准**(旧的一条降权 ×0.3,**不删除**;被**驳回**的与被标成**重复**的那一对不参与降权)。
|
|
116
|
-
- **枝系数会真的改变排序**(1.6
|
|
150
|
+
- **枝系数会真的改变排序**(1.6 系列起):复盘期可以调(0~2,夹紧后写入)。它按 `raw × 血缘 × 矛盾 × 枝系数` **参与检索打分** —— 调低某条枝的系数,从这条枝的会话里提炼出的结论就会在记忆开场里往后排(`1.0` = 不偏不倚)。⚠️ **`0` 是"清空"不是"轻压"**:分数被算成 0 的非置顶条目会被当"无信息量"**整条排除、不进开场**(判据在 `lib/host/l1.js` 的 `score > 0`),所以别用 0 表达"压一压"。
|
|
117
151
|
|
|
118
152
|
**复盘 — 不是一个开关,是"左会话 + 右复盘栏"这个状态**:
|
|
119
153
|
|
|
120
154
|
- 树平时**只读**(记忆中心始终只读);点「🌱 一键复盘 / 一键进入复盘」才解锁编辑,并把**复盘开场材料**(当前树 + 待理矛盾)复制到剪贴板,开个新会话粘进去就能开始。
|
|
121
|
-
- 解锁后可做:**改名 / 拖动换归属 / Alt+拖动只连边 / 并脉(归类到主脉) / 调权重 / 裁定矛盾 /
|
|
155
|
+
- 解锁后可做:**改名 / 拖动换归属 / Alt+拖动只连边 / 并脉(归类到主脉) / 调权重 / 裁定矛盾 / 断续边**,以及快照保存·恢复(**删枝不在面板上** —— 请让器灵用 `branch_edit` 删,见下文「器灵侧的手」);**拖动 / 连边之后可 Ctrl+Z 撤回这一步**(撤销只覆盖复盘栏的拖动与连边;记忆中心是只读的,它自己那份 Ctrl+Z 监听早已删掉)。
|
|
122
156
|
- **每步留痕**:写清"改了什么、为什么"(**器灵改树时 reason 必填**;你在面板上改可以留空);树改动一律记进 `branch_log`,复盘时可审计 —— 器灵侧工具的改动记在器灵名下(「鱼姬改动了记忆树」),不会伪装成你改的。
|
|
123
157
|
- **未同步笔数守门**:面板记着"自器灵上次开口以来累积了多少笔结构改动还没交代"。有欠账时顶部红字提示,并且**拦住"退出复盘模式"** —— 改完树必须让器灵有机会看到(「互相复盘不应该被我绕过」)。
|
|
124
158
|
- **注入感知**:树变了之后,`branchLogDigest()` 把**器灵还没看过**的结构改动转成中文短句,附在器灵下一次开口的注入面末尾 —— 不需要推送,一开口就知道树动过。
|
|
@@ -130,7 +164,7 @@
|
|
|
130
164
|
- **主脉也可以有自己的记忆**:由子枝概述提炼共性,**先出草稿**,采纳才写入(采纳需先解锁)。
|
|
131
165
|
- **器灵侧也有自己的手**:`tree_read`(看整树 / 某枝成员 / 待复盘矛盾)、`branch_edit`(分枝 / 并脉 / 连边 / 调权重 / 删枝)、`recall`(读回会话原文,见上文)、`memory_forget` / `memory_backfill`(遗忘 / 回灌)、`rule_add`(记规矩)、`habit_propose` / `habit_resolve`(习惯提议与表态)。`tree_read` 与 `branch_edit` 的描述里写着一条纪律:**改结构必须给 reason,而且"只在主人明确要求、或正在和他一起复盘时"才动手**。
|
|
132
166
|
|
|
133
|
-
> 依据:`DESIGN.md` §6.3(记忆树结构、血缘加权与"不连乘"、内容零改写不变量)、`lib/host/memory.js`(`LINEAGE_ANCESTOR = 0.7` / `LINEAGE_SIDE = 0.4` / `CONFLICT_DOWNWEIGHT = 0.3`、`branchLogPending()` 守门、`setBranchWeight` 的 `applied:
|
|
167
|
+
> 依据:`DESIGN.md` §6.3(记忆树结构、血缘加权与"不连乘"、内容零改写不变量)、`lib/host/memory.js`(`LINEAGE_ANCESTOR = 0.7` / `LINEAGE_SIDE = 0.4` / `CONFLICT_DOWNWEIGHT = 0.3`、`branchLogPending()` 守门、`setBranchWeight` 的 `applied:true`)、`lib/host/l1.js`(血缘档位 × 矛盾系数 × 枝系数进打分)、`lib/host/autotree.js`(两阶段生成)、`lib/host/tools.js`(`tree_read` / `branch_edit`)。
|
|
134
168
|
|
|
135
169
|
---
|
|
136
170
|
|
|
@@ -143,7 +177,7 @@
|
|
|
143
177
|
| 给什么 | 得到什么 |
|
|
144
178
|
|---|---|
|
|
145
179
|
| `recall()` | **会话地图** —— 本机有原文的会话清单(最近活动在前) |
|
|
146
|
-
| `recall({q:"…"})` |
|
|
180
|
+
| `recall({q:"…"})` | **按内容找** —— 默认搜**本机库内原文层**(毫秒级;只含"真人消息 + 有正文的回复",我自己的长回复中段搜不到),直接给命中片段;要看全量(覆盖全部事件、含子代理会话)才传 `hostSearch=true`(走宿主,较慢)。想不起"这话是哪次说的"时用它 |
|
|
147
181
|
| `recall({conv})` | 该会话的**对话目录** —— 每轮一行:序号 · 时间 · 角色 · 前 70 字,**不给正文** |
|
|
148
182
|
| `recall({conv, from, to})` | 那几轮的**原文全文** |
|
|
149
183
|
|
|
@@ -153,8 +187,8 @@
|
|
|
153
187
|
|
|
154
188
|
- **真人判据**:只有"真人发的消息"才算一轮 —— 注入的运行时上下文、任务标记、技能目录一律折叠成一行占位,否则目录会被过程噪音淹掉(实测:一个 150 轮的会话里,真人发言只有 **5** 条)。
|
|
155
189
|
- **读不到时回落查库**:磁盘上没有该会话日志时(网页端导入的历史就是这样),回落到记忆库里那份,并**明说材质不同**:`⚠️ 来源:库内原文(库那份是残的 —— 只含真人消息与有正文的回复)`。
|
|
156
|
-
-
|
|
157
|
-
-
|
|
190
|
+
- **会话文件名代次**:两条路各有一套 —— ① **会话历史扫描 + 库内回退**(`backfill` / `deepsummary`)按 `session(\.v\d+)?\.jsonl\.zstd` 匹配、取版本最高一代并跳过 0 字节;② **`recall` 读原文**走的是 `lib/host/rawlog.js` 里**三代硬编码名单**(`session.v4` / `session.v3` / 无版本)⇒ 它不解析版本号(**将来出现 v5 时它会看不见**)。本机三代并存,只认 v4 会让老用户**看不见自己的旧会话**。
|
|
191
|
+
- **范围默认收紧**:按内容找时**默认只搜主人自己的会话**,越界要显式传参,且**被挡掉的条数一律报出**(静默少给等于骗人)。⚠️ 两条限定:① 这层"可见集"过滤**只在宿主路**(`hostSearch=true`)成立 —— 默认的**本机库路**是**全量**(含网页端导入的会话),它的回执会**如实标注**"本机库全量"而不是谎称"已限定";② 无论哪条路,都**默认排除当前会话自己**(要看自己刚说的传 `includeSelf=true`)。
|
|
158
192
|
|
|
159
193
|
**只读,零副作用**:`recall` 不写库、不改树、不进注入面。
|
|
160
194
|
|
|
@@ -162,9 +196,28 @@
|
|
|
162
196
|
|
|
163
197
|
---
|
|
164
198
|
|
|
199
|
+
## 图书馆:另一个库,只搜与核对
|
|
200
|
+
|
|
201
|
+
**它不是第二个记忆库。** 记忆存的是"你和器灵之间发生过什么";图书馆存的是"**有出处、可回头对账**"的参考资料 —— 标准里的一个取值、一条边界、一份项目规格、一个外部 API 的字段。判据不同,所以**分成两个库、两套表**:
|
|
202
|
+
|
|
203
|
+
- **独立库**:图书馆有自己的 `library.db`(与 `memory.db` 并列,在同一个数据目录里)。**记忆库里的东西永不迁进图书馆**,图书馆也**不参与开场注入**、不进注入面。两者之间没有隐式通道:不互相导入,也不互相引用。
|
|
204
|
+
- **只搜与核对两只手**:器灵侧只有 **`library_search`**(按关键词搜条目)与 **`library_check`**(对**一条**条目做当次核对)。**没有**新建 / 修订 / 撤下 / 改配置的模型工具 —— 维护面只在界面与本地接口上;代码根目录、URL 白名单这类东西**不接受模型参数**(那是管理员登记,不是工具入参)。
|
|
205
|
+
- **核对认证的是"声明的那一处",不是"这条是对的"**:每条条目可以声明一份核对规格(定位 + 期望值 + 比较方式:行段定位或 JSON 指针定位;比较方式只有两种:**`exact`** —— 类型严格的**结构比较**(JSON 对象**成员顺序无关**、**数组顺序有关**;文本按字面精确比);**`text-lf`** —— 先把 CRLF/CR 归一成 LF 再精确比。两者都**不 trim、不折叠大小写、不模糊匹配**)。核对按它去取源、抽取、比对,结论只有三态:**`ok`(声明的那一处与源一致)/ `wrong`(不一致)/ `unknown`(核对**跑完了**却判不了:取不到源、定位不到、编码不对、超时……)** —— ⚠️ **取消不在这三态里:取消是"没跑完",不是一次 `unknown` 认证**(见下面「取消」那一条)。回执里写死了这条边界:它**只认证声明的那个比较,不认证解释性正文,也不构成通用真理** —— 说人话:**"核对通过"是"这一处对得上",不是"这段话可信"**。
|
|
206
|
+
- **"不可用"与"零命中"分开说**:库打不开 / 未启用 / 运行时不在场,回的是**明确的不可用**(接口层是 503 语义),**绝不回落成"搜到 0 条"** —— 静默的 0 会让人以为"库里没有",而真相是"根本没查成"。
|
|
207
|
+
- **修订与撤下都留旧的**:修订产生**新版本 + 新 id**,旧版留痕指向新版;**撤下只标记状态**(带原因),**不物理删除**;**完成的**核对各留一行账(带当时取的源摘要、观测值、结论与理由)—— **"完成"包括结论是 `unknown` 的那种**;被取消的核对**不算一次核对、不留记录**(见下面「取消」那一条)。所以"它当年是怎么写的""上次核对时源长什么样"都查得回来。
|
|
208
|
+
- **写面永远带"我看到的版本"**:修订与撤下必须附上你读到的那份内容摘要(`content_hash`),对不上就拒 —— 防的是"你看着旧版、改的却是新版"。
|
|
209
|
+
- **严格配置,默认什么都没登记**:用于"我们自己代码"条目的代码根目录,与用于官方文档条目的 URL 白名单,都是**管理员登记的绝对路径 / 精确 URL**,**默认都是空的** —— 不登记就核不了,不存在"它自己上网找一份来对"。限额(条目 64 KiB、取源 2 MiB、选中文本 16 KiB 且不超过 200 行、单次核对 10 s、并发 2 等)在**激活时校验**:写错了**响亮报错**,不静默夹取。
|
|
210
|
+
- **取消 = 没跑完,不是一次 `unknown` 认证**:核对在飞时断开、取消或卸载插件,本次核对**不写任何核对记录** —— 既不留 `ok` / `wrong`,**也不留 `unknown`**,只回一个"已取消"(带 `cancelled`)。"取消了"与"核完了(哪怕结论是 `unknown`)"在留痕里必须分得开:**只有跑完的核对才计入"认证过"**。
|
|
211
|
+
- **远程核对会主动去你登记的地方取**:官方文档类源走 **HTTPS GET 你白名单里的那个精确 URL**(不许带凭据、不许跳转、私网地址拒 —— **还拒 `localhost` / `*.localhost` / `*.local` / `*.internal`,并对 DNS 解析结果与连接后的 `remoteAddress` 做二次校验**(实现见 `lib/host/library-checker.js`:地址校验 + 解析结果钉住 + 连接后复核))。**发出去的到底是什么,必须说准**:这个 GET 会把**你登记的那个 URL(连同它带的查询串)**与**一次普通 HTTPS 请求的元数据**(例如对方可见的连接来源 IP,以及 Accept/Accept-Encoding 请求头)交给那台服务器 —— 换句话说,**对方能看到你的 IP,也看得到这个 URL 本身**;但它**不会附带**条目正文、记忆内容、人格档案或任何本机文件。⚠️ 因此:**URL 里若放了不该外传的东西(比如把 token 写在查询串里),它就会被发出去** —— 白名单是你自己登记的,请当成"公开可见"来写。白名单默认为空 ⇒ 图书馆默认不发生外部取源访问。
|
|
212
|
+
- **边界(如实写)**:这一版已抬版到 **`1.7.0`(工作区候选)但仍未发布、未安装**;而"没发布"**不等于"没验过"** —— 第五个标签(图书馆)已于 **2026-10-07 在本机既有 3080 上真机验收走通**(建档 / 核对 / 撤下留痕 / 撤销弹窗全过),实现与交互测试同时也在源码与离线测试里。两者别混读。另有一条边界要说清:**"不把记忆库里的旧数据迁进图书馆"不等于"禁止网页端来源的资料"** —— 一条资料能不能进图书馆,看的是它**有没有具体、可追责的出处**,与它从哪个渠道来无关。
|
|
213
|
+
|
|
214
|
+
> **机制依据与源码证据**(表结构、核对三态与各条判据的实际位置、取消与错误码落在哪一行)集中在 [`DESIGN.md`](./DESIGN.md) 的「图书馆:机制与源码证据」一节 —— 本节讲"用户能感觉到什么",那一节给出"代码里是哪一行"。
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
165
218
|
## 快速开始
|
|
166
219
|
|
|
167
|
-
> 前置:**Node ≥ 22.
|
|
220
|
+
> 前置:**Node ≥ 22.15**(用到内置 `node:sqlite` **与** `node:zlib` 的 `zstdDecompressSync` —— 两者都到位才加载得起来;**23.x 线需 ≥ 23.8**;精确范围见 `package.json` 的 `engines`)· 已安装 **DeepSeek Harness** 并至少启动过一次。
|
|
168
221
|
|
|
169
222
|
安装入口是官方 CLI 的 `dsh plugin add`(它在 profile 目录里转发给 pnpm,并自动把本包登记进 profile 的 `dsh.profile.bundles` 层列表)。两条路径按你的身份选一条,不要两条都走。
|
|
170
223
|
|
|
@@ -177,7 +230,7 @@ dsh plugin --profile web add @nightpainters/dsh-ling
|
|
|
177
230
|
# 2) 只验证配置层,先不启动
|
|
178
231
|
dsh --profile web --dump-config # 应能看到一行 "# == @nightpainters/dsh-ling" 层
|
|
179
232
|
|
|
180
|
-
# 3) 给 DSH
|
|
233
|
+
# 3) 给 DSH 核心打补丁(**两行** —— `PATCH_TARGETS` 里两个目标;可取证访问日志要用;幂等;这一页各步里**只有这一步**自带回滚)
|
|
181
234
|
node ~/.dsh/profiles/web/node_modules/@nightpainters/dsh-ling/tools/apply-access-log-patch.mjs
|
|
182
235
|
# 不打也一切照常 —— 只是访问日志为空;但**会提醒**:侧栏挂常驻 ⚠(判据 installed===false 且 reason 为 patch-missing;只有**有意关掉** config.accessLog.enabled=false ⇒ reason 为 disabled-by-config 才不染红)
|
|
183
236
|
# DSH 升级/重装后需重跑一次(补丁随包被覆盖)
|
|
@@ -206,7 +259,7 @@ pnpm add file:<路径>/dsh-ling # 或 npm install file:<路径>/dsh-ling
|
|
|
206
259
|
# name: '@nightpainters/dsh-ling'
|
|
207
260
|
# (id 保持 dsh-ling;name 用包名,Node 才解析得到代码)
|
|
208
261
|
|
|
209
|
-
# 2) 给 DSH
|
|
262
|
+
# 2) 给 DSH 核心打补丁(**两行** —— `PATCH_TARGETS` 里两个目标;可取证访问日志要用;幂等;这一页各步里**只有这一步**自带回滚)
|
|
210
263
|
cd <路径>/dsh-ling
|
|
211
264
|
node tools/apply-access-log-patch.mjs # 只在 core 的 /api 栅栏处插一行可选调用
|
|
212
265
|
# 不打也一切照常 —— 只是访问日志为空;但**会提醒**:侧栏挂常驻 ⚠(判据 installed===false 且 reason 为 patch-missing;只有**有意关掉** config.accessLog.enabled=false ⇒ reason 为 disabled-by-config 才不染红)
|
|
@@ -232,12 +285,18 @@ node tools/check-peers.mjs # 声明与宿主对不上?退出码三态
|
|
|
232
285
|
跑测试(不需要宿主,全部离线):
|
|
233
286
|
|
|
234
287
|
```bash
|
|
235
|
-
npm test #
|
|
288
|
+
npm test # 55 套:人格组装(含冻结门 · L1 选择)/ 归档清理(人工)/ **归档·遗忘·回灌** / 模式(只改档位不改模型)/ **跨插件挡位服务(dsh-ling/mode)** / 时间戳归一 / 空闲刷新 / 规矩·习惯 / 习惯生成器(A 数出来 + B 想出来)/ 会话内工具 / **接口守卫** / L1 行瘦身 / 记忆库 / 记忆标题与排序 / 导出合并 / 文件导入 / 导入记录 / **活行(那一行跟着会话走)** / **会话文件名代次(会话历史扫描)** / 网页端补摘要 / 深摘要 / 概述器 / 诞生仪式 / **职责字段(承担)** / 语气 / 时间锚 / **clock skill(时间查询)** / 捕获差分 / 反馈成长回路 / 语料建议 / **小助手地址配置** / **注入面中和** / **记忆分枝与血缘** / **记忆树(主脉·连边·矛盾)** / **一键生成树** / **可取证访问日志** / **补丁锚点(cohort 候选)** / **请求体上限(超限排空 → 413)** / **导入切批(按字节 × 条数双限)** / **投递留痕(每次注入落一条:注入了谁·为什么是它·多少字)** / **会话原文直读(三档下钻 + 库内回退 + 旧版会话代次)** / **深层库条目(结论层落点:读写·幂等·取代·加固)** / **检索档(按内容找会话:条目 + 会话同查·范围限制与降级)** / **图书馆存储层(独立库:生命周期·限额·检索·留旧·不可用≠零命中)** / **图书馆跨连接事务(陈旧修订拒绝·完成的核对留档·序号一致)** / **图书馆核对(三态判定·只认证声明的那个比较·限额与取消不写)** / **图书馆运行时(禁用/不可用降级·接线与关闭顺序)** / **图书馆接口与工具(端点形状·状态码映射·两个工具的参数边界)** / **图书馆界面(独立库的面:分页无伪总数·必填与 JSON 校验·推迟应答竞态)** / **图书馆导入引擎(料源登记与导入)** / **图书馆独立 SQLite(隔离库:只读打开·表必须点名)** / **图书馆浏览(分页与零命中)** / **热重载补绑(工具重挂载:存量 agent 补绑)** / **文档灌入通道(结论层 C 档:两道污染闸·三级去重·出处核验·累计预算)** / **后台自动行为开关(auto:五键默认值·三级优先级·白名单夹取·四条真 HTTP 回归)**
|
|
236
289
|
```
|
|
237
290
|
|
|
238
291
|
> `npm test` 需要 `tests/`,而本包 `files` 白名单**不含 `tests/`** ⇒ **从 npm 装的人跑不了测试**。要跑测试请走路径 B(clone 源码)。
|
|
239
292
|
>
|
|
240
|
-
> 计数口径:**`npm test` 链里登记的段数**(即 `package.json` 的 `scripts.test` 那一行按 `&&` 切分后有多少段就是多少套,不再数 `tests/` 目录)—— **实测
|
|
293
|
+
> 计数口径:**`npm test` 链里登记的段数**(即 `package.json` 的 `scripts.test` 那一行按 `&&` 切分后有多少段就是多少套,不再数 `tests/` 目录)—— **实测 55 套(即链里 55 段),且 55 套全部已登记在 `npm test` 链里**(`tests/harness.mjs` 与 `tests/vm-light.mjs` 是被复用的辅助模块,不计套数)。**加了一套新测试记得同步登记**,否则 `npm test` 会静默少跑一套 —— 这份登记是**手写**的(`package.json` 里 `test` 脚本那一行字面量清单),**漏登记不会被自动发现**,没有安全网兜底。
|
|
294
|
+
>
|
|
295
|
+
> ⚠️ **2026-10-15 实测订正**:此前这里写着 49、而链里当时已经有 53 段 —— 也就是**这段注释自己警告的坑真发生过**:套件登记进去了,这个数字却没人回头改,四次都没被任何判据抓住。当天新增 `deep-import-docs.test.mjs`(C 档文档灌入)⇒ 54。这个数字没有判据替你看着,改链时必须顺手改它。
|
|
296
|
+
>
|
|
297
|
+
> ⚠️ **2026-10-16 再 +1**:新增 `tests/auto-config.test.mjs`(后台自动行为开关:五键默认值 / 三级优先级 / 白名单与夹取 / **四条真 HTTP 回归**)⇒ **55 套**。同日还抓到**一条真红**:修复批次把 `tools/compliance-spec.mjs` 的出站基线从 6 抬到 23 时,**漏改了 `tests/tools.test.mjs` 里钉住的字面量** ⇒ 整链自那时起就是红的,直到当日修复。**同一个坑两次**(数字写死在多处、改一处忘另一处)—— 改链、改基线时,**同批**把所有钉死它的地方一起改。
|
|
298
|
+
>
|
|
299
|
+
> **本轮跑过的实测(1.7 工作区)**:在**隔离环境**(临时数据目录,不碰真机记忆库/图书馆库)下完整跑过一遍 `npm test` —— **55 套全部通过、exit 0**(宿主侧 `deep_item` / `GET /deep/items` 另在 2026-10-15 重启后实测生效);各组件的断言**条数会随迭代变动,本文不写死** —— **最终测试结果以工作区验收清单为准**。⚠️ 这只说明"**这一版代码在离线测试里的行为**",**不等于"所有门禁都完成了"** —— 真实远程核对与真实 DNS/TLS 仍未验(见上文「图书馆」一节的边界)。
|
|
241
300
|
|
|
242
301
|
### 数据放在哪
|
|
243
302
|
|
|
@@ -245,10 +304,11 @@ npm test # 43 套:人格组装(含冻结门 · L1 选择)/ 归档清理(
|
|
|
245
304
|
|---|---|
|
|
246
305
|
| 设置(人格档案) | `$DSH_HOME/cache/dsh-ling/settings.json`(`DSH_HOME` 默认 `~/.dsh`) |
|
|
247
306
|
| 记忆库 | `$DSH_HOME/cache/dsh-ling/memory.db`(SQLite,开启 WAL) |
|
|
307
|
+
| 图书馆(独立库) | `$DSH_HOME/cache/dsh-ling/library.db`(SQLite;**与记忆库分开的第二套表**;不迁移记忆、不参与开场注入) |
|
|
248
308
|
|
|
249
309
|
可覆盖的环境变量:`DSH_HOME`(数据根)、`DSH_LING_DSWEB_DB`(网页端聊天记录库默认路径,UI 里也能填)、`DSH_LING_ASSISTANT` / `DSH_LING_ASSISTANT_MODEL`(小助手地址与模型名)。
|
|
250
310
|
|
|
251
|
-
> **排障用逃生开关(不是日常配置)**:`DSH_LING_GUARD=off`(须**恰好**是 `off`,小写)
|
|
311
|
+
> **排障用逃生开关(不是日常配置)**:`DSH_LING_GUARD=off`(须**恰好**是 `off`,小写)或在**插件配置**(`cordis.patch.yml` 的 `config` 段)里把 `guard.enforce` 设为 `false`,用于**误判把你自己锁在门外**时的临时解锁 —— 它是**整体放行** —— `/api` 的**来源栅栏 + cookie 名字对撞**,以及**手术门**(本机限定 / 每启动票据 / 原句匹配)**一起不再拦**(默认 `guard.enforce = true`),关掉期间**任何请求都不再被拦**。只该短期使用,排障完立刻恢复。`DSH_LING_GUARD=off` 只由进程环境决定、不进配置;**`guard.enforce = false` 这条不要直接写进 `settings.json`** —— 设置接口也帮不了你:它的字段白名单只放行 `persona` / `styles` 两棵子树,`guard` 这类字段会被**直接丢弃**并在响应里回报 `ignored`(见 `lib/host/api.js` 里 `/persona` 端点的字段白名单处理:`ignored` 回报被丢弃的键),不是被拒绝而是根本进不去 —— 而且**本版没有界面开关**:面板里没有任何写 `guard.*` 的路径(客户端里 `allowLan` / `trustedHosts` 一处都没有,`guardInfo` 定义了却零使用)。**要改只能改 `cordis.patch.yml` 的 `config` 段,或临时用环境变量 `DSH_LING_GUARD=off`。**(这不是没做完,是**有意**的:`lib/host/guard.js` 里写明这道白名单要防的是"把你自己关在门外"这件事被顺手关掉。)
|
|
252
312
|
|
|
253
313
|
> **访问日志与核心补丁的总开关(同样不是日常配置)**:这套「可取证访问日志」默认**开着**,关它的键是插件配置里的 `accessLog.enabled`(**默认 `true`**)—— 在 `cordis.patch.yml` 注册行的 `config` 段里写 `accessLog: { enabled: false }`,重载后生效,启动日志会出现 `access log off`;它**只有配置键、没有环境变量**。关掉之后**退化的只有「留痕」这一件事**:那两个全局观察钩子不再挂上、不再写 `$DSH_HOME/logs/access-YYYY-MM-DD.jsonl`、日志健康读数(`accessLogHealth()`)归 `null`;而 `/api` 与 `/api/remote.mux` 的**来源栅栏照常判定与拦截**,记忆、人格、注入与工具面**一律不受影响** —— 关掉的是「记不记」,不是「拦不拦」。已经打进 `node_modules` 的**核心补丁**可以留在原地:那两行是可选调用,日志关着时就是 no-op,DSH 照常启动;要连它一起撤掉,用 `node tools/apply-access-log-patch.mjs --revert` 删掉插进去的那几行。
|
|
254
314
|
|
|
@@ -259,6 +319,7 @@ npm test # 43 套:人格组装(含冻结门 · L1 选择)/ 归档清理(
|
|
|
259
319
|
## 隐私
|
|
260
320
|
|
|
261
321
|
- 记忆库、人格档案、导入的历史**全部保存在你自己机器上**(SQLite 文件),插件**不上传**任何数据到第三方;
|
|
322
|
+
- **图书馆的远程核对会访问你登记的 URL**(1.7 工作区,未发布;注意这**不等于"本插件只有这一处联网"** —— 模型调用本来就走你自己配置的网络与密钥):只有管理员把官方文档 URL 登记进白名单之后,核对才会对**那一个精确 URL** 发 HTTPS GET,把文档读回来与条目里声明的期望值比对。**发出去的是这个 URL(连同查询串)与一次普通 HTTPS 请求的元数据** —— **对方能看到你的 IP 与这个 URL**,但请求里**不会附带**条目正文、记忆内容、人格档案或任何本机文件;**不跟随跳转、不带凭据、私网地址一律拒**。⚠️ **别把敏感信息放进登记 URL 的查询串** —— 那部分是真的会发出去的。白名单**默认为空** ⇒ 图书馆默认不发生外部取源访问。(记忆库与图书馆库都在本机,两者之间不互相导入。)
|
|
262
323
|
- 模型调用走**你自己的** DSH 配置与密钥;
|
|
263
324
|
- 导入的是**你自己的**对话记录 —— 请不要把他人数据导进来。
|
|
264
325
|
- **访问日志也只在本地**:`$DSH_HOME/logs/access-YYYY-MM-DD.jsonl` 只记"谁在何时调了哪个端点、结果如何"(来源 IP / `fwd` / Host / UA / `bytes` / 状态码 / 拒绝原因 / 设备字段),**不记请求体、不记响应体、不记 cookie 值**;查询串与 hash(可能带 token)一律丢弃;UA 截断到 200 字符、`fwd` 60、Host 120 —— 单一设备仍可跨天对上号,但**配对凭据原文一律不落盘**。设备字段是两件东西:`deviceCookie` 只说明**配对 cookie 在不在**,`deviceId` 是**摘要**而非凭据 —— `sha256(凭据原文)` 取前 16 位十六进制,同行带 `deviceIdHash:"sha256-16"` 标出这一形态(较早版本的旧行没有这个字段,其 `deviceId` 是 32 位十六进制凭据原文)⇒ **看日志时按 `deviceIdHash` 分辨时代,别把两代的行当成同一台设备** —— 与记忆树"内容零改写"同源。**覆盖范围**:`/api` 与 `/api/remote.mux` 的 upgrade;静态资源与非 `/api` 路径不记。命中**自家部署姿态自检**签名的 403 会多带 `probe:"posture"` 字段 —— 它**仍然是被栅栏拦下的**请求,标注只为免得自检被误读成入侵。没有 `user-agent` 头的行会多带 `channel:"no-ua"` —— 它只说明"**不是浏览器直连**"(进程内客户端与经远端通道进来的设备**同签名**),**不指认是哪一台设备**。
|
|
@@ -401,16 +462,39 @@ npm test # 43 套:人格组装(含冻结门 · L1 选择)/ 归档清理(
|
|
|
401
462
|
| **N-1** | **`recall` 直通原文四档**:清单 / 按内容找 / 对话目录 / 按区间取原话 —— 逐级下钻,一次一层 | ✅ |
|
|
402
463
|
| **N-2** | **它不替你挑"最重要的那一段"** —— 只给坐标系;选哪一段是器灵自己的判断(它才知道自己为什么要读) | ✅ |
|
|
403
464
|
| **N-3** | 磁盘日志读不到时**回落查库**,并在回执里如实标注那份是**残的**(只含真人消息与有正文的回复) | ✅ |
|
|
404
|
-
| **N-4** |
|
|
405
|
-
| **N-5** |
|
|
465
|
+
| **N-4** | **会话文件名代次**:历史扫描/库内回退按 `session(\.v\d+)?\.jsonl\.zstd` 匹配、取版本最高的一代并跳过 0 字节(**`recall` 读原文那条路走的是三代硬编码名单,不解析版本**) | ✅ |
|
|
466
|
+
| **N-5** | 检索范围:宿主路**默认只搜"你自己的会话"**、越界须显式参数、被挡掉的条数**一律报出**;默认的本机库路是全量,**如实标注**;两条路都默认排除当前会话自己 | ✅ |
|
|
406
467
|
| **N-6** | **投递留痕**:每一次真正定稿的注入都落一条 —— 注入了谁 / **为什么是它** / 多少字 / **谁落选了以及为什么** | 🚧 只写不读 |
|
|
407
|
-
| **N-7** | **深层库(结论层)**:把过程流水换成**可复用的结论**,分承诺 / 决定 / 事实 / 偏好 /
|
|
468
|
+
| **N-7** | **深层库(结论层)**:把过程流水换成**可复用的结论**,分承诺 / 决定 / 事实 / 偏好 / 关系 / 纪律**六类**;**空结果是正确结果** | 🚧 在做 |
|
|
408
469
|
| **N-8** | **记忆开场改用结论层**:置顶必进 + 被反复采用的排前 + 当轮关键词加成 + **按硬度过滤**(临时条目不进开场)+ **2 席留给最硬的事实** | ✅ |
|
|
409
470
|
| **N-9** | **视角框**:开场先声明人称,并写死「**本会话 / 接下来 / 现在**」指当时那个会话、**不是此刻的指令** | ✅ |
|
|
410
471
|
| **N-10** | 一年半的网页端历史(**1,523 个会话 / 726.7 万字**)已补录进库,`recall` 能直接读到 | ✅ |
|
|
411
472
|
| **N-11** | **条目硬度**:每条结论带 `durable / long / ephemeral` 三档,**临时的那档不进开场** —— 从**根源**判断它是不是临时,而不是靠"同一次会话限几条"去机械地卡 | 🚧 在做 |
|
|
412
473
|
| **N-12** | **被采用才算加固**:条目的"反复加固"由**真的下钻去读它的原话**推进,**不由"被注入"推进** —— 否则会形成"注入越多分越高、分越高越容易被注入"的自我强化 | ✅ |
|
|
413
474
|
| **N-13** | **索引层**已落地:11 簇主题地图(一簇一行)做成**一个技能**常驻,细节按需展开;簇里**不写条数**(条数天天变会毁掉前缀稳定) | ✅ |
|
|
475
|
+
| **N-14** | **结论层有了"看得见 + 能落条"两条路**:工具 `deep_item`(`add` 可先 `dryRun` / `retract` 作废 / `list`)与**只读**「结论层」标签;文本**超 80 字当场拒**;作废**只标记不删**、理由留痕、可撤;面板**不给写入口** —— 落条与作废的判据是"经你授权" | ✅ 已落(2026-10-15 重启实测生效) |
|
|
476
|
+
| **N-15** | **文档灌入:先 dry 后 commit + 累计预算** —— 把已写进文档的结论批量灌进结论层:默认只出清单(每条带真源指针与**真源原文**,看过再落);一趟总量 ≤40 条,且是**全趟额度**(跑一次与跑十次扣同一个额度,超额**拒绝再落**) | ✅ 已落(第一趟 40 条,2026-10-15) |
|
|
477
|
+
| **N-16** | **会过时的条目落成 `ephemeral`** —— 文本里带具体读数 / 版本号 / 时点状态的结论**不进开场注入**、检索仍搜得到:将来过时了也不会拿旧数字污染开场;**复查**走 `--review` 出信号清单(含时间锚却当着长期条 / 当次档够老 / 从没被采用过),**只列信号、不作废** | ✅ 已落 |
|
|
478
|
+
| **N-17** | **"纪律"不走检索召回** —— 纪律要的是"该动手时它**在场**(行动触发)",与"按内容去找(内容触发)"不是一回事 ⇒ **不进结论层的自动落库**,归宿是规矩 / 常驻注入面 | 📋 1.7.x |
|
|
479
|
+
|
|
480
|
+
### 1.7 新增(图书馆 · 工作区,未发布)
|
|
481
|
+
|
|
482
|
+
> ⚠️ **本节的状态标记只指"工作区代码 + 离线测试"这一层**:1.7 **尚未发布**(包版本已抬到 `1.7.0`,尚未发布/安装);"宿主界面上的「图书馆」标签"**已真机验收走通**(2026-10-07,见 L-11);「结论层」标签已于 **2026-10-15** 随一次宿主重启实测生效。
|
|
483
|
+
|
|
484
|
+
| # | 设定 | 状态 |
|
|
485
|
+
|---|---|---|
|
|
486
|
+
| **L-1** | **图书馆是独立库,不是记忆的第二层** —— 独立的 `library.db` 与独立的表;两库之间**不互相导入、不互相引用**(没有隐式通道) | ✅ 工作区 |
|
|
487
|
+
| **L-2** | **既有记忆永不迁进图书馆**;反过来,图书馆条目**不进注入面、不参与开场装配** | ✅ 工作区 |
|
|
488
|
+
| **L-3** | **"不迁移记忆"≠"禁止某个渠道的新资料"** —— 一条资料能不能进图书馆,看它**有没有具体、可追责的出处**,与它从哪个渠道来无关 | ✅ 口径 |
|
|
489
|
+
| **L-4** | 器灵侧**只有两只手**:`library_search`(搜)与 `library_check`(核对);**没有**新建 / 修订 / 撤下 / 改配置的模型工具,代码根目录与 URL 白名单**不接受模型入参** | ✅ 工作区 |
|
|
490
|
+
| **L-5** | **核对只认证"声明的那一处"** —— 结论只有 `ok` / `wrong` / `unknown`;回执必须写明"不认证解释性正文、也不构成通用真理" | ✅ 工作区 |
|
|
491
|
+
| **L-5′** | **比较方式的准确定义** —— **`exact`** = 类型严格的**结构比较**(JSON 对象**成员顺序无关**、**数组顺序有关**;文本按字面精确比);**`text-lf`** = 只把 CRLF/CR 归一成 LF 后精确比。**两者都不 trim、不折叠大小写、不模糊匹配** | ✅ 工作区 |
|
|
492
|
+
| **L-6** | **"不可用"与"零命中"必须分开** —— 库打不开 / 未启用 / 运行时不在场 = 明确的不可用(接口层 503 语义),**绝不回落成"搜到 0 条"** | ✅ 工作区 |
|
|
493
|
+
| **L-7** | **修订与撤下都留旧** —— 新版本换新 id、旧版留痕指向新版;撤下只**标记**状态、不物理删除;**跑完的**核对各留一行账(源摘要 / 观测值 / 结论 / 理由,含 `unknown`),**取消的不留** | ✅ 工作区 |
|
|
494
|
+
| **L-8** | **写面必须带"观测到的内容摘要"**(`content_hash`),对不上就拒 —— 防"看着旧版改新版" | ✅ 工作区 |
|
|
495
|
+
| **L-9** | **严格配置** —— 代码根目录与官方文档 URL 白名单**默认为空**、由管理员登记;限额在**激活时校验**,非法值**响亮报错**、不静默夹取 | ✅ 工作区 |
|
|
496
|
+
| **L-10** | **取消 = 没跑完,不留记录** —— 核对在飞时取消 / 断开 / 卸载 ⇒ 本次**不写任何核对记录**(既不留 `ok` / `wrong`,**也不留 `unknown`**);只有**跑完的**核对(含结论 `unknown`)才留账 | ✅ 工作区 |
|
|
497
|
+
| **L-11** | **发布状态如实声明** —— 包版本已抬到 **`1.7.0`(工作区候选)**,**未发布、未安装**;但「图书馆」标签**已真机验收走通**(2026-10-07),「结论层」标签也已随 2026-10-15 的重启实测生效 —— **"没发布"与"没验过"必须分开说** | ✅ 真机验收(2026-10-07) |
|
|
414
498
|
|
|
415
499
|
> ⚠️ **这一节还在补。** 完整规格有**四百余条**,本节先落**对外面**里最稳定的一批(设计理念);其余按主题分批补写 —— 每一条都要从开发期设定**改写成对外语言**并核对状态,这是**写作**而不是复制。
|
|
416
500
|
|
package/cordis.patch.yml
CHANGED
|
@@ -7,10 +7,40 @@
|
|
|
7
7
|
# 不符时客户端判定"该 row 没到货",会回退去取单资源 URL 把同一份字节**再执行一遍**,
|
|
8
8
|
# 第二次注册抛 `duplicate factory registration` ⇒ 前端整片黑屏(2026-09-26 实测两次)。
|
|
9
9
|
# ⇒ 改包名时 `lib/client.js` 必须同批改;`tests/unit.mjs` 已加断言守着。
|
|
10
|
-
#
|
|
10
|
+
# 工作区改动不等于当前 GUI 已更新;部署并重建实际使用的客户端产物后再刷新验证。
|
|
11
11
|
- insert:
|
|
12
12
|
- id: dsh-ling
|
|
13
13
|
name: '@nightpainters/dsh-ling'
|
|
14
14
|
# config(可选,覆盖默认值):
|
|
15
15
|
# dataDir: 覆盖数据目录(默认 $DSH_HOME/cache/dsh-ling)
|
|
16
|
-
# injectEnabled: false #
|
|
16
|
+
# injectEnabled: false # 关掉**记忆段**注入(逃生开关;人格段另受 settings.persona.enabled 管)
|
|
17
|
+
# library:
|
|
18
|
+
# enabled: true # 独立 library.db;不迁移既有记忆,不参与开场注入
|
|
19
|
+
# codeRoots: [] # 管理员登记的已存在绝对目录;默认不允许任何本地源
|
|
20
|
+
# officialUrls: [] # 管理员登记的精确 HTTPS 文档 URL;默认不允许任何远程源
|
|
21
|
+
# limits: # 只接受这些规范键;非法配置在开库前拒绝
|
|
22
|
+
# itemMaxBytes: 65536
|
|
23
|
+
# resultMaxBytes: 262144
|
|
24
|
+
# queryMaxChars: 512
|
|
25
|
+
# searchDefaultLimit: 20
|
|
26
|
+
# searchMaxLimit: 100
|
|
27
|
+
# sourceMaxBytes: 2097152
|
|
28
|
+
# selectedTextMaxBytes: 16384
|
|
29
|
+
# selectedTextMaxLines: 200
|
|
30
|
+
# checkTimeoutMs: 10000
|
|
31
|
+
# checkConcurrency: 2
|
|
32
|
+
# sqliteBusyTimeoutMs: 2000
|
|
33
|
+
|
|
34
|
+
# 后台自动行为(默认全开)的 5 个键 —— **在哪改**:
|
|
35
|
+
# · **首选**:`settings.json`($DSH_HOME/cache/dsh-ling/settings.json)的 `auto.*` 子树
|
|
36
|
+
# —— 面板开关写的就是它;该文件只存你改过的部分;
|
|
37
|
+
# · **兜底一层**:下面这几个旧键(插件配置,仍生效;`auto.*` 命中时以 `auto.*` 为准);
|
|
38
|
+
# · 两处都没有 ⇒ 代码默认值(lib/host/deepsummary.js 的 DEEP_CFG)。
|
|
39
|
+
# auto.deepSummary 默认 true —— 启动自检通过后挂定时器;false = 只有手动点「深摘」才调用模型
|
|
40
|
+
# auto.deepIntervalMin 默认 30(最小 10)—— 每隔多久跑一轮自动深摘
|
|
41
|
+
# auto.deepMaxPerRun 默认 2(1–20) —— 每轮最多挑几个会话
|
|
42
|
+
# auto.bootProbeDelayMs 默认 12000 —— 启动 12 秒后做一次 LLM 自检探针(通过了才挂定时器);0 = 立即试探
|
|
43
|
+
# auto.feedbackAuto 默认 true —— 事件驱动(宿主推 feedback/committed 时);false = 完全不接反馈成长回路
|
|
44
|
+
# 旧键(写在本段 config 里的形态,不是上面的 auto.*):feedbackAuto / deepSummaryAuto / deepIntervalMin / deepMaxPerRun
|
|
45
|
+
# 生效时机:deepSummary / bootProbeDelayMs / feedbackAuto 启动期读取 ⇒ 改完要重启插件;
|
|
46
|
+
# deepIntervalMin / deepMaxPerRun 对已挂上的定时器不回溯(下一轮启动后按新值走)。
|