[返回项目介绍](../README.md)

# 使用与配置


[![npm](https://img.shields.io/npm/v/%40lemoncat7%2Fdsh-knowledge)](https://www.npmjs.com/package/@lemoncat7/dsh-knowledge)
[![GitHub Release](https://img.shields.io/github/v/release/lemoncat7/dsh-knowledge)](https://github.com/lemoncat7/dsh-knowledge/releases/latest)
[![awesome · DSH plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)

`dsh-knowledge` 是面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的知识库插件。它不修改 DSH Agent Loop，同一个插件既能使用本地 SQLite，也能连接远程中央知识库。

## 回写与当前能力

### 分享导入的网络策略

从其他实例导入分享时，清单、文件内容及每次重定向都使用经过地址校验的直连请求，不继承 `HTTP_PROXY`、`HTTPS_PROXY` 或 `NODE_USE_ENV_PROXY` 的环境代理。这样实际连接的 IP 才与本次安全检查一致；只作用于笔记分享导入，不修改模型、联网搜索或其他插件的代理设置。

内网分享仍需确认本次访问或配置精确可信 Origin，确认不会扩展到其他分享；敏感地址拦截、逐跳校验和 HTTPS 证书验证保持启用。DSH 服务所在设备必须能直接访问目标分享；只有通过代理才能访问的公网分享不在当前直连策略支持范围内。不要通过关闭证书校验解决网络问题。

### 回写任务管理

知识工作区的“回写任务”，以及回答下方的“管理回写”，可查看本机持久化队列。按创建先后倒序显示，最新任务在前，每页最多 50 条，可按会话筛选，查看创建日期时间、尝试次数、下次重试时间、阻塞任务、失败原因及完成后的目标文档。旧记录未保存创建时间时明确标注，不用迁移时间冒充。即使连接中央知识库，这里管理的也是当前 DSH 客户端的队列。

- 网络等暂时错误最多自动尝试 5 次，之后保留为失败项，支持手动重试。重试复用原快照和已保存的计划，不使用后续对话重新生成旧任务。
- 服务正常关闭后恢复排队；进程意外退出时，在旧工作租约到期后恢复（租约为 60 秒）。失败项仍需处理，不会在每次启动时无限重试。
- 同会话正常按顺序回写；执行失败后间隔 5、15、60、180 秒自动重试（共最多 5 次尝试），不依赖错误文案。耗尽后保留失败记录、原始快照和写入计划，自动放行后续轮次；历史失败项也不再阻塞队列，可在回写任务中手动重试或取消。重试沿用幂等与版本冲突检查。服务停止、连接切换和远端执行租约等待不计入失败次数；其他会话可继续处理。
- 排队和失败项可立即取消。执行中的任务先记录取消请求，待当前执行退出后完成取消，期间不提前放行后续任务。取消请求在重启后仍有效；已写入内容不撤销，也不支持恢复已取消的任务。
- 页面通过共享长轮询接收状态变更通知，收到变化后立即查询最新状态，同时保留每 5 秒刷新队列的兜底。隐藏后暂停连接，重新显示或网络恢复后重新同步；原回答下也使用共享通知通道。确认记录不存在时清除旧等待状态，查询网络失败则提示重连，不误报任务不存在。历史版本未保存快照的任务不能安全重试。

当前版本提供可部署的多知识库、按需检索工具、本地与远程中央服务、文档型 Web 管理台，以及全局回写策略与安全直写协调：

- 回答完成后保存本轮快照，后台使用对应模型判断是否产生知识，并在原回答下方显示逐库回写结果。
- 知识标题、正文、自然语言标签和提取理由默认跟随本轮用户语言；代码、命令和技术标识保持原样。
- 回写结果只作为 UI 状态展示，在下一次模型请求前会被移除，不占用会话上下文。
- 全局“严谨 / 主动”回写策略保存在权威知识库服务中；远程客户端自动跟随中央设置。严谨模式不限制候选数量，而是以长期价值和较高置信度为门槛，接受用户明确陈述以及带具体来源的可靠调研结论。
- 可创建多个知识库，分别设定说明、默认标签和提取要求。
- 每个知识库可选择专用回写模型；未设定时跟随当前会话模型。
- 项目和会话挂载；会话默认继承项目，也可独立覆盖或关闭。
- 每个挂载支持仅召回、审核写入、直接写入，以及包含/排除标签和额外提取要求。
- `create / update / conflict / skip` 文档变更决策；更新会明确区分“补充新内容”和“修订过时原文”，不再用追加文本冒充原文修改。
- 原文修订使用唯一旧文本锚点和目标版本，由服务端在完整文档上原子执行。无关并发补充可安全重放；同一区域已变化时才转为真实冲突并进入人工解决。
- 未挂载知识库时，不召回、不提取、不回写。
- 全局与项目范围，以及偏好、事实、决策、流程、经验五类知识。
- SQLite WAL、FTS5 全文搜索、原子事务、完整版本历史和幂等提取任务。
- 回答前通过 DSH 官方提示组装接口提供有界的挂载库地图，并自动召回最多 3 条达到相关性门槛的摘要；不自动注入完整文档。模型可继续按“`knowledge_base_search` 找库 → `knowledge_search` 搜索指定库 → `knowledge_read` 读取文档”的顺序核对完整内容。这些是 `knowledge` 统一入口下的操作名，先 `action=describe` 查询参数，再 `action=call` 执行；详见[统一工具入口](tool-entry.md)。
- 普通知识沉淀独立于主 Agent：主模型不暴露通用 `knowledge_write`，在回答结束后由独立提取调用处理，真实回写状态显示在回答下方。
- 用户明确确认“问题已解决”或“收集完成／结束”时，Agent 可通过 `knowledge_document_status` 更新对应知识状态，也支持回答后的自动提取。工具先搜索并读取目标文档，提交当前版本、用户确认原话和结论；仅解决其中一个问题时只修订对应段落，整篇保持开放。整篇结束保留正文和结论、生成历史版本并停止后续回写，可在界面重新打开。
- 状态更新遵循挂载权限：仅召回不能写，审核模式产生待审核候选，直接模式在版本核验通过后生效；敏感内容转人工审核。Agent 只能按实际工具结果说明“已标记”或“待审核”。不能用模型自述、疑问或普通“好了”封存文档，过期版本也不能确认结束。远程使用同一候选协议，服务端需同步升级到支持文档状态候选的版本，不会在远端失败后回退写本地。
- 用户明确要求时，模型可调用 `knowledge_base_create` 和 `knowledge_base_update` 创建或修改知识库，包括描述、标签、回写策略与专用回写模型；工具内部跟随当前 Provider 自动写入本地 SQLite 或远程中央服务，模型不传也不猜存储位置。
- `knowledge_base_create` 默认不保存专用 provider/model，回写沿用本机覆盖设置，否则跟随每次会话；即使连接远程知识库，也不复制远端模型配置。只有明确指定 `useCurrentSessionModel: false` 时，才要求并校验成对的专用模型参数。默认模式下旧调用夹带的模型字段会被忽略，并在结果中说明。
- 创建或修改工具不会自动挂载知识库，也不会回退、双写或同步到另一端；结果会明确返回实际写入的 `local` 或 `remote`。
- 搜索和读取由服务端按当前会话挂载、项目范围及包含/排除标签强制限权，读取句柄带签名且仅限当前会话。
- 本地与远程 Provider 使用同一接口；远程模式不做隐式双向同步。
- DSH“设置 → 插件”提供“知识库连接”卡片，可选择本地来源或填写中央服务地址和只写客户端令牌，保存后实时验证并切换 Provider。
- Bearer Token 仅保存 SHA-256 摘要，支持 `read / propose / write / admin` 权限及吊销。
- 认证 HTTP API，可作为其他 DSH 客户端和未来桌面端的中央知识库。
- 笔记软件式双栏文档界面：左侧以“知识库 → 文档”树形目录浏览和新建，右侧支持 Markdown 编辑与安全预览；目录按知识库懒加载并分页，只有打开文档时才读取正文。已有文档默认预览，新建文档默认编辑。
- 每个生效主题对应一篇真实 Markdown 文档；相似知识作为章节或增量内容写入同一文档。创建、改名、保存、归档和删除会同步 SQLite、全文索引、版本历史与物理文件。
- 独立的笔记工作区：在知识工作区上方提供可无限嵌套的目录树，支持 Markdown 与常见文本文件直接编辑，图片和 PDF 就地浏览，以及任意文件的拖拽移动、复制、重命名、下载和只读分享。主侧栏中的独立“已分享”页面集中管理本机链接，也能读取其他 DSH 的分享清单并将文档或完整目录复制到指定笔记目录。Markdown 编辑器提供标题大纲定位、文内查找与替换、选择结束后出现的浮动格式菜单和 `Ctrl/Cmd + F` 快捷键；每次保存会形成按需读取的页面历史，可预览、比较并恢复为新版本。笔记默认不参与知识检索、自动召回或 AI 回写。
- 分享导入保留 SSRF 防护；域名解析到内网或使用内网 IP 时，导入弹窗提示目标 Origin，管理员点击「允许本次内网分享并读取」后即可继续，无需预先配置白名单。确认仅绑定当前分享链接，修改链接或关闭弹窗即清除，不持久化；不允许借此访问回环、链路本地/云元数据地址或其他分享和接口，重定向仍逐跳校验。原有 `trustedShareOrigins` 和远程访问插件的可信 Origin 配置继续兼容。
- 知识文档使用独立的“关联笔记”列表引用笔记文档或文件，正文不再插入引用语法。关系绑定稳定编号，笔记移动或改名不会失效；旧 `note://` 引用会在升级时安全回填为结构化关系。
- AI 可使用 `knowledge_note_list / search / read` 浏览和读取笔记，无需额外的语义授权；创建、更新、改名和移动先生成提案，展示变更后等待用户在下一轮对话确认。所有目标都使用当前会话签名句柄，远程操作继续服从令牌权限，删除仍有独立的明确授权边界，被知识文档引用的笔记不能直接删除。
- `knowledge_note_references` 单独负责查看、添加或移除知识文档与笔记的结构化关联，并在执行时重新检查知识挂载范围、写入模式和文档封存状态。
- 文档可标记为“已解决”或“已收集完成”。结束后的文档仍参与搜索和召回，但被服务端强制封存为只读；AI 回写、候选审核和人工编辑都必须先重新打开文档。
- 知识库管理拆分为“知识库”和“项目与会话挂载”两个工作区；支持按名称、描述、标签和模型即时搜索，避免知识库较多时逐张翻找。
- 随插件安装的响应式 Web 管理台，覆盖概览、文档树与编辑器、AI 候选审核和客户端令牌管理。
- DSH 浏览器端插件：在左侧工作区下方显示“知识库”，并在当前页面内打开管理面板。
- 明暗主题、键盘操作、窄屏布局以及不依赖颜色的状态标签。

## 安装

从 npm 安装正式版：

```bash
dsh plugin --profile web add @lemoncat7/dsh-knowledge
```

需要固定版本时，将 `<version>` 替换为对应的发布版本：

```bash
dsh plugin --profile web add @lemoncat7/dsh-knowledge@<version>
```

也可以从 [GitHub Releases](https://github.com/lemoncat7/dsh-knowledge/releases) 下载对应版本的完整预构建包后安装：

```bash
dsh plugin --profile web add ./lemoncat7-dsh-knowledge-<version>.tgz
```

卸载：

```bash
dsh plugin --profile web remove @lemoncat7/dsh-knowledge
```

插件是标准 DSH profile bundle：`package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`。安装后不需要单独运行知识库容器。

安装或更新后请重启对应的 DSH profile。Web 版重启命令：

```bash
pnpm dsh web
```

## DSH 插件商店

本仓库符合 DSH 社区目录的安装要求：声明了 `dsh.bundle`、发布了 npm 预构建包，并使用 GitHub `dsh-plugin` Topic。目录收录完成后，可在 DSH 的插件市场搜索 `dsh-knowledge` 或“知识库”，安装源为 `@lemoncat7/dsh-knowledge`。

插件商店的数据来自 [awesome-dsh-plugin.com](https://awesome-dsh-plugin.com)，不是单靠 npm 标签自动生成。若商店尚未刷新，可先使用上面的 npm 命令安装。

## 本地模式

默认配置使用 DSH 持久目录中的 SQLite 文件：

```yaml
- id: knowledge
  name: '@lemoncat7/dsh-knowledge'
  config:
    backend: local
    databasePath: !!js dshHomePath('knowledge/knowledge.sqlite')
    extractionEnabled: true
    defaultScope: project
    autoRecallLimit: 3
    autoRecallMinScore: 0.2
    recallMaxChars: 5000
    exposeApi: false
    exposeWeb: true
```

本地管理台默认开启。它使用独立的同源管理接口，不要求开放远程 API，也不要求输入访问令牌；侧栏“知识库”安装后即可使用。任何能访问 DSH Web 的用户都具有本地管理权限，因此把 DSH 暴露到公网时，应继续使用反向代理登录保护整个 DSH 站点。

提取模型默认沿用刚完成回答的 provider/model。可在单个知识库中设置专用回写模型；“本机回写模型”是当前客户端的最高优先级覆盖，适合中央知识库在不同客户端使用不同模型。实际优先级为：本机覆盖 → 知识库专用模型 → 当前会话模型 → 以下兼容性后备配置：

```yaml
    extractionProvider: deepseek-official
    extractionModel: deepseek-chat
```

独立模型必须先在 DSH 的模型设置中注册。不论使用 Kimi 还是其他会话模型，首次超限后都会保持原 provider/model，用精简提示和低推理重试，不会暗中换模型。

提取输出达到模型上限时会自动用双倍预算重试一次（最高 8192 tokens）。其他提取失败会将幂等任务标为 `failed`，失败任务最多可重新领取两次，并在回答下方记录回写通知，不会阻断下一轮。

## 中央服务端

需要作为中央知识库时，进入“知识库 → 访问管理”，点击“开启远程 API”。开关会持久化，页面会显示其他客户端应填写的完整 API 地址；然后为每台客户端创建独立令牌。已撤销令牌可以永久删除。

部署自动化仍可通过配置直接启用认证 API：

```yaml
    backend: local
    databasePath: !!js dshHomePath('knowledge/knowledge.sqlite')
    exposeApi: true
    apiToken: !!js process.env.DSH_KNOWLEDGE_API_TOKEN
    apiPrefix: /knowledge-api/v1
    exposeWeb: true
    webPath: /knowledge
```

`DSH_KNOWLEDGE_API_TOKEN` 至少 24 个字符。该值只用于创建或恢复 bootstrap admin 身份；数据库只保存摘要。服务端没有 TLS，非回环部署必须放在 HTTPS 反向代理之后。

启用后访问 `http://<DSH 地址>:<端口>/knowledge`。本地管理台使用同源管理权限；开放给其他客户端的 `apiPrefix` 仍强制要求 Bearer Token。管理台和 API 均由 DSH 自身 WebServer 提供，不需要额外容器。

管理台功能：

- 查看准确的知识、候选和提取任务统计。
- 创建和编辑多个知识库，管理默认标签与提取要求。
- 在知识库页切换全局“严谨 / 主动”回写策略。
- 管理当前项目挂载和会话覆盖，设定召回、写入模式与标签范围。
- 在左侧知识目录中搜索、新建和切换文档，在右侧进行 Markdown 编辑与安全预览；文档区域随窗口自适应，窄屏时知识目录切换为抽屉。
- 在“笔记工作区”中建立多级目录，直接编辑 Markdown、文本、JSON、YAML、代码和配置文件；Markdown 笔记支持标题大纲定位、文内查找/替换，以及选中文字后的段落、标题、列表、引用、代码、链接等快捷格式菜单。页面历史按需加载单个版本，可查看逐行差异并将任意旧版恢复为新的保存记录。工作区同时支持上传、拖放、复制、移动、搜索、下载和就地浏览图片与 PDF；知识文档底部的“关联笔记”栏用于查看、打开、添加和移除资料关系。
- 查看 AI 提取依据和真实增删差异，直接通过、编辑最终文档后通过或拒绝候选。
- 创建、查看和撤销客户端令牌；新令牌原文只显示一次。

输入框的 `@` 菜单支持独立的「笔记文档」分组：跨目录按标题搜索，选中后引用准确的文档 ID，发送时生成当前会话可用的读取句柄。不会混入普通知识条目、目录或附件，也不会授予修改权限；沿用原菜单的方向键、Enter、Tab 与 Escape。详见 [笔记文档引用](../docs/note-mentions.md)。

知识库的 `description` 同时用于读取和回写路由：它以轻量目录形式告诉模型每个挂载库覆盖什么主题，`knowledge_base_search` 也用它匹配当前信息需求；文档正文不会随目录注入。主模型不执行内容回写，所有回答都在完整结束后进行一次独立的严格提取，同时判断长期价值、目标知识库、重复、更新与冲突；用户明确要求保存时也走同一条回答后链路。挂载只表示“可选”，不代表每次回答都要写入。`extractionInstructions` 用于匹配后继续限定具体收录规则。

笔记工具与知识回写相互独立。列举、搜索和读取不要求用户先发送授权句式，也不要求知识库挂载；仍需有效的当前会话句柄和远端服务访问权限。创建、更新、改名和移动支持自然表达需求，但首次工具调用只生成待确认提案，不写入；AI 需展示具体变更，长预览通过 `knowledge_note_preview` 完整读取后，等待用户下一轮对话确认，再用 `knowledge_note_confirm` 执行原提案。不使用弹窗，也不要求复制固定授权段落；提案有效期为 15 分钟，重启、过期、改需求或版本冲突时需重新提案。永久删除仍必须在当前消息中明确提出，不能沿用历史授权。

工具先用 `knowledge_note_list` 浏览目录或按名称搜索，也可用 `knowledge_note_search` 查找非目录节点；随后使用返回的精确句柄。局部修改使用 `replace_range`，多处修改使用同一原文快照的 `batch_edit`，保留未修改正文；仅真正新增内容才使用追加，整篇替换需明确说明影响范围。`knowledge_note_create` 未指定父目录时写入笔记根目录，指定目录时必须使用列表返回的文件夹句柄。本地和远程模式由当前 Provider 决定，工具不猜测存储位置。管理台中的笔记文档和普通文件可从目录列表或工具栏下载。

创建示例：

```json
{
  "draft": {
    "name": "DSH 项目规范",
    "description": "只匹配 DSH 插件开发、架构决策和部署规范相关对话",
    "defaultTags": ["dsh", "project-rule"],
    "extractionInstructions": "只收录已确认且可跨会话复用的结论"
  }
}
```

局部修改标签或描述时使用 `PATCH /knowledge-bases/:id`，请求体为 `{"patch":{"description":"...","defaultTags":["..."]}}`。

主要 API：

| Method | Path | Permission | Purpose |
| --- | --- | --- | --- |
| GET | `/health` | public | 健康检查 |
| GET/PUT | `/settings` | read/admin | 读取或修改全局回写策略 |
| GET / POST | `/search` | read | FTS 检索；长查询使用 POST JSON 请求体，字段为 `text`、`limit`、`projectId`、`knowledgeBaseIds`、`includeTags`、`excludeTags`、`types` |
| GET/POST | `/knowledge-bases` | read/write | 知识库列表和创建 |
| GET/PUT/PATCH | `/knowledge-bases/:id` | read/write | 详情、完整替换和局部修改 |
| POST | `/knowledge-bases/:id/archive` | admin | 归档并关闭相关挂载 |
| POST | `/knowledge-bases/:id/restore` | admin | 恢复已归档知识库 |
| DELETE | `/knowledge-bases/:id` | admin | 永久删除已归档知识库及全部关联数据 |
| GET/POST/DELETE | `/mounts` | read/write | 挂载查询、更新和删除 |
| POST | `/mounts/bulk` | write | 事务型批量挂载与取消 |
| GET | `/mounts/resolve` | read | 解析项目继承与会话覆盖 |
| GET | `/documents` | read | 按知识库或正文搜索 Markdown 文档 |
| GET | `/document-index` | read | 分页读取不含正文的文档目录；支持 `knowledgeBaseId`、`q`、`limit` 和 `cursor` |
| GET | `/documents/:id` | read | 读取单篇 Markdown 文档 |
| POST | `/documents/:id/finalize` | write | 标记为已解决或已收集完成并封存 |
| POST | `/documents/:id/reopen` | write | 重新打开封存文档 |
| GET | `/notes` | read | 懒加载目录子节点，或使用 `q` 搜索笔记；支持 `kind=document` 类型过滤和 `recursive=1` 跨目录列举 |
| POST | `/notes/folders` | write | 在任意层级创建目录 |
| POST | `/notes/documents` | write | 创建可编辑的 Markdown 笔记文档 |
| POST | `/notes/files` | write | 上传原始文件；名称和父目录通过查询参数传入 |
| GET/PATCH/DELETE | `/notes/:id` | read/write/admin | 读取元数据、重命名或移动、递归删除 |
| POST | `/notes/:id/copy` | write | 复制文档、文件或完整目录树 |
| GET/PUT | `/notes/:id/content` | read/write | 读取文件内容，或保存 Markdown 与受支持的文本文件；支持 `?download=1` |
| GET | `/notes/:id/references` | read | 列出引用该节点或其目录后代的知识文档 |
| GET | `/notes/shares` | admin | 列出当前笔记工作区的分享记录 |
| POST/DELETE | `/notes/:id/share` | admin | 创建或停止文档/目录的只读分享 |
| POST | `/notes/import-share/inspect` | read | 校验分享链接并读取有大小上限的清单，不写入内容 |
| POST | `/notes/import-share` | write | 从分享链接复制文档或完整目录到指定笔记目录 |
| GET | `/shared/:token` | public | 打开只读分享页；目录分享只允许访问对应子树 |
| GET | `/shared/:token/content` | public | 读取分享范围内的文件内容，支持 `noteId` 与 `download=1` |
| GET | `/shared/:token/manifest` | public | 返回供导入使用的只读目录清单与内容摘要 |
| GET/POST | `/entries` | read/write | 列表和直接创建 |
| GET/PUT/DELETE | `/entries/:id` | read/write/admin | 详情、更新、彻底删除 |
| GET/POST | `/entries/:id/note-references` | read/write | 查看或添加结构化笔记关联 |
| DELETE | `/entries/:id/note-references/:noteId` | write | 移除一项笔记关联 |
| GET | `/entries/:id/versions` | read | 版本历史 |
| GET/POST | `/candidates` | read/propose | 候选列表和提交 |
| POST | `/candidates/direct` | propose + write | 原子直写、兼容合并、重复跳过和冲突转审 |
| POST | `/candidates/:id/review` | write | 审核候选 |
| GET/POST/DELETE | `/tokens` | admin | 客户端令牌管理 |

路径均位于配置的 `apiPrefix` 下。创建令牌时，原始令牌只在响应中返回一次。

笔记文件上传使用请求体原始字节，不使用 Base64 或 multipart；单文件上限为 64 MiB。目录和文件元数据与知识 SQLite 分开保存在 `notes/notes.sqlite`，内容按稳定编号保存在 `notes/objects/`。知识库删除或归档不会删除笔记；仍被知识文档引用的节点及其上级目录默认禁止删除。

## 远程客户端

先在中央实例的“知识库 → 客户端令牌”中为每台客户端分别创建令牌。普通 DSH 客户端建议选择 `read + propose`。`write` 是当前中央服务的全局写权限，同时允许直接写入知识、管理知识库、挂载和笔记；只在客户端确实需要这些能力时授予。令牌原文只显示一次。

其他 DSH 客户端安装本插件后，打开“设置 → 插件 → 知识库连接”，选择“远程”，填写中央实例的知识库 API 地址和客户端令牌，再点“验证并连接”。插件会先验证地址和令牌，成功后立即热切换，并把连接持久化到 DSH 数据目录；令牌不会在页面或控制接口中回显，只能覆盖。

侧栏“知识库”入口会先通过控制接口确认当前实例是否启用了管理台，确认后才加载管理页面。管理台默认随本地模式启用；只有 profile 显式设置 `exposeWeb: false` 时才关闭。入口不会把未注册的 `/knowledge` 误交给 DSH Web 主页面，因此不会触发 `dsh-plugin-desktop` 参数错误。

如需用配置文件或环境变量部署，也可以直接设置 Provider：

```yaml
- id: knowledge
  name: '@lemoncat7/dsh-knowledge'
  config:
    backend: remote
    remoteUrl: 'https://knowledge.example.com/knowledge-api/v1'
    remoteToken: !!js process.env.DSH_KNOWLEDGE_REMOTE_TOKEN
    extractionEnabled: true
```

远程地址必须是 HTTPS；只有 `localhost` 和回环 IP 的测试地址允许 HTTP。普通客户端建议只分配 `read + propose` 权限。
远程客户端连接的是中央库，不会复制或同步一份本地数据库；断网时无法召回或回写。侧栏管理台仍在当前 DSH 内打开，插件通过同源代理携带已保存的远程令牌访问中央 API，不使用跨域 iframe，也不会把令牌交给浏览器。远程模式隐藏“访问管理”，API 开关和客户端令牌仍由中央 DSH 管理。每台客户端仍需用自己的项目/会话标识挂载所需知识库。

## 开发与 Docker 构建

要求 Node.js `^22.19.0 || >=24.0.0`。

```bash
npm install
npm test
npm run pack:check
```

推荐使用 Node 24 Docker 环境编译、测试并输出 tarball：

```bash
docker build \
  --build-arg NODE_IMAGE=docker.1ms.run/library/node:24-bookworm-slim \
  --target artifact \
  --output type=local,dest=dist .
```

架构和一致性设计见 [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)。

本项目采用 MIT License。
# 挂载知识的引用笔记

已挂载、可召回的知识文档引用了笔记后，AI 可以通过 `knowledge_note_references list` 取得笔记句柄。读取笔记本身无需额外语义授权；更新时若传入 `knowledgeHandle`，会检查当前挂载和实际引用关系。引用关系不代替修改确认：普通会话的正文更新仍需先展示提案，再由用户下一轮确认，并核验目标版本；不会因为知识库可召回就自动获得直接写入或删除笔记的权限。远端服务原有访问权限继续生效。
伙伴轻量关注只使用手动指定的记录位置，不处理依据中的笔记引用。宿主通过 `dshKnowledgeNoteRecording` 读取、校验并更新指定笔记。

## 文档自动同步与保存保护

- 当前打开的知识文档、可编辑笔记约每 5 秒检查一次版本，有变化才读取正文。不扫描整个文档库；后台标签暂停请求，网络失败自动退避重试。
- 未编辑时自动更新并保留滚动位置；有未保存修改或正在输入时保留编辑器，提示“文档有新版本”。差异窗口可对照最新内容手动整理，应用为草稿后再保存；放弃草稿需要确认。
- 页面保存携带读取时的版本；保存过程中继续输入的内容仍标记为未保存。服务端拒绝过期版本，不自动覆盖，也不自动创建被删除的文档。
- `knowledge_note_read` 返回 `note.version`。`knowledge_note_update` 的正文追加、替换必须携带 `expectedVersion`；版本过期需重新读取和合并，重命名不需要正文版本。
- 指定关注记录的内容哈希检查保留，实际写入进一步在笔记写入队列内校验版本。知识文档的版本校验与写入位于同一数据库事务。
- 这是自动同步与冲突保护，不是多人逐字协同。远端知识服务也需要更新到支持版本校验的版本。
# 内置工作日报

在「知识库 → 工作记录 → 工作日报」使用，无需独立日报插件。适配 DSH 0.1.7-rc.2。
采集默认关闭；支持全部目录、树状勾选当前/已记录的工作目录、手写路径，以及从 DSH 已配置模型中选择整理模型。

「采集设置 → 选择目录」提供可展开的工作目录树。目录树仅根据当前 DSH 实例的默认工作目录、观察到的会话工作目录、当前会话和手动添加的路径构建，不读取磁盘目录，也不把中央接收的其他机器路径或手工补记当成本机项目；自动补出父级节点，父目录没有会话也能勾选。这里的“本机”是运行 DSH 的实例，并非浏览器所在电脑。展开与勾选相互独立；方向键浏览/展开，空格勾选。旧版混合目录表会按来源修复，本地与远端同时出现的路径需有本机会话依据才能恢复；历史配置不删除、不重写，缺少本机依据的已选路径单独收在“其他已保存目录”中。

采集设置只在“本机采集”和“中央整理”两个分区保留小型「？」提示，支持悬浮、键盘聚焦及点按，Esc 先关闭提示；权限、离线和错误消息仍直接显示。目录树首次显示只展开本机默认工作目录的祖先，使默认目录可见，其子目录及其他分支仍收起；当前 DSH 使用服务启动工作目录作为未指定工作区或 cwd 时的默认值，不取当前会话或远端中央目录。默认值不可用时全部收起，不因已有勾选自动展开；主动添加目录时仍展开定位。手动收起后，轮询刷新不重新展开。采用紧凑单行布局，展开高度受限，支持一键收起且不改变勾选；树下不再重复展示当前目录路径。模型刷新按钮与选择框同排，刷新失败保留原选择并显示错误。

树外的「包含所选目录的子目录」默认关闭，保持原来的路径精确匹配。开启后，例如选择 `/work`，会包含 `/work` 本身及 `/work/project-a` 等任意层级子目录，但不包含 `/workshop`。树中下级标注「上级已包含」，不会逐个写入选择列表；取消父级后，原本单独勾选的子目录仍保留。若只需要部分下级，应取消父级后分别勾选。依据是会话工作目录（`header.cwd`），不是会话分组或终端里的 `cd`；保存后仅影响后续采集，不扫描历史。排除会话仍然优先。

子目录匹配按路径层级处理末尾分隔符及 `.` / `..`；支持 POSIX 绝对路径（区分大小写）、Windows 盘符和 UNC 共享路径（不区分大小写、兼容正反斜杠）。相对路径只精确匹配，不按服务进程目录推算，也不解析符号链接。该开关只保存在当前 DSH 实例，远程模式和中央离线时也可通过「仅保存本机采集」修改，不改变其他实例的范围。

支持日期、补记、来源核对、编辑、导出、历史版本和持久化重试；日报数据独立存储，不混入知识文档。
试用版升级会复用原 worklog/worklog.sqlite；部署时应先移除旧 dsh-worklog bundle 注册，保留数据库，防止双重执行。

### 中央统一日报

日报跟随知识库连接：本地模式的 DSH 是日报存储/整理节点；远程模式仅采集和补传，浏览、编辑、模型列表和定时配置均来自已连接的中央知识库。**中央与采集端都需要升级到支持统一日报的版本**，中央需开启知识库远程 API。旧中央不支持时显示升级提示，不悄悄切回本地日报。

- **本机采集**：启用开关、项目范围、本地工作目录、排除会话由每个 DSH 实例独立保存。断网时也可单独关闭采集；已授权进入上传队列的素材仍会补传。
- **中央整理**：时区、模型、每日整理时间和开关统一管理。上传素材按中央时区归日；客户端模型 ID 不直接用于中央生成。请在中央模型列表选择可用模型，避免中央没有对应本机模型。远端模式不会运行原本地整理队列。
- **断网补传**：来源先写入本地 SQLite 上传队列，指数退避重试（最长间隔 5 分钟），可手动重试。来源使用持久实例 ID + 原记录 ID 去重；成功回执后清掉队列中的正文，只保留去重凭证。中央记录被排除后，重复上传不会重新纳入。
- **目标隔离**：队列绑定采集时的中央地址，切换连接不把旧来源发到新中央；回到原地址后继续。同一地址的中央实例 ID 改变时暂停上传并提示，不自动将旧数据交给替代实例。
- **历史迁移**：点击「迁移本地历史」并确认后，来源进入上传队列，已有日报/历史版本作为中央历史归档，不覆盖中央正文。本地数据仍保留；不迁移原本地模型/定时配置或未完成的生成任务。重复迁移可去重。
- **认证和权限**：中央使用现有 Knowledge Bearer Token：读取需要 `read`，来源上传/补记/整理需要 `write`，中央设置和历史日报迁移需要 `admin`。本机网页入口仍需 Host 登录认证。这里是同一中央的共享工作记录，不是按令牌隔离的私人日记，勿给不可信人员中央读取权限。

来源跨实例汇总，但不会尝试在本机打开其他实例的会话。补传状态在页面显示；中央离线时明确报错，本机采集设置仍可修改。

### 每日定时整理

在「采集设置 → 中央整理 → 定时整理」开启，选择每日时间（默认建议 23:00），按中央设置中的 IANA 时区运行。默认关闭；保存后从下一个设定时间开始，浏览器无需保持打开，但中央 DSH 服务必须运行。

每次整理目标为该日期截至执行时的已采集/补记素材，使用同一模型设置及持久任务队列。采集开关与整理开关独立：关闭采集后，仍可定时整理手工补记。不覆盖人工编辑的正文；无新素材不调用模型；到点后新增的素材可手动更新日报。既有任务运行时等待其结束再判断是否需要整理。

每日触发标记与任务入队在同一事务中持久化；服务重启只补最近一次错过的日期，不批量回填历史。网络失败沿用最多三次自动尝试，失败后在对应日期手动重试。设置中显示最近一次定时检查结果。修改执行时间或时区从新设置的下一次时间生效；关闭定时不取消已入队任务，可在日报页面单独取消。
