@lemoncat7/dsh-knowledge 0.6.0-alpha.6

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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/cordis.patch.yml +12 -0
  4. package/docs/architecture.md +107 -0
  5. package/docs/document-knowledge-design.zh-CN.md +329 -0
  6. package/docs/requirements.md +86 -0
  7. package/lib/api.d.ts +4 -0
  8. package/lib/api.d.ts.map +1 -0
  9. package/lib/api.js +497 -0
  10. package/lib/api.js.map +1 -0
  11. package/lib/client.js +420 -0
  12. package/lib/client.js.map +7 -0
  13. package/lib/config.d.ts +38 -0
  14. package/lib/config.d.ts.map +1 -0
  15. package/lib/config.js +84 -0
  16. package/lib/config.js.map +1 -0
  17. package/lib/connection.d.ts +15 -0
  18. package/lib/connection.d.ts.map +1 -0
  19. package/lib/connection.js +95 -0
  20. package/lib/connection.js.map +1 -0
  21. package/lib/control.d.ts +26 -0
  22. package/lib/control.d.ts.map +1 -0
  23. package/lib/control.js +149 -0
  24. package/lib/control.js.map +1 -0
  25. package/lib/domain.d.ts +207 -0
  26. package/lib/domain.d.ts.map +1 -0
  27. package/lib/domain.js +122 -0
  28. package/lib/domain.js.map +1 -0
  29. package/lib/extraction.d.ts +27 -0
  30. package/lib/extraction.d.ts.map +1 -0
  31. package/lib/extraction.js +367 -0
  32. package/lib/extraction.js.map +1 -0
  33. package/lib/index.d.ts +15 -0
  34. package/lib/index.d.ts.map +1 -0
  35. package/lib/index.js +198 -0
  36. package/lib/index.js.map +1 -0
  37. package/lib/local-provider.d.ts +60 -0
  38. package/lib/local-provider.d.ts.map +1 -0
  39. package/lib/local-provider.js +1096 -0
  40. package/lib/local-provider.js.map +1 -0
  41. package/lib/provider-router.d.ts +19 -0
  42. package/lib/provider-router.d.ts.map +1 -0
  43. package/lib/provider-router.js +83 -0
  44. package/lib/provider-router.js.map +1 -0
  45. package/lib/provider.d.ts +38 -0
  46. package/lib/provider.d.ts.map +1 -0
  47. package/lib/provider.js +2 -0
  48. package/lib/provider.js.map +1 -0
  49. package/lib/recall.d.ts +8 -0
  50. package/lib/recall.d.ts.map +1 -0
  51. package/lib/recall.js +76 -0
  52. package/lib/recall.js.map +1 -0
  53. package/lib/remote-provider.d.ts +51 -0
  54. package/lib/remote-provider.d.ts.map +1 -0
  55. package/lib/remote-provider.js +216 -0
  56. package/lib/remote-provider.js.map +1 -0
  57. package/lib/retrieval.d.ts +35 -0
  58. package/lib/retrieval.d.ts.map +1 -0
  59. package/lib/retrieval.js +206 -0
  60. package/lib/retrieval.js.map +1 -0
  61. package/lib/runtime.d.ts +147 -0
  62. package/lib/runtime.d.ts.map +1 -0
  63. package/lib/runtime.js +26 -0
  64. package/lib/runtime.js.map +1 -0
  65. package/lib/tools.d.ts +6 -0
  66. package/lib/tools.d.ts.map +1 -0
  67. package/lib/tools.js +99 -0
  68. package/lib/tools.js.map +1 -0
  69. package/lib/web.d.ts +3 -0
  70. package/lib/web.d.ts.map +1 -0
  71. package/lib/web.js +71 -0
  72. package/lib/web.js.map +1 -0
  73. package/package.json +79 -0
  74. package/web/app.js +1686 -0
  75. package/web/index.html +19 -0
  76. package/web/styles.css +786 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lemoncat7
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # dsh-knowledge
2
+
3
+ `dsh-knowledge` 是面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的知识库插件。它不修改 DSH Agent Loop,同一个插件既能使用本地 SQLite,也能连接远程中央知识库。
4
+
5
+ 当前版本 `0.6.0-alpha.6` 已实现可部署的多知识库、按需检索工具与文档型 Web 管理台:
6
+
7
+ - 回答完成后同步调用 DSH 当前模型判断是否产生知识,并在回答下方显示逐库回写结果。
8
+ - 知识标题、正文、自然语言标签和提取理由默认跟随本轮用户语言;代码、命令和技术标识保持原样。
9
+ - 回写结果只作为 UI 状态展示,在下一次模型请求前会被移除,不占用会话上下文。
10
+ - 可创建多个知识库,分别设定说明、默认标签和提取要求。
11
+ - 每个知识库可选择专用回写模型;未设定时跟随当前会话模型。
12
+ - 项目和会话挂载;会话默认继承项目,也可独立覆盖或关闭。
13
+ - 每个挂载支持仅召回、审核写入、直接写入,以及包含/排除标签和额外提取要求。
14
+ - `create / update / conflict / skip` 提取决策;直写模式自动写入普通结果,冲突仍进入人工审核。
15
+ - 未挂载知识库时,不召回、不提取、不回写。
16
+ - 全局与项目范围,以及偏好、事实、决策、流程、经验五类知识。
17
+ - SQLite WAL、FTS5 全文搜索、原子事务、完整版本历史和幂等提取任务。
18
+ - 挂载库的名称和描述作为轻量动态目录注入,不直接塞入文档正文。
19
+ - 每条新用户消息默认只主动预取 3 条短摘要;模型可按需调用只读的 `knowledge_search` 与 `knowledge_read` 工具继续检索。
20
+ - 搜索和读取由服务端按当前会话挂载、项目范围及包含/排除标签强制限权,读取句柄带签名且仅限当前会话。
21
+ - 本地与远程 Provider 使用同一接口;远程模式不做隐式双向同步。
22
+ - DSH“设置 → 插件”提供“知识库连接”卡片,可选择本地来源或填写中央服务地址和只写客户端令牌,保存后实时验证并切换 Provider。
23
+ - Bearer Token 仅保存 SHA-256 摘要,支持 `read / propose / write / admin` 权限及吊销。
24
+ - 认证 HTTP API,可作为其他 DSH 客户端和未来桌面端的中央知识库。
25
+ - Apple 风格三栏文档界面,按知识库浏览自动整理的 `README.md`、`facts.md`、`decisions.md` 等文档。
26
+ - 知识库栏和文档栏可拖拽或用方向键调宽;DSH 内的管理窗口可缩放、最大化和还原。
27
+ - 随插件安装的响应式 Web 管理台,覆盖概览、文档浏览、条目维护、AI 候选审核和客户端令牌管理。
28
+ - DSH 浏览器端插件:在左侧工作区下方显示“知识库”,并在当前页面内打开管理面板。
29
+ - 明暗主题、键盘操作、窄屏布局以及不依赖颜色的状态标签。
30
+
31
+ ## 安装
32
+
33
+ ```bash
34
+ dsh plugin --profile web add ./lemoncat7-dsh-knowledge-0.6.0-alpha.6.tgz
35
+ ```
36
+
37
+ 卸载:
38
+
39
+ ```bash
40
+ dsh plugin --profile web remove @lemoncat7/dsh-knowledge
41
+ ```
42
+
43
+ 插件是标准 DSH profile bundle:`package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`。安装后不需要单独运行知识库容器。
44
+
45
+ ## 本地模式
46
+
47
+ 默认配置使用 DSH 持久目录中的 SQLite 文件:
48
+
49
+ ```yaml
50
+ - id: knowledge
51
+ name: '@lemoncat7/dsh-knowledge'
52
+ config:
53
+ backend: local
54
+ databasePath: !!js dshHomePath('knowledge/knowledge.sqlite')
55
+ extractionEnabled: true
56
+ defaultScope: project
57
+ autoRecallLimit: 3
58
+ exposeApi: false
59
+ ```
60
+
61
+ 提取模型默认沿用刚完成回答的 provider/model。可在单个知识库中设置专用回写模型;以下全局配置仅作为兼容性后备:
62
+
63
+ ```yaml
64
+ extractionProvider: deepseek-official
65
+ extractionModel: deepseek-chat
66
+ ```
67
+
68
+ 独立模型必须先在 DSH 的模型设置中注册。不论使用 Kimi 还是其他会话模型,首次超限后都会保持原 provider/model,用精简提示和低推理重试,不会暗中换模型。
69
+
70
+ 提取输出达到模型上限时会自动用双倍预算重试一次(最高 8192 tokens)。其他提取失败会将幂等任务标为 `failed`,失败任务最多可重新领取两次,并在回答下方记录回写通知,不会阻断下一轮。
71
+
72
+ ## 中央服务端
73
+
74
+ 本地实例可以同时开放认证 API:
75
+
76
+ ```yaml
77
+ backend: local
78
+ databasePath: !!js dshHomePath('knowledge/knowledge.sqlite')
79
+ exposeApi: true
80
+ apiToken: !!js process.env.DSH_KNOWLEDGE_API_TOKEN
81
+ apiPrefix: /knowledge-api/v1
82
+ exposeWeb: true
83
+ webPath: /knowledge
84
+ ```
85
+
86
+ `DSH_KNOWLEDGE_API_TOKEN` 至少 24 个字符。该值只用于创建或恢复 bootstrap admin 身份;数据库只保存摘要。服务端没有 TLS,非回环部署必须放在 HTTPS 反向代理之后。
87
+
88
+ 启用后访问 `http://<DSH 地址>:<端口>/knowledge`。管理台要求输入 API 令牌,令牌只保存在当前浏览器标签页的 `sessionStorage` 中,关闭标签页后自动清除。`exposeWeb` 必须与 `exposeApi` 一起启用,管理台和 API 均由 DSH 自身 WebServer 提供,不需要额外容器。
89
+
90
+ 管理台功能:
91
+
92
+ - 查看准确的知识、候选和提取任务统计。
93
+ - 创建和编辑多个知识库,管理默认标签与提取要求。
94
+ - 管理当前项目挂载和会话覆盖,设定召回、写入模式与标签范围。
95
+ - 在三栏界面中搜索和阅读 Markdown 文档,并保留条目管理作为兼容入口。
96
+ - 查看 AI 提取依据,直接通过、编辑后通过或拒绝候选。
97
+ - 创建、查看和撤销客户端令牌;新令牌原文只显示一次。
98
+
99
+ 知识库的 `description` 同时用于读取和回写路由:它会出现在会话的轻量挂载目录中,帮助模型判断何时调用检索工具;提取器也只有在当前对话中的可复用知识符合该描述时,才能选择这个库。挂载只表示“可选”,不代表每次回答都要检索或写入。`extractionInstructions` 用于在匹配后继续限定具体收录规则。
100
+
101
+ 创建示例:
102
+
103
+ ```json
104
+ {
105
+ "draft": {
106
+ "name": "DSH 项目规范",
107
+ "description": "只匹配 DSH 插件开发、架构决策和部署规范相关对话",
108
+ "defaultTags": ["dsh", "project-rule"],
109
+ "extractionInstructions": "只收录已确认且可跨会话复用的结论"
110
+ }
111
+ }
112
+ ```
113
+
114
+ 局部修改标签或描述时使用 `PATCH /knowledge-bases/:id`,请求体为 `{"patch":{"description":"...","defaultTags":["..."]}}`。
115
+
116
+ 主要 API:
117
+
118
+ | Method | Path | Permission | Purpose |
119
+ | --- | --- | --- | --- |
120
+ | GET | `/health` | public | 健康检查 |
121
+ | GET | `/search` | read | FTS 检索 |
122
+ | GET/POST | `/knowledge-bases` | read/write | 知识库列表和创建 |
123
+ | GET/PUT/PATCH | `/knowledge-bases/:id` | read/write | 详情、完整替换和局部修改 |
124
+ | POST | `/knowledge-bases/:id/archive` | admin | 归档并关闭相关挂载 |
125
+ | POST | `/knowledge-bases/:id/restore` | admin | 恢复已归档知识库 |
126
+ | DELETE | `/knowledge-bases/:id` | admin | 永久删除已归档知识库及全部关联数据 |
127
+ | GET/POST/DELETE | `/mounts` | read/write | 挂载查询、更新和删除 |
128
+ | POST | `/mounts/bulk` | write | 事务型批量挂载与取消 |
129
+ | GET | `/mounts/resolve` | read | 解析项目继承与会话覆盖 |
130
+ | GET | `/documents` | read | 按知识库或正文搜索 Markdown 文档 |
131
+ | GET | `/documents/:id` | read | 读取单篇 Markdown 文档 |
132
+ | GET/POST | `/entries` | read/write | 列表和直接创建 |
133
+ | GET/PUT/DELETE | `/entries/:id` | read/write/admin | 详情、更新、彻底删除 |
134
+ | GET | `/entries/:id/versions` | read | 版本历史 |
135
+ | GET/POST | `/candidates` | read/propose | 候选列表和提交 |
136
+ | POST | `/candidates/:id/review` | write | 审核候选 |
137
+ | GET/POST/DELETE | `/tokens` | admin | 客户端令牌管理 |
138
+
139
+ 路径均位于配置的 `apiPrefix` 下。创建令牌时,原始令牌只在响应中返回一次。
140
+
141
+ ## 远程客户端
142
+
143
+ 先在中央实例的“知识库 → 客户端令牌”中为每台客户端分别创建令牌。普通 DSH 客户端建议选择 `read + propose`;需要直接写入或管理挂载时再增加 `write`。令牌原文只显示一次。
144
+
145
+ 其他 DSH 客户端安装本插件后,打开“设置 → 插件 → 知识库连接”,选择“远程”,填写中央实例的知识库 API 地址和客户端令牌,再点“验证并连接”。插件会先验证地址和令牌,成功后立即热切换,并把连接持久化到 DSH 数据目录;令牌不会在页面或控制接口中回显,只能覆盖。
146
+
147
+ 如需用配置文件或环境变量部署,也可以直接设置 Provider:
148
+
149
+ ```yaml
150
+ - id: knowledge
151
+ name: '@lemoncat7/dsh-knowledge'
152
+ config:
153
+ backend: remote
154
+ remoteUrl: 'https://knowledge.example.com/knowledge-api/v1'
155
+ remoteToken: !!js process.env.DSH_KNOWLEDGE_REMOTE_TOKEN
156
+ extractionEnabled: true
157
+ autoRecallLimit: 3
158
+ ```
159
+
160
+ 远程地址必须是 HTTPS;只有 `localhost` 和回环 IP 的测试地址允许 HTTP。普通客户端建议只分配 `read + propose` 权限。
161
+ 远程客户端连接的是中央库,不会复制或同步一份本地数据库;断网时无法召回或回写。每台客户端仍需用自己的项目/会话标识挂载所需知识库。
162
+
163
+ ## 开发与 Docker 构建
164
+
165
+ 要求 Node.js `^22.19.0 || >=24.0.0`。
166
+
167
+ ```bash
168
+ npm install
169
+ npm test
170
+ npm run pack:check
171
+ ```
172
+
173
+ 推荐使用 Node 24 Docker 环境编译、测试并输出 tarball:
174
+
175
+ ```bash
176
+ docker build \
177
+ --build-arg NODE_IMAGE=docker.1ms.run/library/node:24-bookworm-slim \
178
+ --target artifact \
179
+ --output type=local,dest=dist .
180
+ ```
181
+
182
+ 架构和一致性设计见 [docs/architecture.md](docs/architecture.md),首版产品边界见 [docs/requirements.md](docs/requirements.md),文档型演进设计见 [docs/document-knowledge-design.zh-CN.md](docs/document-knowledge-design.zh-CN.md)。
183
+
184
+ 本项目采用 MIT License。
@@ -0,0 +1,12 @@
1
+ # Install this package as one DSH profile bundle. The profile's later user
2
+ # patch may replace this row to select remote mode or expose the local API.
3
+ - insert:
4
+ - id: knowledge
5
+ name: '@lemoncat7/dsh-knowledge'
6
+ config:
7
+ backend: local
8
+ databasePath: !!js dshHomePath('knowledge/knowledge.sqlite')
9
+ connectionPath: !!js dshHomePath('knowledge/connection.json')
10
+ exposeApi: false
11
+ extractionEnabled: true
12
+ autoRecallLimit: 3
@@ -0,0 +1,107 @@
1
+ # Architecture
2
+
3
+ ## Design goals
4
+
5
+ The plugin is a modular monolith inside one DSH process. It keeps deployment simple while preserving explicit boundaries that can later become separate packages without changing the knowledge contract.
6
+
7
+ ```text
8
+ DSH events / pre-step / HTTP / Web console
9
+ |
10
+ extraction, catalog, retrieval tools, API
11
+ |
12
+ KnowledgeProvider
13
+ / \
14
+ local SQLite remote HTTPS
15
+ ```
16
+
17
+ The DSH core is never patched. `src/index.ts` is the composition root; every other module is independently testable.
18
+
19
+ ## Layers
20
+
21
+ - `domain.ts` owns stable value types, normalization, IDs and content hashing. It has no DSH dependency.
22
+ - `provider.ts` is the storage/application port. Local and remote clients implement the same asynchronous contract.
23
+ - `local-provider.ts` owns schema migrations, transactions, FTS and token hashes.
24
+ - `remote-provider.ts` is an authenticated, timeout-bounded HTTPS adapter.
25
+ - `extraction.ts` snapshots completed turns, resolves writable mounts and validates model JSON fail-closed.
26
+ - `retrieval.ts` owns mounted-scope authorization, signed handles, ranking and bounded rendering shared by proactive and tool-driven retrieval.
27
+ - `recall.ts` contributes a lightweight mounted-base catalog and performs bounded proactive retrieval in the asynchronous `agent/pre-step` waterfall.
28
+ - `tools.ts` registers read-only `knowledge_search` and paginated `knowledge_read` tools whose scope is resolved from the calling Agent.
29
+ - `api.ts` is a size-bounded HTTP adapter with permission checks and safe errors.
30
+ - `web.ts` serves a same-origin, CSP-constrained management console from package-owned static assets.
31
+ - `web/` is a dependency-free browser application with a small API/state/view boundary; it stores credentials only in session storage.
32
+ - `index.ts` validates configuration and wires lifecycle disposal.
33
+
34
+ ## Data model and consistency
35
+
36
+ SQLite is authoritative in local mode. Schema version 4 contains:
37
+
38
+ - `knowledge_bases`: independently named destinations with default tags and extraction instructions.
39
+ - `knowledge_mounts`: project/session policy overlays for recall, write mode and tag constraints.
40
+ - `knowledge_entries`: current materialized entry state.
41
+ - `knowledge_versions`: immutable snapshots for every create, update, archive or restore.
42
+ - `knowledge_fts`: FTS5 index containing only active entries.
43
+ - `knowledge_candidates`: proposed create/update/conflict decisions and review state.
44
+ - `extraction_jobs`: one idempotency record per `sessionId:turn`.
45
+ - `api_tokens`: token metadata, permissions and SHA-256 token digests.
46
+
47
+ Entry writes, version creation and FTS changes share one `BEGIN IMMEDIATE` transaction. Candidate approval and its resulting entry mutation are also one transaction. WAL mode permits readers during a writer, `busy_timeout` absorbs short contention, and foreign keys prevent orphan versions.
48
+
49
+ An active content hash unique index blocks byte-equivalent duplicate knowledge. Candidate proposals additionally deduplicate by source turn plus proposal hash.
50
+
51
+ ## Extraction flow
52
+
53
+ 1. Awaited `agent/turn-stopping` observes the completed answer before `turn/end` is committed.
54
+ 2. Project mounts are resolved and then overlaid by explicit session mounts; a disabled session mount blocks inheritance.
55
+ 3. Without a writable mount, no extraction model call or job claim occurs.
56
+ 4. The relevant direct user input and final non-empty assistant message are copied into an immutable job snapshot.
57
+ 5. `extraction_jobs` atomically claims `sessionId:turn`; replaying the event cannot duplicate work.
58
+ 6. Existing knowledge is retrieved only from mounted destinations and framed with the conversation as untrusted JSON.
59
+ 7. A bounded auxiliary LLM call returns strict candidate JSON naming one supplied destination.
60
+ 8. Runtime validation rejects unknown destinations, types, targets, arbitrary project IDs and malformed output.
61
+ 9. Audit mounts keep valid proposals pending. Direct mounts auto-approve only non-conflicts at or above the confidence threshold.
62
+ 10. A persistent DSH notice reports per-base direct and pending counts below the answer; failures produce a retryable failure notice.
63
+ 11. Before every later model request, plugin notices with `form: notice` are removed from the request message list. They remain durable UI feedback but never consume or influence model context.
64
+
65
+ The extractor explicitly refuses secrets and ephemeral output in its system policy. Conflict and low-confidence proposals always remain behind human review.
66
+
67
+ ## Recall flow
68
+
69
+ Recall is a hybrid of a replaceable runtime-context catalog, proactive snippets, and model-driven tools:
70
+
71
+ - `system-prompt/assemble` resolves the current session mounts and publishes only knowledge-base names, descriptions and tag filters as a lightweight runtime-context snapshot;
72
+ - `agent/pre-step` sees only the current claimed user input and proactively searches a small configurable number of snippets (default 3);
73
+ - `knowledge_search` lets the model issue a focused natural-language query across all or one mounted base;
74
+ - `knowledge_read` opens an exact matched section through a signed, session-bound handle and paginates unusually long content;
75
+ - remote retrieval can be awaited;
76
+ - cancellation propagates through the current turn signal;
77
+ - proactively injected snippets are attributed as plugin `dsh-knowledge`, form `recall`;
78
+ - retrieval failure is fail-open and never prevents a model response.
79
+
80
+ Only active entries from recall-enabled resolved mounts are searched. Each search and read applies that mount's include/exclude tag constraints and project scope. Exact project entries are ordered before global entries. Proactive retrieval injects only compact snippets and handles; full content enters the model context only after an explicit `knowledge_read` call. The framing tells the model that knowledge is contextual data and cannot override current system or user instructions.
81
+
82
+ ## Local and remote topology
83
+
84
+ Local and remote modes are mutually exclusive for one plugin instance. There is deliberately no transparent cache or two-way synchronization: that would create conflict semantics at a second layer and obscure which database is authoritative.
85
+
86
+ A local provider may expose the API and become a central service. Remote clients use the same provider contract, so extraction candidates and recall work identically. Network timeouts and DSH turn cancellation bound remote requests.
87
+
88
+ ## Security boundaries
89
+
90
+ - Secrets are configuration-only and are never returned by plugin APIs or written to logs.
91
+ - Server tokens are stored as SHA-256 digests; generated client tokens are shown once.
92
+ - Permissions are capability-oriented: `read`, `propose`, `write`, `admin`.
93
+ - Request bodies are capped at 1 MiB and every domain value has size/range validation.
94
+ - Hard deletion and token management require admin.
95
+ - Remote URLs require HTTPS except explicit loopback testing.
96
+ - Tool handles are HMAC-signed, bound to the calling session, and re-authorized against live mount, project and tag policy on every read.
97
+ - The embedded DSH web server has no TLS; LAN/public exposure requires an HTTPS reverse proxy.
98
+ - The management console uses the same Bearer permissions as every other client, never puts tokens in URLs, and ships with a restrictive Content Security Policy.
99
+
100
+ ## Deferred modules
101
+
102
+ - Explicit export/import jobs.
103
+ - Optional embeddings/reranking behind a retrieval port.
104
+ - Retry controls for failed extraction jobs.
105
+ - Multi-user tenant isolation.
106
+
107
+ These are additions around existing boundaries; none requires changing the entry, candidate or provider semantics.
@@ -0,0 +1,329 @@
1
+ # DSH Knowledge 文档型知识库设计
2
+
3
+ 状态:设计稿 v1(`0.4.0-alpha.3` 已部署可视化投影阶段)
4
+ 参考:Nomifun Desktop 文档型知识库、DSH 插件现有多库/挂载/审核能力、Apple 桌面端信息架构原则
5
+
6
+ ## 1. 结论
7
+
8
+ 知识库改为“Markdown 文档是内容真源”,不再把每条知识作为用户界面的一级对象。
9
+
10
+ - 用户看到并维护的是知识库、目录和 Markdown 文档。
11
+ - 模型回写的是某篇文档中的一段新内容,而不是一张孤立知识卡片。
12
+ - 搜索与召回仍按标题、段落和标签切块,内部索引不暴露为满屏卡片。
13
+ - 待审核内容仍按提案逐条展示,因为审核对象需要明确的目标文档、变更内容和理由。
14
+ - 现有项目/会话挂载、每库回写模型、审核/直写模式继续保留。
15
+
16
+ 这是一种“文档真源 + 段落索引 + 变更提案”的混合架构。
17
+
18
+ `0.4.0-alpha.3` 为了安全兼容已有召回与版本历史,暂时由已生效条目自动投影 Markdown 文档;用户已可以三栏浏览和搜索。后续迁移完成后再将 Markdown 目录切换为唯一内容真源。
19
+
20
+ ## 2. 从 Nomifun 采用的设计
21
+
22
+ 采用:
23
+
24
+ 1. 一个知识库对应一个 Markdown 目录。
25
+ 2. 目录和 `.md` 文件是可浏览、可编辑的知识内容。
26
+ 3. 根 `README.md` 提供知识库摘要,目录树生成有界 TOC。
27
+ 4. 回写模型输出 `knowledgeBaseId + relPath + content`。
28
+ 5. 更新已有文档时只追加真正的新材料,不让模型重写整篇文档。
29
+ 6. 文件写入采用目标锁、内容比对、原子替换和 CAS,避免并发覆盖人工编辑。
30
+ 7. 会话只向模型暴露挂载知识库的摘要和 TOC,不把整个知识库塞进提示词。
31
+
32
+ 不直接照搬:
33
+
34
+ 1. DSH 保留审核写入;Nomifun 当前主线更偏直接写入。
35
+ 2. DSH 保留每知识库独立回写模型,未指定时跟随当前会话模型。
36
+ 3. DSH 保留知识库描述作为回写匹配规则。
37
+ 4. DSH 需要原生远程 API,使其他客户端可连接中央知识服务。
38
+ 5. DSH 的直接写入仍受置信度阈值约束;冲突永远进入审核。
39
+
40
+ ## 3. 内容与存储模型
41
+
42
+ ### 3.1 知识库
43
+
44
+ ```ts
45
+ interface KnowledgeBase {
46
+ id: string
47
+ name: string
48
+ description: string // 判断当前对话是否属于这个库
49
+ defaultTags: string[]
50
+ extractionInstructions: string
51
+ storage: {
52
+ kind: 'managed' | 'directory'
53
+ rootPath: string
54
+ }
55
+ writebackRoute?: {
56
+ provider: string
57
+ model: string
58
+ } // 缺省即跟随当前会话模型
59
+ status: 'active' | 'archived'
60
+ }
61
+ ```
62
+
63
+ - `managed`:服务拥有目录,默认位于 `/data/knowledge/bases/{id}`,允许创建、重命名和删除文档。
64
+ - `directory`:引用用户已有的绝对路径,服务不删除目录结构,只在授权范围内编辑 Markdown。
65
+ - 远程客户端不直接访问文件路径,统一通过文档 API 操作。
66
+
67
+ ### 3.2 文档
68
+
69
+ 文件系统中的 `.md` 是内容真源;SQLite 保存注册信息、索引、版本和写入任务。
70
+
71
+ ```ts
72
+ interface KnowledgeDocument {
73
+ id: string
74
+ knowledgeBaseId: string
75
+ relPath: string // 例如 architecture/runtime.md
76
+ title: string // 第一处 Markdown 标题,缺省取文件名
77
+ content: string
78
+ contentHash: string
79
+ version: number
80
+ size: number
81
+ modifiedAt: string
82
+ }
83
+ ```
84
+
85
+ 内部派生表 `document_chunks` 按标题和段落切块,保存 FTS 文本、标签、类型、范围和来源。它用于召回,不作为用户界面的一级实体。
86
+
87
+ ### 3.3 版本与提案
88
+
89
+ ```ts
90
+ interface DocumentWriteProposal {
91
+ id: string
92
+ knowledgeBaseId: string
93
+ relPath: string
94
+ operation: 'create' | 'append' | 'conflict'
95
+ baseContentHash?: string
96
+ markdown: string // 仅新增内容
97
+ reason: string
98
+ confidence: number
99
+ source: { sessionId: string; turn: number; messageId?: string }
100
+ status: 'pending' | 'approved' | 'rejected'
101
+ }
102
+ ```
103
+
104
+ - 创建文档:目标路径不存在时原子创建。
105
+ - 追加文档:读取现有内容,块级去重后追加,发布前验证 `baseContentHash`。
106
+ - 冲突:绝不自动写入,必须审核。
107
+ - 版本表保留每次创建、追加、人工编辑、归档的快照,支持查看和恢复。
108
+
109
+ ## 4. 回写流程
110
+
111
+ ```text
112
+ 回答完成
113
+ → 解析当前项目/会话挂载
114
+ → 按有效回写模型分组
115
+ → 每组加载知识库描述、README 摘要、TOC、相关文档片段
116
+ → 模型判断是否值得收录并选择目标文档
117
+ → 安全校验、去重、路径校验
118
+ → 审核提案 或 直接追加
119
+ → 在回答下方显示可点击的回写结果
120
+ ```
121
+
122
+ ### 4.1 模型选择
123
+
124
+ 优先级固定为:
125
+
126
+ 1. 知识库显式设置的 `writebackRoute`。
127
+ 2. 旧版全局提取模型(只用于配置兼容,不在新部署中强制设置)。
128
+ 3. 当前回答实际使用的会话模型。
129
+
130
+ 同一轮挂载多个模型时按路由分组调用。每次调用只能看到本组知识库,防止写入错误目标。
131
+
132
+ ### 4.2 Kimi 等推理模型的稳定性
133
+
134
+ - 首次调用使用原模型和配置预算,不偷换模型。
135
+ - `max-tokens` 时以更短的严格 JSON 提示重试。
136
+ - 重试使用 `reasoningEffort: low` 和最高 8192 输出预算。
137
+ - 模型不支持该参数时,只撤掉该参数重试,不切换 provider/model。
138
+ - 每组只提供有界 TOC 和相关片段,减少模型在路径选择上的推理消耗。
139
+ - 明确指定的模型不可用时显示失败,不静默换成其他模型。
140
+
141
+ ### 4.3 模型输出
142
+
143
+ ```json
144
+ {
145
+ "candidates": [
146
+ {
147
+ "knowledgeBaseId": "kb-id",
148
+ "relPath": "deployment/docker.md",
149
+ "operation": "append",
150
+ "markdown": "## 生产部署端口\n\n服务统一监听 3080。",
151
+ "confidence": 0.93,
152
+ "reason": "这是可跨会话复用的已确认部署约定"
153
+ }
154
+ ]
155
+ }
156
+ ```
157
+
158
+ 限制:
159
+
160
+ - 路径必须为库内相对 `.md` 路径,禁止绝对路径、路径穿越和隐藏系统目录。
161
+ - 内容必须是新增 Markdown,不允许要求模型返回整篇修改后的文件。
162
+ - 回写前后各执行一次凭据脱敏。
163
+ - 相同 Markdown 块已存在时视为幂等成功,不重复追加。
164
+ - 一轮最多 5 个提案,单提案和总字符数均设硬上限。
165
+
166
+ ## 5. Apple 桌面端界面
167
+
168
+ 主界面采用三栏 `NavigationSplitView` 思路,检查器按需展开。
169
+
170
+ ```text
171
+ ┌──────────────┬──────────────────────┬───────────────────────────────────┐
172
+ │ 知识库 │ 文档 │ 项目规范 / deployment/docker.md │
173
+ │ │ │ │
174
+ │ ⌕ 搜索 │ ⌕ 搜索当前库 │ # Docker 部署 │
175
+ │ │ │ │
176
+ │ 智能列表 │ README.md │ 正文阅读 / 编辑 │
177
+ │ 待审核 3 │ architecture/ │ │
178
+ │ 最近更新 │ runtime.md │ │
179
+ │ │ deployment/ │ │
180
+ │ 我的知识库 │ docker.md │ │
181
+ │ 项目规范 │ │ │
182
+ │ 个人偏好 │ │ │
183
+ │ │ │ │
184
+ │ + 新建 │ + 新建文档 │ 标签 历史 来源 ⋯ │
185
+ └──────────────┴──────────────────────┴───────────────────────────────────┘
186
+ ```
187
+
188
+ ### 5.1 第一栏:知识库导航
189
+
190
+ - 常驻全局搜索。
191
+ - 顶部智能列表:待审核、最近更新、已归档。
192
+ - 下方显示知识库名称、标签色点和文档数量。
193
+ - 单击切换知识库;上下方向键移动选择;回车打开。
194
+ - “挂载范围”作为工具栏按钮打开批量管理 Sheet,不与文档树混排。
195
+
196
+ ### 5.2 第二栏:文档浏览器
197
+
198
+ - 默认显示目录树;可切换“树 / 最近更新”视图。
199
+ - 文件行显示标题、相对路径、更新时间;目录懒加载。
200
+ - 搜索匹配标题、路径、正文和标签。
201
+ - 支持新建文档/目录、重命名和移动。
202
+ - `README.md` 固定靠前,作为当前库的说明首页。
203
+ - 选择状态表现为整行填充 + 前导强调条,不能只靠颜色。
204
+
205
+ ### 5.3 主区:文档阅读与编辑
206
+
207
+ - 默认阅读模式,工具栏切换编辑。
208
+ - Markdown 编辑器和预览不同时占用主区;需要时使用分栏预览。
209
+ - 标题、正文是一级内容;路径、标签、模型、范围、来源、版本放入可收起检查器。
210
+ - 自动保存前显示保存状态;外部文件发生变化时提供“重新加载 / 查看差异”,不直接覆盖。
211
+ - 窄窗口依次折叠检查器、文档栏;手机宽度使用逐级导航,不强挤三栏。
212
+
213
+ ### 5.4 审核界面
214
+
215
+ 审核是文档变更,不再是孤立知识卡片:
216
+
217
+ ```text
218
+ 目标:项目规范 / deployment/docker.md
219
+ 操作:追加 1 个章节 置信度 93%
220
+
221
+ 现有文档末尾
222
+ ────────────────────────────
223
+ + ## 生产部署端口
224
+ + 服务统一监听 3080。
225
+
226
+ [拒绝] [编辑后通过] [通过]
227
+ ```
228
+
229
+ 创建文档显示完整预览;追加显示目标文档上下文和新增块;冲突显示双方内容。审核动作必须有清晰文字,不使用只有图标的关键按钮。
230
+
231
+ ### 5.5 项目/会话批量挂载 Sheet
232
+
233
+ - 顶部分段控件切换“项目 / 会话”。
234
+ - 常驻搜索,可按已挂载、未挂载、继承项目、已关闭筛选。
235
+ - 列表行显示库名、描述、标签、回写模型和当前模式。
236
+ - 进入选择模式后显示复选框和固定批量操作栏。
237
+ - 批量挂载以事务提交;会话“恢复继承”删除显式覆盖,而不是写入关闭状态。
238
+ - 默认批量设置:召回开启、审核写入、标签过滤为空。
239
+
240
+ ### 5.6 对话内回写反馈
241
+
242
+ 回答下方显示单行、可展开状态:
243
+
244
+ ```text
245
+ 知识库回写 · 项目规范 / deployment/docker.md · 待审核 1
246
+ ```
247
+
248
+ - 点击打开对应提案或文档,不跳到无关首页。
249
+ - 提取中显示进度;无需收录、失败、部分成功均使用不同文案。
250
+ - 失败要显示实际模型和可重试入口,不能只有“失败”。
251
+
252
+ ## 6. 文档 API
253
+
254
+ ```http
255
+ GET /knowledge-bases/:id/tree?path=
256
+ GET /knowledge-bases/:id/documents/:path
257
+ PUT /knowledge-bases/:id/documents/:path
258
+ DELETE /knowledge-bases/:id/documents/:path
259
+ POST /knowledge-bases/:id/documents/move
260
+ GET /knowledge-bases/:id/documents/:path/versions
261
+ POST /knowledge-bases/:id/documents/:path/restore
262
+
263
+ GET /writeback-proposals
264
+ POST /writeback-proposals/:id/review
265
+
266
+ POST /mounts/bulk
267
+ ```
268
+
269
+ 所有写文档请求带 `expectedContentHash`。哈希不一致返回 `409 Conflict` 并提供当前版本,客户端不得自动覆盖。
270
+
271
+ ## 7. 现有数据迁移
272
+
273
+ 当前生效知识迁移为文档:
274
+
275
+ 1. 每个知识库创建 `README.md`。
276
+ 2. 旧条目按类型写入 `migrated/preferences.md`、`facts.md`、`decisions.md`、`procedures.md`、`lessons.md`。
277
+ 3. 每条旧知识变成一个二级标题段落,来源、标签、范围写入隐藏的结构化注释或内部 chunk 元数据。
278
+ 4. 迁移完成前后核对条目数、正文哈希和知识库归属。
279
+ 5. 旧表保留一个版本周期只读兼容,确认后再移除。
280
+
281
+ 示例:
282
+
283
+ ```md
284
+ # 决策
285
+
286
+ ## Docker 服务监听端口
287
+
288
+ 生产部署统一监听 3080。
289
+ ```
290
+
291
+ 迁移后新回写直接选择合适文档,不继续生成“一条知识一个文件”。
292
+
293
+ ## 8. 分阶段实现
294
+
295
+ ### 阶段 A:文档内核
296
+
297
+ - 文件存储适配器、路径安全、原子写、CAS、版本。
298
+ - 文档树/read/write API。
299
+ - 旧知识迁移和段落索引。
300
+
301
+ ### 阶段 B:文档回写
302
+
303
+ - TOC/README 摘要。
304
+ - 每库模型分组。
305
+ - create/append/conflict 提案。
306
+ - Kimi 低推理重试、幂等追加和审核差异。
307
+
308
+ ### 阶段 C:Apple 三栏 Web UI
309
+
310
+ - 知识库栏、文档栏、阅读编辑区、检查器。
311
+ - 审核变更视图。
312
+ - 搜索、键盘、焦点、明暗主题和响应式。
313
+
314
+ ### 阶段 D:挂载与部署
315
+
316
+ - 事务型批量挂载 Sheet。
317
+ - DSH 会话入口和回写状态深链接。
318
+ - Docker 升级、迁移备份、远程客户端联调。
319
+
320
+ ## 9. 本版验收标准
321
+
322
+ 1. 用户日常浏览时看到文档和目录,不再看到满屏知识卡片。
323
+ 2. 模型永远不能用回写覆盖整篇人工文档。
324
+ 3. Kimi 或其他推理模型在首次超限后能用同一模型完成有界重试。
325
+ 4. 每库模型为空时跟随会话,显式设置时只覆盖该库。
326
+ 5. 十个以上知识库可以搜索并批量挂载,无逐库滚动操作。
327
+ 6. 本地目录和远程服务使用同一套文档语义与 API。
328
+ 7. 迁移前后的有效知识数量和内容可核对、可回滚。
329
+ 8. 界面支持键盘导航、可见焦点、明暗主题和窄窗口折叠。