メインコンテンツへスキップ
C

dsh-sag-wiki

clear0/dsh-sag-wiki

Adds four tools that query a local SAG Wiki index through the installed SAG CLI: semantic search, exact or regex match, and index status or update. Needs the SAG CLI on PATH, and semantic search also needs a JEV model configured in SAG; the model chooses which directory to index or drop (default: the session working directory).

インストール

dsh plugin --profile web add github:clear0/dsh-sag-wiki

README

dsh-sag-wiki

把 SAG Wiki 的本地代码 / 文档检索能力接进 DeepSeek Harness。

宿主侧 Cordis 插件(纯 host,无浏览器半侧),向 tools 服务注册 4 个 sag_* 工具;索引与检索全部交给本机已安装的 SAG CLI 完成——插件自己不建索引、不联网、不缓存正文。

模型 ──► sag_* 工具(本插件)──► sag 可执行文件 ──► 本地索引(SAG 后台服务)
                                        ▲
                                 索引由 sag add / sag remove 管理

0. 一页速览

# 1) 准备 SAG CLI(两条通道择一;插件按 PATH 顺序取第一个可用的)
#    a. 桌面版 SAG Wiki:安装后自带随包 CLI
#    b. 独立 CLI:npm install -g @zleap-ai/sag
sag --version

# 2) 给要检索的目录建索引(在该目录内执行)
cd /path/to/project && sag add . --json

# 3) 装插件:把本仓库放到任意目录,然后在 Harness 插件管理器里
#    install_bundle,target = 该目录的绝对路径
#    (本机 PATH 里没有 dsh 命令,安装一律通过插件管理器)

# 4) 验证:调用 sag_index_status,应看到上面的目录 status=ready

sag_search(语义检索)需要额外配置 JEV 模型;没配时会返回可操作的提示并建议改用 sag_grep(精确 / 正则检索),后者不依赖任何模型。


1. 依赖与平台

1.1 需要什么

依赖是否必需说明
DeepSeek Harness(含 Cordis 插件系统)必需本插件是宿主侧 bundle,需 tools / subprocess / workingDirectory 三个服务
Node.js ≥ 20必需插件本身是 ESM;与宿主共用同一个 Node 运行时
SAG CLI(sag 可执行文件)必需真正干活的部分;缺失时工具返回“未找到可执行文件”的提示
SAG 后台服务 + 已建索引的目录必需首次 sag add 会拉起常驻服务;未索引的目录检索会报“目录未建立索引”
JEV 模型配置可选仅 sag_search(语义检索)需要;sag_grep、索引管理都不需要

1.2 平台支持

平台支持情况说明
Windows x64✅SAG 随包提供 sag.exe
macOS arm64(Apple Silicon)✅提供 sag 原生二进制
macOS x64 / Linux⚠️ 取决于 SAG 发布插件按 process.platform + process.arch 推导原生二进制目录;上游提供了对应平台的构建即可用
其他 Node 运行时⚠️需要宿主支持的 Node ≥ 20

插件代码本身不含平台分支(除“sag.exe 与 sag 文件名差异”外),路径统一走 Node path 处理;从 CLI 输出里取回的 Windows \\?\ 前缀与 ./ 前缀在返回前会被剥掉。


2. 安装 SAG CLI

插件不下载、不打包 CLI,只在本机 PATH 里找它。两条通道等价,选一条:

2.1 通道 A:桌面版(推荐)

安装 SAG Wiki 桌面版 后,安装器会附带一份 CLI,通常落在:

平台常见位置
Windows%USERPROFILE%\.local\bin\sag.exe
macOS~/.local/bin/sag

并写入当前用户 PATH。装完开新终端验证:

sag --version
sag status          # 服务与配置诊断

2.2 通道 B:独立 CLI(npm)

npm install -g @zleap-ai/sag
sag --version

需要全局安装:插件是在 PATH 里找 sag / sag.exe / sag.cmd,再据此推导同目录下的原生二进制;仅装成局部依赖不会出现在 PATH 里。

两种通道的差异:

桌面随包 CLInpm 全局 CLI
形态单个原生可执行文件shim(.cmd / 符号链接)→ Node 脚本 → 原生二进制
版本节奏随桌面端更新以 npm 上 @zleap-ai/sag 的 latest 为准
数据目录与桌面端共享与桌面端共享

两者使用同一个后台服务、同一份配置与索引数据,所以不要同时保留两份不同版本——PATH 里先命中的那个会决定实际运行的版本;后台服务只有一个,由先启动者决定其版本。

2.3 确认 CLI 能被找到

where sag      # Windows
which sag      # macOS / Linux

如果 sag 可用、但插件仍报找不到,通常是因为宿主进程的 PATH 与你终端里的不同(例如从 GUI 启动的 Harness 未继承最新 PATH)。重载插件或重启 Harness 即可让插件重新扫描。


3. 建立索引

在要检索的目录内执行:

cd /path/to/project
sag check . --json       # 看是否已建索引
sag add . --json         # 建索引(首次会拉起后台服务)
sag list --json          # 列出所有已索引目录
sag remove . --json      # 移除

add 可限制文件类型:

sag add . --types md,txt,js,ts,py,json,yaml --json

几点经验:

  • 重型二进制文档(扫描版 PDF、超大 PPTX 等)转换耗时且有失败风险,建议在目录根放 .sagignore 把它们排除:
    *.pdf
    *.docx
    *.pptx
    *.xlsx
    *.epub
    
  • 大树首次索引可能持续数分钟;sag add 在部分版本上会因后台服务继承输出管道而不返回,这是上游已知问题(已在较新版本修复)。用插件的 sag_index_update 时,超时但输出里已含 index_status 的会被视为“已生效”并附带说明。
  • 索引完成后 sag check . --json 的 index_ready 应为 true,roots[].status 为 ready。

4. 安装插件

4.1 获取代码

git clone https://github.com/clear0/dsh-sag-wiki.git
cd dsh-sag-wiki

放在哪个目录都可以——安装时记录的是该目录的绝对路径。

4.2 在 Harness 里安装

通过 Harness 的插件管理器安装(plugin_manager install_bundle,target = 上面的绝对路径)。安装动作会:

  1. 在 profile 的 package.json 写入依赖:"dsh-sag-wiki": "link:<你的路径>"(本地目录用 link,改源码无需重装);
  2. 把 dsh-sag-wiki 追加进 dsh.profile.bundles;
  3. 在 profile 的 node_modules/ 下建立指向源码目录的符号链接;
  4. 通过包内 dsh.bundle.patch 指向的 patch 把插件插入 boot graph 并启用:
# cordis.patch.yml
- insert:
    - id: dsh-sag-wiki
      name: dsh-sag-wiki

id 必须与包名一致。

4.3 验证安装

  1. 工具列表里应出现 sag_search、sag_grep、sag_index_status、sag_index_update;
  2. 调用 sag_index_status(不带参数),应返回当前工作目录的覆盖情况与索引状态。

4.4 改完源码如何重载

插件以 link: 方式安装,源码改动立即落到 profile 的 node_modules,但运行中的进程需要重载插件才生效。重载时要用 profile 里登记的 entry id(形如 include:dsh-sag-wiki,可用配置文件列举接口查到),只传包名通常会报 unknown-plugin:

set_plugin(entryId, enabled=false)   → applied
set_plugin(entryId, enabled=true)    → applied

4.5 卸载

从 profile 的 dsh.profile.bundles 移除并删除对应依赖项,或通过插件管理器的卸载动作完成;源码目录可以保留。


5. 工具参考

四个工具都返回结构化 JSON,同时渲染成紧凑的中文文本。

5.1 sag_search — 语义检索

参数类型默认说明
querystring必填自然语言问题,建议写完整问句
directorystring会话工作目录必须是已索引目录
maxResultsnumber51–100
timeoutSecondsnumber18010–600

对应 CLI:sag "<query>" [dir] -m N --json -c。需要 JEV 模型;未配置时返回配置指引而非报错。

5.2 sag_grep — 精确 / 正则检索

参数类型默认说明
patternstring必填已知标识符、错误串、配置键、URL
modefixed | regexfixed字面量或正则
directorystring会话工作目录已索引目录
maxResultsnumber501–200
ignoreCasebooleanfalse忽略大小写
wholeWordbooleanfalse整词匹配
filesOnlybooleanfalse只返回文件名,不返回行

对应 CLI:sag -F|-E [--json] [-l|-c] [-i] [-w] -m N -- <pattern> <dir>。命中项带 file:line 与正文;未命中不算错误(退出码非 0 但结果为空时按“0 条”处理)。

5.3 sag_index_status — 索引状态

参数类型默认说明
actioncheck | listcheck单目录检查 / 列出全部
directorystring会话工作目录action=check 时使用

返回:覆盖状态(included / partial / excluded / none)、是否就绪、已索引文件数、扩展名列表、每个 root 的状态,以及 JEV 是否已配置密钥。

5.4 sag_index_update — 增删索引

参数类型默认说明
actionadd | remove必填加入或移除索引
directorystring会话工作目录目标目录
typesstring[]全部add 时限定扩展名,如 ["md","ts"]
timeoutSecondsnumber18010–900,大树可调高

6. 推荐用法

  1. 查概念 / 不熟的实现:sag_search,但要先确认目录已索引;
  2. 查已知符号:直接 sag_grep(mode=fixed 最快;需要“或”关系时用 mode=regex);
  3. 结果太散:把 directory 收窄到子目录,或调小 maxResults;
  4. 搜不到东西:先 sag_index_status,区分“没建索引”“目录不在覆盖范围”“索引未就绪”三种情况;
  5. 新目录:sag_index_status → 需要时 sag_index_update(add) → 再检索。

索引规模越大检索越慢(时间大致随切片数线性增长),把查询限制在相关子目录通常比扩大 maxResults 更有效。


7. 与 sag skill 的分工

  • skill:写给模型的流程说明(先 check 再检索、一次一个目录、结果先取 3–5 条),不执行任何操作;
  • 插件工具:真正的执行单元。

两者互相独立,可以同时存在;技能描述里提到的“先确认索引状态”对应工具 sag_index_status。


8. 故障排查

现象原因处理
未找到 sag 可执行文件PATH 里没有 sag,或宿主没继承最新 PATH安装 CLI / 重载插件 / 重启 Harness
spawn ... ENOENTCLI 被卸载或移动,插件缓存了旧路径插件会自动重新扫描并重试一次;仍失败则检查 PATH
目录未建立索引目录没 sag add 过,或不在覆盖范围sag_index_status → sag_index_update(action=add)
索引未就绪(status: pending / indexing)后台服务正在索引,或索引器异常退出等待;长时间不动则检查服务状态,必要时移除后重建索引
JEV 未配置语义检索模型无密钥配置 JEV,或改用 sag_grep
此文件夹正在索引,请完成后再修改索引设置索引进行中等当前任务结束再 add / remove
检索很慢语料规模大收窄 directory,或为无关子目录加忽略规则
工具不出现插件未启用 / 安装未完成检查 profile 的 bundles 列表与工具列表

9. 自测(不依赖宿主)

两个脚本用 mock ctx 直接驱动插件代码,验证参数拼装与输出渲染:

node test/smoke.mjs [目录] [检索词] [--write]
node test/bench.mjs [目录]
  • 目录默认是当前工作目录,检索词默认 MIT;
  • smoke 依次跑 sag_index_status → sag_grep(含 filesOnly)→ sag_search → sag_index_status(list);
  • 只有带 --write 才会执行 sag_index_update(add)——它会真的改动索引,默认不跑;
  • bench 计时冷/热调用并打印总计,用于判断延迟瓶颈在 CLI 启动还是检索本身;
  • 未装 SAG、未建索引、JEV 未配置时,脚本给出对应提示而不是崩溃。

10. 目录结构

dsh-sag-wiki/
├── package.json          # dsh.bundle.patch 指向 cordis.patch.yml
├── cordis.patch.yml      # 把插件插入 boot graph
├── lib/
│   ├── index.js          # 插件入口:注册 4 个工具,输出降噪(null/undefined 剔除)
│   └── sag-cli.js        # CLI 定位(PATH → 原生二进制)、子进程执行、JSON 解析
├── assets/icon.svg
├── test/
│   ├── smoke.mjs
│   └── bench.mjs
└── README.md

设计取舍

  • 不等管道关闭:sag 拉起后台服务后可能继承并长期持有 stdout/stderr,等待 close 会挂住;只 await 子进程退出事实,再从已收集缓冲里读取(按字节偏移读取,非消耗式)。
  • CLI 定位缓存可自愈:定位结果缓存,但每次使用前校验文件存在;ENOENT 时重扫 PATH 并重试一次。
  • 输出降噪:宿主对工具输出 schema 校验很严,null 不合法,统一在注册包装层递归剔除 null / undefined。
  • 路径归一:剥掉 Windows \\?\ 前缀与 ./ 前缀,返回可读的绝对路径。

11. 参考

License

MIT

関連プラグイン