DeepSeek Harness 插件

hyzyn/dsh-plugin-kit#codegraph

Star 数 ★ 48 下载量(近 30 天) 5,421 分类 工具与能力 收录于 2026-08-30 npm @hyzyn/dsh-codegraph

DSH Web GUI 的 Codegraph 集成:设置 → 插件 中的「Codegraph」卡片提供索引状态、符号搜索、callers/callees/impact 查看与一键 sync/index;托管 codegraph MCP 服务器,并向 system prompt 注入 Codegraph 使用指引。需安装 codegraph CLI。

安装

# npm 包(预构建)

dsh plugin --profile web add @hyzyn/dsh-codegraph

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:hyzyn/dsh-plugin-kit#path:/packages/codegraph

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

中文 | English

DSH 设置 → 插件 里的「Codegraph」卡片:把代码图谱的状态、符号搜索、调用链搬进 GUI,并替你把 codegraph MCP 服务器的项目目录对齐好。

特性

  • status --json 字段分区呈现:initialized / version / projectPath / fileCount / nodeCount / edgeCount / lastIndexed / pendingChanges / languages / dbSizeBytes 分区铺开,原始 JSON 收进 <details>;符号下钻输出带行号的 verbatim 源码 + callers / callees / impact 三段关系。CLI 的过期信号(reindexRecommended / builtWithVersion / 提取器版本差 / worktreeMismatch)会在面板上给出一行警告并把「重建索引」标成建议动作。
  • 索引两条路径、超时分两档:sync -- <path> 增量、index [--force] -- <path> 全量重建走 indexTimeoutMs(默认 600s,0 = 不限时);status / query / callers / callees / impact / node 走 cliTimeoutMs(默认 60s,0 = 不限时)。超时与取消都走「SIGTERM → 3s 清理窗口 → SIGKILL」的进程组升级链,POSIX 与 Windows 同一套语义;索引类操作进行中卡片有「取消」按钮,关闭页面也会中止 CLI。
  • 托管 MCP 服务器行:dsh-mcp-client 不声明 MCP roots,codegraph serve --mcp 只从 process.cwd() 向上解析 .codegraph/;插件在 ~/.dsh/cordis.patch.yml 维护 @deepseek-ai/dsh-mcp-client 行并写 config.cwd,改写经 watchUserPatches 热加载重建 MCP 连接。同一台服务器同一时刻只挂一个项目,其余项目用 projectPath 查询。
  • 索引判定取 .codegraph/*.db 且与 CLI 同口径向上解析:从目标目录向上(到 git 根为止)找第一个带索引库的 .codegraph/,命中根即项目根——monorepo 子目录里的会话不再被误判「未索引」。只看目录存在会把 codegraph CLI 自身的安装目录 ~/.codegraph 判成项目索引,托管行随之落在未索引 cwd 上——实测该状态下 codegraph_explore 的 required 由 ["query"] 变为 ["query","projectPath"]。非真索引时不改写现有 cwd,卡片给出 indexState 与原因。
  • 写入纪律:对 ~/.dsh/cordis.patch.yml 的每次写都带 mtime+size 盖章复核(dsh-mcp 同款 CAS,≤3 次重读);复用 dsh-mcp 区块时只定点改 codegraph 行自己的 cwd: 一行,区块里的注释、其它服务器行、loader 合法的 override 条目逐字节保留;区块损坏时拒绝追加第二个区块(serverName 撞名会让 codegraph MCP 整体加载失败),把原因报给卡片。
  • 托管行 cwd 跟随活动会话:followSession(默认开)在会话切到有效索引项目时对齐托管行,否则回落到绑定路径;绑定路径由「设为默认项目」写入 settings 命名空间 codegraph 并把 followSession 置 false(显式指定优先于会话跟随)。会话上报失败会退避重试,不再一次抖动就永久失效。
  • 可选的 per-agent MCP 隔离(mcpScope: 'per-agent',默认 'managed'):默认模式下一台 MCP 服务器按时分复用服务所有项目(靠 projectPath 与跟随会话)。开启 per-agent 后,每个 agent 在自己的 Cordis scope 里挂一份独立的 dsh-mcp-client,cwd 固定为它自己会话目录解析出的索引根——多项目并行时不再共享一个全局 cwd,也不再需要「写盘 → 热加载 → 重建连接」那条链;全局托管行会被挂起(disabled: true,切回 managed 自动恢复)。代价是每个 agent 一个子进程(实测空 Node 基线约 40MB)。会话目录没有可用索引时该 agent 不挂(而不是回落到默认项目)——否则它会拿到别的项目的上下文,这正是「宣称避免、实现却没做到」的那类错误。机制实测与取舍见 docs/p0-plan.md。
  • 一键初始化:未初始化的目录在卡片上直接点「初始化索引」跑 codegraph init(两步确认)——index / sync 都要求项目先 init 过,此前这是唯一还要把用户赶回终端的一步。
  • systemPrompt 分两段,开关与门禁各自独立:plugin:dsh-codegraph(order 150)与 plugin:dsh-codegraph:usage(order 151);两段均以 <command> --version 探测为前置,announceToAgent / usageGuidance 写 settings 命名空间后即时增删 section。

为什么要托管 MCP 的工作目录

DSH 的 MCP 客户端不声明 MCP roots 能力,codegraph serve --mcp 启动后只能从进程工作目录向上查找 .codegraph/。而 dsh web 经常从家目录启动——这时模型调用 mcp__codegraph__* 一律拿到:

No CodeGraph project is loaded for this session.
Searched for a .codegraph/ directory starting from: /Users/you

本插件解决这个问题:在 ~/.dsh/cordis.patch.yml 托管一行 codegraph MCP 服务器(codegraph serve --mcp,cwd = 默认项目路径)。默认项目路径变化(卡片「设为默认项目」或配置修改)即重写该行,DSH 的 watchUserPatches 热加载后自动把 MCP 服务器挂载到新项目。

行为细则:

  • 优先复用 @hyzyn/dsh-mcp 托管区块里已有的 codegraph 行(只补 cwd,其余字段含禁用状态不动),没有才写本插件自己的区块,避免 serverName 撞名。
  • 区块外的手工行只检测不碰(避免冲突)。
  • 目标路径必须有真索引才托管:.codegraph/ 里得存在索引库(.db)。只看目录存在是不够的——codegraph CLI 把自己的安装数据放在 ~/.codegraph(current -> versions/<v>、bundles/、codegraph.lock,没有任何索引库),于是家目录会被误判成「已索引项目」,插件把 MCP 的 cwd 钉在家目录上并报告一切正常,而 codegraph status --json -- ~ 实际返回 initialized:false,工具照旧拿 "No CodeGraph project is loaded"。命中这种情况时插件不改写现有 cwd、不凭空建行,并在卡片上提示「默认项目 X 不是有效索引」+ 一键修复路径。
  • 多项目使用:一台 codegraph MCP 服务器同一时刻挂载一个默认项目;其它已索引项目可在工具调用里传 projectPath 查询,或回卡片一键切换。
  • 跟随语义:托管行 cwd = 「跟随开启 + 会话目录是有效索引」时取会话目录,否则取绑定路径。有效索引按 .codegraph/ 里存在索引库判定(不是目录存在),所以家目录那种 ~/.codegraph 安装目录不会把 cwd 带偏;项目被 uninit 后也会自动回落,不留陈旧状态。
  • 跟随由浏览器半体上报(页面加载即订阅活动会话,与设置面板是否展开无关):宿主侧没有「当前会话」这个信号,因此跟随只在有 GUI 页面打开时生效,其余情况用绑定路径。
  • 关闭方式:插件配置 mcpIntegration: false(会撤销本插件写入的托管行)。

CLI 面

卡片此前只覆盖 status/query/callers/callees/impact/node/sync/index/init,其余子命令只能去终端。现在补齐了旗舰与常用的那几个:

  • explore:与 MCP 的 codegraph_explore 同输出(相关符号源码 + 调用路径)。模型那条路走 MCP,人在卡片上此前够不着同一个能力——这有点荒谬,现在补上了。
  • context:为一个任务组装上下文(与 explore 面向「区域」的区别)。
  • files:索引里的文件结构(语言 / 符号数 / 大小)。
  • affected:由改动文件反向查出受影响的测试(实测本仓库:改 src/index.ts → 5 个测试文件)。这条对「我改了这里,该跑哪些测试」特别实用。插件刻意不替你猜改动列表(不读 git status、不猜编辑器状态):待测文件从哪来是上游流程的事,卡片只负责把你给的列表交给 CLI。
  • uninit:删除 .codegraph/——与 init 反向,是本卡片第二个破坏性动作,同样两步确认。实测必须带 -f:不带时 CLI 问 Continue? (y/N),而运行器没有 TTY、读到 EOF 就中止且不删除(安全但无效),所以确认由卡片负责。
  • telemetry:只读转达上游匿名用量统计的状态。刻意不给开关——那是用户的全局偏好(~/.codegraph/telemetry.json,由 CLI 自己的 telemetry on|off 管),插件替他翻等于越权改别人的全局设置。
  • 查询参数面板:query -k/--kind(类型过滤)、callers|callees -l/--limit(CLI 默认 20,会把大符号截断而卡片此前无从知道)。

kind 用自由文本而不是下拉枚举:上游加新 kind 时插件不必跟着改,填错 CLI 自己回空结果。

项目列表(一键切换)

一台 codegraph MCP 服务器同一时刻只挂一个项目,所以「换项目」是高频动作,而卡片此前只能手敲绝对路径。GET /projects + 卡片上一排胶囊按钮解决它。

候选只用界内的数据源:宿主 sessions.list() 的活跃会话 header.cwd,以及插件自己观察到的路径(/follow 上报、查过 /status 的目录、当前默认项目)。刻意不读 ~/.dsh/sessions/——那里确实有历史项目路径,但那是 DSH 的内部存储格式(会话桶名是路径编码、日志是多帧 zstd),插件解析它会在 DSH 改格式时静默失效;实测按桶名解码 51 个目录,一个都没解对。宁可比用户记忆少几个项目,也不要一个「有时准有时不准」的列表。

每个候选现算 locateIndex:只有真索引才可作为切换目标;未索引的也列出但禁用(用户会想知道「这个项目还没索引」),点击无效。列表按「最近见过」排序,容量 50 条、淘汰最久未见者。切换复用「设为默认项目」那条链路(持久化 defaultPath → 关闭跟随 → 热切换 MCP)。

API

路由 方法 说明
/api/dsh-codegraph/status?path= GET 索引状态(JSON)
/api/dsh-codegraph/query?q=&path=&limit= GET 搜索符号
/api/dsh-codegraph/callers?symbol=&path= GET 查调用者
/api/dsh-codegraph/callees?symbol=&path= GET 查被调用者
/api/dsh-codegraph/impact?symbol=&path=&depth= GET 查影响面
/api/dsh-codegraph/node?name=&path= GET 查符号/文件详情
/api/dsh-codegraph/sync POST 增量同步 { path }
/api/dsh-codegraph/index POST 全量重建 { path }(要求项目已经初始化过,见下)
/api/dsh-codegraph/init POST 在未初始化的目录跑一次 codegraph init(建 .codegraph/ + 首次索引),成功后重算 MCP 托管行;已索引目录回 409
/api/dsh-codegraph/default-path GET 绑定路径 defaultPath + 生效路径 effectivePath + sessionPath + followSession + 提示词开关 + cliAvailable / cliProbeError / cliProbeAt + MCP 托管状态(indexState 针对生效路径)
/api/dsh-codegraph/follow POST 上报活动会话目录 { path }(空 = 无活动会话);宿主据此对齐托管行 cwd,非索引目录自动回落
/api/dsh-codegraph/settings POST 写开关 { announceToAgent?, usageGuidance?, mcpIntegration?, followSession? }(布尔)与 { mcpScope? }('managed' / 'per-agent',非法值 400),即时生效
/api/dsh-codegraph/default-path POST 设为默认项目 { path }(需 .codegraph/ 里有索引库),同步热切换 MCP
/api/dsh-codegraph/reprobe POST 重跑一次 <command> --version 探测,回 { cliAvailable, cliProbeError, cliProbeAt } 并同步 systemPrompt 门禁
/api/dsh-codegraph/files GET 文件结构 { path, files, raw }(codegraph files --json);旋钮 filter / pattern / maxDepth
/api/dsh-codegraph/affected GET 受影响测试 { path, affected, raw }(codegraph affected --json -- <files…>);files 可重复传
/api/dsh-codegraph/explore GET 探索 { path, query, output }(codegraph explore,与 MCP 的 codegraph_explore 同输出,markdown);旋钮 maxFiles
/api/dsh-codegraph/context GET 任务上下文 { path, task, output }(codegraph context,markdown);旋钮 maxNodes
/api/dsh-codegraph/uninit POST 删除 .codegraph/ { path }(codegraph uninit -f);未索引目录回 409;撤销的是索引所在的根
/api/dsh-codegraph/telemetry GET 只读转达上游匿名用量统计状态 { enabled, output }
/api/dsh-codegraph/projects GET 已见项目列表 { projects, indexedCount, effectivePath }——候选来自活跃会话与插件观察到的 cwd(/follow 上报、查过 status 的路径、默认项目),每条现算索引态;monorepo 子目录归并到索引根
/api/dsh-codegraph/agents GET per-agent MCP 挂载台账 { mode, requested, effective, reason, fallback, mounted, live, agents }——每个 agent 挂没挂上、挂在哪个索引根、没挂的原因(只读)
/api/dsh-codegraph/unlock POST 清挡住索引的陈旧锁 { path }(codegraph unlock,幂等:没锁时 exit 0)
/api/dsh-codegraph/cancel POST 取消进行中的 CLI 调用 { path? }(合法 JSON body:{} = 全部;畸形 body 回 400,不会升级成「取消全部」);关标签页的断连也会自动中止对应调用
/api/dsh-codegraph/diagnose GET 收集诊断包 { path?, report }:report 是一段纯文本,含版本/平台、CLI 探测实测原文、索引状态、托管行与脱敏后的补丁区块原文、~/.codegraph 的 daemon 登记与日志尾、最近一次 CLI 失败、以及采纳率
/api/dsh-codegraph/metrics GET 采纳率 { path? }:不带 path 回全部项目 { summaries, since };带 path 回该项目 { project, summary, text, since }

所有路由均为 loopback-only,防止远程访问。reprobe 只认 POST:它会真的起一个子进程,不该由 GET 顺带触发。diagnose 只认 GET(只读),但它可能补跑一次探测,所以不会在写路径上被顺手调用。

诊断包的脱敏口径(diagnose):~/.dsh/cordis.patch.yml 是所有 MCP 服务器共用的文件,别家的行里可能有 headers / env 这类凭据,所以只摘 codegraph 相关的两个区块(本插件区块 + dsh-mcp 卡片区块),并按键名处理——id / name / serverName / transport / command / args / cwd / disabled 留值(这些正是排查要看的东西),其余键一律 <redacted>,且 headers: / env: 这类敏感键会污染整棵子树(连 authorization: 的值一起抹掉,但键名保留)。新增字段默认脱敏(fail-closed)。

采纳率仪表

卡片上那行「采纳率」回答的是配置之外的问题:配好了之后,模型到底买不买账。

  • 数据来源:宿主既有的 session/event 事件流(只数 tool/call,与 dsh-agent-instructions / dsh-acp 同一个公开订阅面)。不数 tool/result——采纳率问的是「模型想不想用」,失败了也是想用(那是另一个问题,由诊断包回答)。
  • 分子/分母(两个口径,窄口径是主口径):codegraph 命中 mcp__codegraph__*;窄口径分母是「发现类」调用(grep / glob / search / find / list_dir),宽口径分母还包含 read / view / open。之所以两个都报:真实历史里 read 占 1956 次而 grep 只有 100 次,而 read 多半是「打开已知道要改的文件」——codegraph 替代的是「找东西」,把 read 算进主口径会把数字永久压在个位数(实测宽口径 2.2% vs 窄口径 28.8%)。
  • bash / 媒体 / 网络类不计入分母:模型用 bash 干的事大部分(跑测试、装依赖、git)与代码探索无关;read_image / read_pdf / web_search 同理(这一条是拿真实历史量过之后补的,见下)。
  • 实测数字见 docs/adoption-audit.md:从 177 个真实历史会话回溯——会话级 23%、窄口径 28.8%、最近三天 47%,并给出 codegraph 调用 query 的质量抽样(34/47 带具体符号名)。
  • 分母为 0 显示「还没有探索类调用」而不是 0%:「一次都没探索」与「探索了但全用 grep」是两回事。
  • 项目键 = 索引根(resolveIndexedRoot),与托管行 cwd、注入门禁同一口径;所以同一个仓库的多个会话(换会话、子 agent、重启宿主)会归并成一条,而不是散成一堆没有统计意义的小样本。未索引项目也会记,但文案会标明「这个数字不代表提示词效果」,且 /metrics 额外给 grouped.indexed / grouped.unindexed 两组合计——未索引项目里模型本就不该用它,混进整体会得出没有意义的数字。
  • 只在内存里,宿主重启即归零,since 会如实给出起点。不落盘是有意的:它是「现在要不要调提示词」的观测值,不是审计日志,落盘会把工具名与项目路径长期留在磁盘上。
  • 同一份数据也进诊断包(/diagnose),因为报告「codegraph 好像没效果」时,第一个要分清的就是「模型根本没用」还是「用了但结果不对」。

请求语义(v0.4.2 起):

  • POST 路由对畸形 / 超限 / 非对象的 body 一律 400——不会把「请求体没读出来」当成「没指定路径」而在默认项目上执行写操作。/cancel 也在这道门禁内:{}(合法 JSON、未指定 path)才是「取消全部」,畸形 body 不会顺带把别的项目正在跑的索引杀掉。
  • 路径必须真实存在且是目录:status / query / callers / callees / impact / node 对不存在的路径回 400(CLI 对不存在的路径会 exit 0 + 空结果,静默得像「没有匹配」);--limit / --depth 只收正整数(limit 上限 10000,depth 的上限由 CLI 自己钳到 10)。
  • 祖先口径:/default-path 的 POST 在 monorepo 子目录上会绑定索引所在的仓库根;对子目录调 /init 回 409(祖先已有索引,避免建出嵌套索引);/follow 拒绝不存在目录的路径上报。

兼容性(DSH / codegraph CLI)

  • DSH:宿主版本矩阵(每一档都注明验证方式,别把回归测试说成兼容性声明):
    • 0.1.7-rc.1(上一轮适配基线,2026-09-23 实测):node scripts/verify-codegraph-host-contract.mjs --profile test --port 3087 --dsh-bin <独立安装的 rc.1 dsh> --runtime-store <该安装的 .pnpm/node_modules/@deepseek-ai> 42/42 通过——25 条路由全在(含 /projects、/metrics、/diagnose、/unlock、/files、/affected、/explore、/context、/uninit、/telemetry、/agents)、POST 门禁与 loopback 门禁成立、/diagnose 输出分段完整、浏览器半体产物可供给且含最新 UI、MCP 托管行按真索引写入 home 补丁、mcpScope 开关「切 per-agent → 全局行被挂起 → 切回 managed 恢复」全程可逆且真实 ~/.dsh/cordis.patch.yml 逐字节未变。新增的两项专门验 0.1.7 的 settings 迁移:启动后经插件自己的写路径把 mcpScope 切回 managed 基线、并把默认项目切到临时项目,两项都要求 HTTP 200(旧 API 下这两步只会 500)。

      • 验证方式说明:本机全局 dsh 若不是 rc.1,可用 --dsh-bin 指向一份独立安装的 rc.1,并用 --runtime-store 把复制出来的临时 profile 的 node_modules/@deepseek-ai/* 重指到该安装的运行时——否则那些链接仍指向全局旧安装,新 cohort 的兼容性 preflight 会把整套旧运行时行判成 incompatible 而全部禁用(宿主根本起不来,与本插件无关)。
      • 另一条已跑过的真机证据:隔离 DSH_HOME 启动 test profile(同样做运行时重指)→ 10 个插件全部 mounted、0 行 disabling profile plugin row,POST /api/dsh-codegraph/settings 在 per-agent / managed 之间往返都是 200。
    • 0.1.7-rc.2(当前适配基线,2026-09-25 实测):cohort 从 rc.1 提到 rc.2,peerDependencies 与 dsh.engines.dsh 的下限同步提升。node scripts/verify-codegraph-host-contract.mjs --profile test --port 3087(本机全局就是 rc.2,无需 --dsh-bin / --runtime-store)42/42 通过——25 条路由、POST / loopback 门禁、/diagnose 分段、浏览器半体可供给、MCP 托管行写入隔离 home 补丁、mcpScope 在 per-agent / managed 间往返可逆且真实 ~/.dsh/cordis.patch.yml 逐字节未变。另两项:真宿主加载 test profile 时 10 个插件全部 mounted、0 行 disabling profile plugin row;工作区 pnpm -r typecheck 全绿、vitest 960/960、pnpm -r build 绿。本轮未改任何插件运行行为(只有兼容性声明、文档与 lockfile)。rc.1 → rc.2 的 lib 产物逐文件比对:dsh-tools 仅新增可选 PreToolDecision.displayReason(本仓不构造该决策)、dsh-session-query 仅 JSDoc、dsh-client-ui-theme 仅设计 token 增补,dsh-mcp-client / dsh-host-webserver / dsh-subprocess-local / dsh-credentials / dsh-base / dsh-settings / dsh-web-app / dsh-headless 逐字节相同;dsh-app-boot 删除了 skippedProfileBundles 并改了 generateConfigSchema 签名(去掉首参 binName),但那是 DSH 自己的 CLI 与 app-boot 之间的内部面,本仓无任何引用。

      ⚠️ 标注(本次未擅改)——两个测试总数不是同一次运行的产物:本条写的是 rc.2 那一轮验证 时点的用例数(960/960);本轮项目级文档改造之后,当前值为全仓 56 files / 965 tests (packages/codegraph 本包 14 files / 317 tests)。两个数都不改——当前值以 ROADMAP.md 的「2026-09-25 复测」表为准。

      本条的「25 条路由」同理:以命令现算为准,别把它当契约(现算命令见 ROADMAP 复测表)。

    • 0.2.0-rc.1(同轮新增的第二档基线,2026-09-28 实测):不改任何运行代码,只把兼容范围写成两段(见下两条)。证据:① 用 0.2.0-rc.1 自己的判定器(dsh-app-boot 的 evaluatePluginCompatibility)对本仓 13 个可安装包逐一核对:单段 ^0.1.7-rc.2 时 12/12 全被拒(^0.1.7-rc.2 展开是 >=0.1.7-rc.2 <0.2.0-0,0.2.0-rc.1 恰好卡在 -0 上,includePrerelease: true 也救不回来),改成两段后逐 cohort 全部放行。② 隔离 DSH_HOME 在真 0.2.0-rc.1 宿主上:dsh plugin add 不需要任何豁免就装上 10 个插件,启动后 10 个全部 mounted、无 skipping profile bundle;verify-client-ui 5/5 PASS、verify-rss-opml 9/9 PASS(真实下载 + 回环)。③ 同一批包在 0.1.7-rc.2 宿主上回归同样全绿(client-ui 5/5、rss-opml 9/9)。④ 两档的插件 API 面逐文件比对:dsh-tools / dsh-client-ui-slots / dsh-client-locale / dsh-host-webserver / dsh-subprocess-local / dsh-client-modules / dsh-package-manifest 的 .d.ts 逐字节相同,plugins.row.config 槽契约相同,cordis 4.0.4 与 schemastery 3.18.4 同版本。

    • 0.2.0-rc.2(同轮追加的第三档基线,2026-09-29 实测):不改任何运行代码,只把兼容范围追加第三段(见下两条)。注意这一段与前两档不同:0.2.0-rc.2 本来就被 ^0.2.0-rc.1 覆盖(>=0.2.0-rc.1 <0.3.0-0,includePrerelease: true 下 semver.satisfies('0.2.0-rc.2', …) 为真),所以它是显式声明而不是修边界——但照样走完「每加一档都必须实测」的全部动作。证据:① 三档各自的判定器(dsh-app-boot 的 evaluatePluginCompatibility,0.1.7-rc.2 与 0.2.0-rc.1 从 registry 装出带依赖的副本)对本仓 13 个可安装包逐包 × 逐 cohort 核对,3 档判定器 × 3 个 cohort 全部放行(node scripts/check-dsh-peers.mjs --app-boot <该档的 dsh-app-boot 目录>)。② 隔离 DSH_HOME 在真 0.2.0-rc.2 宿主上:dsh plugin add 不需要任何豁免就装上 10 个插件;--dump-config 的 stderr 0 行、10 条 @hyzyn bundle 全在组合结果里;启动后 10/10 mounted、无 skipping profile bundle。③ 同一宿主上的三层真机验收:verify-client-ui 6/6 PASS(10 个 @hyzyn 客户端 bundle 真在 Chrome 里被加载、0 未捕获异常、0 error 级控制台输出、0 失败子请求)、verify-rss-opml 9/9 PASS(真实下载 + 导入回环 + 收尾复原)、verify-codegraph-host-contract 42/42 PASS(25 条路由、POST / loopback 门禁、/diagnose 分段、浏览器半体可供给、MCP 托管行写入隔离 home 补丁、mcpScope 在 per-agent / managed 间往返可逆,真实 home 的 cordis.patch.yml 逐字节未变)。④ rc.1 → rc.2 的插件 API 面逐文件比对:cli + web-app 的全部依赖包 166 个里只有 40 个有真实改动,本仓 import 的宿主包(dsh-base / dsh-tools / dsh-client-ui-slots / dsh-web-app / dsh-plugin-manager / dsh-mcp-client / dsh-settings / dsh-system-prompt / dsh-credentials / dsh-scope / dsh-session-query / dsh-launch-environment / dsh-agent / dsh-hmr 等)零代码变化;唯一与本仓相关的是 dsh-cordis-client-runner 的 slot 目录 97 → 98 条、只增不减(新增 sidebar.right.tab.files.actions),本仓注册的 4 个槽(plugins.row.config / settings.kit.item / settings.plugin.item / sidebar.right.pane.tab)逐字节相同。⑤ 工作区回归:pnpm -r build / pnpm -r typecheck 绿、pnpm test 92 files / 1484 tests 全过;本轮只动兼容性声明与文档,未动任何插件运行行为。

    • 0.2.1-alpha.1(第四档基线,2026-10-03 实测):不改任何运行代码,只把兼容范围追加第四段(见下两条)。这一段与第三档同类,也是显式声明而不是修边界:0.2.1-alpha.1 本来就被 ^0.2.0-rc.2 覆盖(>=0.2.0-rc.2 <0.3.0-0,includePrerelease: true 下 semver.satisfies('0.2.1-alpha.1', …) 为真),但照样走完「每加一档都必须实测」的全部动作。证据:① 用 0.2.1-alpha.1 自带的判定器(本机全局安装里的 dsh-app-boot,同一次安装的 getDshRuntimeVersion() 报 0.2.1-alpha.1)对本仓 13 个条目(12 个可安装包 + templates/hello)逐一核对:13/13 放行;node scripts/check-dsh-peers.mjs --app-boot <该安装的 @deepseek-ai/dsh-app-boot 目录> 四档 × 13 条目全部放行。② 隔离 DSH_HOME 起真宿主(复制本机 test2 profile,--patch 固定端口):10/10 个 @hyzyn 插件 mounted、0 行 disabling profile plugin row、0 行 skipping profile bundle;本机真实 test2 profile 上再跑一遍安装期判定:dsh plugin --profile test2 add link:<每个包>(10 个)全部返回 Already up to date、无 incompatible-version、不需要任何豁免(安装前与启动时各过一次)。③ 同一宿主上的四层验收:verify-client-ui --mode boot 5 PASS / 0 WARN / 0 FAIL、--mode full 17 PASS / 1 WARN / 0 FAIL(10 个 @hyzyn 客户端 bundle 真在 Chrome 里被加载、0 未捕获异常、0 error 级控制台输出、0 失败子请求;--mode full 另证 8/8 个插件的内联配置卡片都渲染出来(plugins.bundle.config + 行标记 plugins.row.config)与设置里「插件配置」行的 8 张 kit 卡片,唯一 WARN 是沙箱里 PTY 被拒 posix_openpt failed,不是回归)、verify-mcp-http 7 PASS / 0 FAIL(三种 streamable-http 响应模式 + 打不通时可读失败)、verify-rss-opml 9 PASS / 0 FAIL(真实下载 + 导入回环 + 收尾复原)、verify-codegraph-host-contract 42/42 PASS(25 条路由、POST / loopback 门禁、/diagnose 分段、浏览器半体可供给、MCP 托管行写入隔离 home 补丁、mcpScope 在 per-agent / managed 间往返可逆,且真实 ~/.dsh/cordis.patch.yml 逐字节未变)。④ 0.2.0-rc.2 → 0.2.1-alpha.1 的插件 API 面逐文件比对:CLI 包 20 个文件里只有 package.json 变;本仓 import 的宿主包(dsh-base / dsh-host-webserver / dsh-subprocess-local / dsh-client-locale / dsh-client-ui-slots / dsh-settings / dsh-session-query / dsh-mcp-client / dsh-system-prompt / dsh-launch-environment / dsh-client-ui-theme / dsh-headless 等)零代码变化;dsh-tools 只改 run_code 的参数顺序与文案、并删掉 ./invariant 子路径导出(本仓零引用,index.d.ts 逐字节相同),evaluatePluginCompatibility 语义等价;dsh-cordis-client-runner 的 slot 目录 98 → 100 条、只增不减(新增 plugins.add.actions / shell.bottom),本仓注册的槽全在。⑤ 运行时依赖版本漂移:这一档的宿主带 cordis 4.0.5-alpha.1 与 schemastery 3.18.5-alpha.1(前三档都是 4.0.4 / 3.18.4),但两份 tarball 除 package.json 外逐字节相同,且 app-boot 用 Symbol.for('schemastery') 判定原生 schema(不是 instanceof);本仓的 pnpm -r typecheck 正是重链到这两个新版本之后跑的,绿。⑥ 工作区回归:pnpm -r build / pnpm -r typecheck 绿、pnpm test 106 files / 1644 tests 全过、pnpm aggregate 无 diff;本轮只动兼容性声明、守卫与文档,未动任何插件运行行为。未跑:pnpm live-smoke(它把一次性 profile 复制到 ~/.dsh/profiles/live-smoke-*,本轮执行环境只允许写工作区,~/.dsh 写入被拒;需要时在本机普通终端补跑)。

    • 0.2.1-alpha.2(第五档基线,2026-10-09 实测):不改任何运行代码,只把兼容范围追加第五段(见下两条)。这一段与第三、四档同类,也是显式声明而不是修边界:0.2.1-alpha.2 本来就被 ^0.2.1-alpha.1 覆盖(同一个 0.2.1 版本元组,预发布之间不比大小),但照样走完「每加一档都必须实测」的全部动作。证据:① 用 0.2.1-alpha.2 自带的判定器(本机全局安装里的 dsh-app-boot,同一次安装的 getDshRuntimeVersion() 报 0.2.1-alpha.2)对本仓 13 个条目(12 个可安装包 + templates/hello)逐一核对:13/13 放行;node scripts/check-dsh-peers.mjs --with-app-boot(自动定位到那份判定器)五档 × 13 条目全部放行。② 本机真实 test profile 上跑安装期判定:dsh plugin --profile test add link:<每个包>(10 个)全部返回 Already up to date、无 incompatible-version、不需要任何豁免;随后 dsh --profile test --patch <端口层> 起真宿主(runtime 0.2.1-alpha.2):10/10 个 @hyzyn 插件 mounted、0 行 disabling profile plugin row、0 行 skipping profile bundle。③ 同一宿主上的验收:verify-client-ui --mode full 18 PASS / 0 WARN / 0 FAIL(10 个 @hyzyn 客户端 bundle 真在 Chrome 里被加载、8/8 个插件的内联配置卡片都渲染出来(plugins.bundle.config + 行标记 plugins.row.config)、设置里「插件配置」行的 8 张 kit 卡片、全局搜索命令面板往返真的有结果、终端面板 xterm 初始化完成、0 未捕获异常、0 error 级控制台输出、0 失败子请求;这一轮 PTY 没被拒,所以第四档那条 WARN 也不在)、pnpm live-smoke(= live-host-smoke --bootstrap --strict)18/18 PASS(两个宿主实例的授权阶梯、路由门控、工具清单、试连文案、宿主正服务的 client.js)——第四档那条「未跑」在这里补上了。④ 0.2.1-alpha.1 → 0.2.1-alpha.2 的插件 API 面逐文件比对:本仓 import 的宿主包里 dsh-mcp-client(MCP 托管行)/ dsh-settings / dsh-credentials / dsh-launch-environment / dsh-sandbox / dsh-scope / dsh-user-approval / dsh-agent / dsh-client-locale / dsh-subprocess 除 package.json 外逐字节相同;dsh-tools 里本仓用的 defineTool 导出行逐字节相同,改动只有 ToolPresentationMode 去掉 'both'(本仓零使用)与 PTC 内部桥 RunCodeBridgeOptions 多一个必填的 resolveWorkingDirectory(本仓没有实现方);客户端槽面只增不减(新增 conversation.chat.flow / conversation.chat.reasoning.body,零删除零改名,本仓注册的槽一个没被拿掉);dsh-host-webserver 与 dsh-web-app 的改动都在宿主配置面(监听地址只收环回或具体网卡、新增 TLS 配置、webRuntime → webStartup),本仓对这些名字零引用。⑤ 运行时依赖:这一档的宿主带的仍是 cordis 4.0.5-alpha.1 与 schemastery 3.18.5-alpha.1(与第四档同一对)。⑥ 工作区回归:pnpm -r build / pnpm -r typecheck 绿——且是在 node scripts/link-dsh-runtime.mjs 把本仓 node_modules/@deepseek-ai/* 指到 alpha.2 那套之后跑的(即类型面就是 alpha.2 的 dsh-tools,不是仓里 devDeps 钉的旧档),pnpm test 139 files / 2420 tests 全过、pnpm aggregate 无 diff。⑦ 同轮还按宿主的升级绊线复核了 docs/os-consent-plan.md §2.1 的三条事实与 picker 口径:宿主这一档真的换了口径(环回判定改用 dsh-host-webserver 的 isLoopbackHost()、新增 allowsRemoteAuthorities 一条),绊线按设计报红、复核记录写进该文 §2.1 末与 §4 第 2 条。

    • 0.1.6-alpha.2 / 0.1.5-rc.2 / 0.1.0-rc.7(历史基线,已不支持):这些档位的 settings 服务还是旧的 register(ns, schema) API,而 0.1.7 线已把它换成 SettingsForms(describe/update + 导出 volatile Config);本包的 peerDependencies 下限 ^0.1.7-rc.2 也会让新宿主在安装前/启动时拒绝加载到旧宿主上。旧档位当时的证据(0.1.6-alpha.2 40/40、0.1.5-rc.2 无脚本、0.1.0-rc.7 审计基线)保留在 git 历史里,仅作参考。

    • package.json 声明 peerDependencies: { "@deepseek-ai/dsh": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2" }(并在 peerDependenciesMeta 标 optional,只压 pnpm 的 unmet-peer 噪音)。DSH 0.1.7-rc.1 起安装前与启动时都据此判定兼容性:不兼容时安装抛 incompatible-version、启动时该行整行 disabled(bundle 则整包 skip)。同时保留 dsh.engines.dsh: ">=0.1.7-rc.2" 作为市场展示位(宿主不读它,见下条;市场解析器只认单段,所以它写的是最低档),peer 覆盖的最低档由 scripts/check-dsh-peers.mjs 校验一致。

    • 为什么是 peer 而不是 engines.dsh:dsh-app-boot 只遍历 peerDependencies 里名为 @deepseek-ai/dsh 或以 @deepseek-ai/dsh- 开头的项,用 semver.satisfies(runtime, range, { includePrerelease: true }) 判定(预发布参与范围匹配)。但 engines.dsh 仍然声明——宿主不读它,插件市场 / 社区条目却按它展示兼容性,所以保留为标准形式 >=0.1.7-rc.2(市场解析器只认 >=X.Y.Z[-预发布],写 || 会被判成「无法验证」而 fail-closed),且与 peer 覆盖的最低档一致。证据:dsh-app-boot/lib/index.js 的 evaluatePluginCompatibility,以及 app-boot README 原文「这些检查使用 peer 声明,而不是 engines.dsh」。

    • 为什么范围是五段 ^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2:预发布参与匹配,^0.1.7-rc.2 = >=0.1.7-rc.2 <0.2.0-0——单段会把整条 0.2 线判死(这正是 0.2.0-rc.1 上线后本仓插件在桌面版里显示「异常 / 不包含任何组件」的原因);第二段补上 0.2.0-rc.1 这一档并顺带覆盖整条 0.2.0 rc 线与 0.2.x 正式版;第三段 ^0.2.0-rc.2、第四段 ^0.2.1-alpha.1 与第五段 ^0.2.1-alpha.2 都是显式声明当前最新档(对宿主行为零差异,因为第二段已经覆盖它们;第四、五档另有各自的实测与 API 面比对,见上条)——留着它们是因为本仓的规则是「适配到哪一档就把哪一档写进范围,并留下实测证据」,而不是「范围恰好够用就行」。命中任一段即放行,五档的 API 面都已逐文件比对(见上条)。0.1.7 正式版与后续 0.1.7-rc.N / 0.1.8 仍走第一段,0.1.7-rc.1、0.1.7-alpha.2、0.1.6-* 依旧不通过。要临时放行别的版本组合,把豁免写进 profile 自己的 compatibility.json(dsh plugin --profile <p> allow-version <pkg@ver> --dsh-version <ver> --accept-risk),而不是随手往范围里加段——每加一段都必须是实测过、且 API 面比对过的 cohort。

  • codegraph CLI:版本矩阵——1.5.0(macOS)与 1.6.0(Windows / macOS)实测过全链路;用到的子命令是 status / query / callers / callees / impact / node / sync / index,旗标逐个核对过。codegraph serve --mcp 仍可用(顶层 help 不列,codegraph serve --help 在),托管行无需改动。升级 CLI 后请重验:-y 这类旗标恰好是版本相关的(本插件刻意不带它,见下)。
  • 浏览器半体的 URL 形态:当前 DSH 走 client-modules 的 combo 路由,单包直链 /plugins/@hyzyn/dsh-codegraph/client.js 已不再直接可用;浏览器只用 boot graph(window.__DSH_BOOT__)下发的 /plugins/??<id>/client.js&rev=…,插件侧无需改动。
  • 操作系统:Windows / macOS / Linux 都按同一份代码走,CI 已是三平台矩阵(pnpm -r build + typecheck + test)。
    • Windows:CLI 走 %COMSPEC% /d /s /c + cmd 转义(npm / pnpm 全局安装只给 .cmd shim,execFile 直连会 ENOENT);超时用 taskkill /pid <pid> /T /F 连 shim 里的孙进程一起收(只杀 cmd.exe 的话大仓库 index 会继续跑完);补丁文件重写沿用原文件行尾(CRLF 文件不会被写成混合行尾,重写也不改变行数)。
    • index 不会替你初始化:codegraph index --help 写着「same result as a fresh init」,但那说的是全量重建的结果等同于刚 init 完,不是「index 会初始化」。对没有 .codegraph/ 的目录,index / sync 都会直接报 CodeGraph not initialized in <path> + Run "codegraph init" first。故卡片的「初始化索引」按钮走的是 init。
      • 参数固定为 init -- <path>:不带 -y——那是 CLI 1.6.0 才有的旗标,1.5.0 会 error: unknown option '-y';而不带也不会挂起(运行器无 TTY,1.5.0 / 1.6.0 实测都自己取默认值跑完)。也不带 -f(CLI 用它兜住「家目录 / 文件系统根」这类误伤,不该由插件替用户绕过)。
      • 这是本插件唯一往用户项目里写东西的动作:它只在 .codegraph/ 下建 codegraph.db 与一个自忽略的 .gitignore(内容 * + !.gitignore),不碰任何源文件、也不改项目根的 .gitignore;codegraph uninit 可整体撤销。卡片上是两步确认,且绝不会自动触发。
      • init / index 会触发 codegraph CLI 自己的匿名用量统计(上游会在输出里提示;codegraph telemetry off 或 CODEGRAPH_TELEMETRY=0 可关)。插件不改这个开关——那是用户的偏好。
    • PATH:探测与调用都用插件配置的 command(默认 codegraph,走 PATH)。从 Dock / 开始菜单这类不继承 shell 环境的入口启动宿主时,PATH 里可能没有 CLI——此时两段 systemPrompt 不注入、卡片点不出可用命令。
      • PATH 是在宿主进程启动时读取的,所以「刷新页面 / 重开卡片」改不了它,宿主自己也不会变。两条修法:① 把 command 写成 CLI 的绝对路径(改 profile 补丁会触发热重载并重新探测);② 从新开的终端重启宿主,让新的环境块生效。
      • 改完之后点卡片上的重新探测(POST /reprobe)即可就地确认,不必重启宿主。卡片会把探测失败的实测原文(spawn codegraph ENOENT、非零退出的 stderr、超时)显示出来,用来区分「没装 / 装错 / 命令不在 PATH」。
      • 中文(及其它非 UTF-8 代码页)Windows 上,CLI 与 cmd.exe 的 stderr 按控制台代码页输出;插件用 @hyzyn/dsh-kit 的容错解码器(UTF-8 优先,遇非法字节整体回落代码页)解,卡片上的报错是中文原文而不是 ���。
    • MCP 行:dsh-mcp-client 用官方 SDK 的 StdioClientTransport(SDK 依赖 cross-spawn),Windows 上 .cmd shim 由它自己解析,托管行无需平台分支。
    • 上游 CLI 本身三平台 × x64/arm64 官方支持(自带 Node 运行时);本插件侧的索引判定只看 .codegraph/ 下的 *.db,不写死库文件名,上游改名也不受影响。

开发

pnpm --filter @hyzyn/dsh-codegraph build
pnpm --filter @hyzyn/dsh-codegraph typecheck
pnpm test                                   # 仓库级 vitest(也可 vitest run packages/codegraph)
pnpm --filter @hyzyn/dsh-codegraph test     # 只跑本包(托管行决策矩阵 + CLI 旋钮 + 路由回归)
node packages/codegraph/scripts/preview-card.mjs        # 渲染卡片预览 HTML 到 .preview/(--png 需在普通终端跑,Chrome 起不来于受限环境)
                                                        # 另有 --per-agent / --fallback:离线看 per-agent 的「生效中」与「已退回 managed」两态
node scripts/verify-codegraph-indexforce.mjs --profile test --port 3086   # 真机端到端:indexForce 是否真的带 --force 起进程(需要本机装好 DSH)
node scripts/verify-codegraph-host-contract.mjs --profile test --port 3087  # 真机端到端:宿主契约 42/42(25 路由 + 门禁 + 供给产物 + 托管行 + per-agent 模式开关 + settings 写路径);需要本机装好 DSH
#   全局 dsh 不是 rc.1 时,加 --dsh-bin <独立安装的 rc.1 dsh> --runtime-store <该安装的 .pnpm/node_modules/@deepseek-ai>
#   —— 后者把复制出来的临时 profile 的运行时链接重指到该 cohort,否则会因兼容性 preflight 禁用整套旧运行时而起不来。
                                                                          # 注:DSH 要写 ~/.dsh/profiles/<profile>/cordis.yml,沙箱只读时会被 EPERM 拦住

per-agent 的三层验收

三层各测一件事,缺一层就有一个真问题测不到——这不是凑数,是补缺口:

脚本 层次 测什么
verify-codegraph-agent-scope.mjs 机制 最小 Cordis 根:scope 能挂 mcp-client、同名跨 scope 不冲突、全局层干净、释放只回收自己
verify-codegraph-host-contract.mjs 路由/开关 起真宿主:25 条路由、mcpScope 切换、全局托管行挂起/恢复、真实补丁逐字节未变
verify-codegraph-agent-integration.mjs 集成 挂真插件,用真 AgentRegistry 驱动一次真 agent/created → 断言工具落到那个 agent、无索引的 agent 不挂、agent/disposed 回收

第三层是补出来的:前两层全绿也证明不了「用户开会话时 MCP 真的挂上了」——机制脚本用假 agent, 宿主脚本那个宿主里没有 agent 被创建(每轮 /agents 都是 mounted=0)。而 per-agent 的全部价值就在那条路径上。

三个脚本都自造临时项目、自收子进程,并断言真实 ~/.dsh/cordis.patch.yml 逐字节未变;后两个还给被测对象 隔离 DSH_HOME(前一版的教训:不隔离时插件当场去写用户真实配置,CG45)。

浏览器半体的源码在 client-src/index.js;build 经 scripts/build-client.mjs 产出包根的 client.js——删掉 index.js 对 client-src/pure.js 的 import、把 pure.js(纯逻辑,可在 vitest 里直接测,见 test/client-pure.test.ts)剥掉 export 后内联进 factory,产物仍是单文件无 import。CI 的 artifact-diff 以逐字节一致为闸,改源码后忘了重新 build 会直接红。

升级本机 DSH 之后,先重链再 typecheck——否则 packages/*/node_modules/@deepseek-ai/* 还是仓库 .pnpm 里那份旧副本,插件与宿主各持一份不同版本的库,兼容性问题会被掩盖:

node scripts/link-dsh-runtime.mjs     # 把 packages/* 的 @deepseek-ai/* 与 @hyzyn/dsh-kit 链到 dsh 运行时 / 本仓库 workspace

规划与缺陷记录(都不随包分发,只在仓库里,因此用绝对链接):

  • DEFECTS.md:缺陷编号字典——CG01–CG63 的索引(症状 + 修复/设计意图);逐条原文、验收记录与原始待办冻结在 git 历史里(见其 §4)。
  • ROADMAP.md:增强路线图——P0–P3 分档、代价、架构项(per-agent 挂载 / 采纳率仪表 / 诊断包)与开工顺序。
  • docs/p0-plan.md:per-agent scoped MCP 挂载的完整方案与实测(已完成项的设计文档,移入包内 docs/)。
  • docs/adoption-audit.md:采纳率实测——从 177 个真实历史会话算出的数字、两个口径的取舍、以及对路线图的影响(移入包内 docs/)。

安装到 DSH

dsh plugin --profile web add link:$(pwd)

配置

设置面在宿主里的位置随 DSH 版本变,但始终是同一份表单:0.2.0-rc.1 起挂 plugins.bundle.config——插件详情页「说明」正下方内联,不必再点「>」进二级页;旧宿主 (0.1.6 线)自动回退到侧边栏「插件」页里该行的「>」子页,≤0.1.5 用设置页卡片。

export interface Config {
  /** 关闭整个插件。默认开。 */
  enabled?: boolean
  /** 是否向 agent 注入插件能力公告。默认开。 */
  announceToAgent?: boolean
  /** 是否向 systemPrompt 注入 CodeGraph 使用指引(CODEGRAPH_START 区块)。默认开。 */
  usageGuidance?: boolean
  /** codegraph CLI 命令,默认 `codegraph`。 */
  command?: string
  /** 默认项目路径,默认 `process.cwd()`。 */
  defaultPath?: string
  /** 是否托管 codegraph MCP 服务器行。默认开;关闭时撤销本插件写入的托管行。 */
  mcpIntegration?: boolean
  /**
   * 托管行 cwd 是否跟随活动会话。默认开;「设为默认项目」会把它关掉(那是一次显式指定)。
   * `mcpScope: 'per-agent'` 生效时本项无意义(每个 agent 直连自己的进程,没有「跟谁走」)。
   */
  followSession?: boolean
  /**
   * MCP 挂载模式,默认 `'managed'`。
   * - `'managed'`:一行托管 + 按会话热切换(时分复用,一台服务器服务所有项目)。
   * - `'per-agent'`:每个 agent 在自己的 scope 里挂一份 dsh-mcp-client,cwd = 它会话的索引根。
   *
   * 默认保持 managed:这是行为变更,且按实测只覆盖「多项目并发」这一窄场景(时间占比 3.1%)。
   * 前提不成立时会退回 managed 并在卡片上说明原因(宿主没有 agent 事件面 / 存在区块外手工
   * codegraph 行 / MCP 总开关关闭),不会静默退回。代价:每个 agent 一个子进程(约 40MB)。
   */
  mcpScope?: 'managed' | 'per-agent'
  /** 查询类命令(status/query/callers/callees/impact/node)超时毫秒数,默认 60000;0 = 不限时。 */
  cliTimeoutMs?: number
  /** 索引类命令(sync/index)超时毫秒数,默认 600000;0 = 不限时。大仓库全量重建会超过查询档。 */
  indexTimeoutMs?: number
  /** 给 `codegraph index` 追加 `--force`(CLI 拒绝索引家目录/文件系统根时会用到)。默认关。 */
  indexForce?: boolean
  /**
   * 检测到索引过期时**自动重建**(`session/event` 首次 `user/message` 时检查,每项目每次
   * 宿主运行最多一次)。默认关——重建在大仓库上是分钟级操作。语义是重建而不是同步:
   * 实测 `codegraph sync` 对「提取器版本落后」会返回 `Already up to date` 且不清除信号。
   */
  autoReindex?: boolean
}

settings 命名空间 codegraph 里保存过的 defaultPath / mcpIntegration / followSession / mcpScope / announceToAgent / usageGuidance 优先于插件配置:「设为默认项目」写 defaultPath 并把 followSession 关掉,其余复选框与模式开关写其余项(POST /api/dsh-codegraph/settings)。

command / cliTimeoutMs / indexTimeoutMs / indexForce 是安装级旋钮,只读插件配置、不进 settings 命名空间。在 profile 的补丁里按 id 覆盖即可,例如:

- id: codegraph
  config:
    indexTimeoutMs: 1800000
    indexForce: true

超时命中时卡片上的报错会直接点名对应配置项(cliTimeoutMs / indexTimeoutMs),不必去翻日志。

系统提示词

安装后自动向 systemPrompt 注入两段提示(合计最多约 310 token;usage 段只在生效路径已索引时出现):

  • plugin:dsh-codegraph(order 150):插件能力公告(中文,约 130 字),只说「有这张卡片、能引导用户去开」;卡片内部有哪些按钮是 UI 细节,不占模型上下文。
  • plugin:dsh-codegraph:usage(order 151):CodeGraph 使用指引(CODEGRAPH_START 区块)。这块对应上游 CODEGRAPH_INSTRUCTIONS_BLOCK 的定位(上游把它定义为「给子 agent / 非 MCP harness 的短块」,长 playbook 走 MCP initialize 的 instructions)——但 DSH 的 MCP 客户端不读 instructions,上游那份「无根索引 → 按项目传 projectPath」的变体模型收不到,所以这块补的就是它,外加三条:shell 兜底(命令名按 command 配置渲染,不写死 codegraph,并给出 --path)、projectPath 按项目查询、没索引就跳过且不要 codegraph init。触发条件与宿主 indexState 同口径:.codegraph/ 里要有索引库,只看目录存在会把家目录里 CLI 自己的 ~/.codegraph 安装目录误判成已索引项目(上游原话就是后者,这块刻意收紧)。

两段都受两道门禁,usage 段另有第三道:

  1. CLI 探测:挂载时跑一次 <command> --version,失败就整段不注入(并 console.warn,带上失败原文)——不向模型宣告跑不起来的能力。探测结果不是锁死的:卡片「重新探测」或 POST /reprobe 会重跑一次并即时刷新这两段 section(CLI 后装好、或 command 改成绝对路径之后不必重启宿主)。
  2. 开关:卡片上的两个复选框写 settings 命名空间(POST /api/dsh-codegraph/settings),改完即时增删 section;也可以用安装级配置关掉(announceToAgent: false / usageGuidance: false)。
  3. 索引门禁(仅 usage 段):生效路径(effectivePath,即托管行实际用的那个目录)必须是有效索引才注入用法指引——判据与宿主 indexState 同口径,只是 .codegraph/ 目录存在不算。所以在没有索引的仓库里不会白白占掉约 300 token 的用法指引(那段话本身讲的正是「本仓库有索引时该怎么做」),也不会诱导模型去调必然失败的工具。判据每次 refreshGuidance 现算,因此跟随会话切换、「设为默认项目」、init 成功、项目被 uninit 都会立刻反映到注入与否上。公告段(order 150)不设这道门禁:它讲的是「有这张卡片」,与索引无关。

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。