🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

插件依赖图 ewoowe/dsh-plugin-dependency-graph-plugin

DeepSeek Harness
ewoowe29 天前有提交已提供中文文档扫描:未发现敏感能力

可视化插件间的服务注入关系与运行时依赖

29.6/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/6 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ewoowe/dsh-plugin-dependency-graph-plugin
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · dev
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 29 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/6) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/cordis-plugin-loader@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 可视化服务注入关系
  • 展示运行时依赖
  • 读取实时运行时

DeepSeek Harness 插件依赖图:哪个插件提供了其他插件都注入的服务,直接读实时 Cordis 运行时。

README

由 DeepSeek 最新模型翻译生成
插件依赖图 哪个插件提供了其他插件所注入的服务——读自运行中的 Cordis 运行时,而不是某份清单。 设置里有一个分节绘制这张图,另有一个独立页面以整页宽度展示同一张图。两处渲染的是同一个面板:两个宿主只在"能提供什么"上不同(一个 locale 服务、一套主题、一个小窗口 vs 一整个页面)。 截图 分节刚打开的样子:统计胶囊、状态行(图上真有的每个状态一颗色点、它的数量,点一下即筛选到它)、画面,以及角落里那段四行图例。画面上方的控件依次是 ← →(选中历史)、缩放、重置视图、全屏。 插件依赖图分节 全屏。画布本身就是全屏元素,所以面板里放在它旁边的东西在屏幕上都不存在——这正是工具栏要移到画布内的第一行、搜索框占第二行的原因。 全屏 选中一个节点。包名下方是它自己的描述,监听的事件列出它订阅了哪些事件,而连线按方向分开——两个颜色各是哪一边,看图例——只在运行时才取的依赖仍然是虚线。 选中一个节点 搜索。查询同时匹配包名、Loader 的 entry id 和插件提供的服务名——所以 ctx.locale 能被直接搜出来。命中的插件列成一张卡片,每行带着包名与它的状态;若是按服务命中的,包名下面还会写出是哪个服务。画面把其余部分变暗。输入框里的 × 清空查询并把光标交回输入框。 搜索匹配 新标签页里的独立查看页:同一张图,用整个窗口的宽度。
展开完整文档(README 剩余 1 节)
插件依赖图

哪个插件提供了其他插件所注入的服务——读自运行中的 Cordis 运行时,而不是某份清单。

设置里有一个分节绘制这张图,另有一个独立页面以整页宽度展示同一张图。两处渲染的是同一个面板:两个宿主只在"能提供什么"上不同(一个 locale 服务、一套主题、一个小窗口 vs 一整个页面)。

截图

分节刚打开的样子:统计胶囊、状态行(图上真有的每个状态一颗色点、它的数量,点一下即筛选到它)、画面,以及角落里那段四行图例。画面上方的控件依次是 ← →(选中历史)、缩放、重置视图、全屏。

插件依赖图分节

全屏。画布本身就是全屏元素,所以面板里放在它旁边的东西在屏幕上都不存在——这正是工具栏要移到画布内的第一行、搜索框占第二行的原因。

全屏

选中一个节点。包名下方是它自己的描述,监听的事件列出它订阅了哪些事件,而连线按方向分开——两个颜色各是哪一边,看图例——只在运行时才取的依赖仍然是虚线。

选中一个节点

搜索。查询同时匹配包名、Loader 的 entry id 和插件提供的服务名——所以 ctx.locale 能被直接搜出来。命中的插件列成一张卡片,每行带着包名与它的状态;若是按服务命中的,包名下面还会写出是哪个服务。画面把其余部分变暗。输入框里的 × 清空查询并把光标交回输入框。

搜索匹配

新标签页里的独立查看页:同一张图,用整个窗口的宽度。这里选中的是 (harness) 节点—— 运行时自己那一行,承载一切不归属任何插件的条目:根 fiber 提供的服务、它注入的服务、以及它监听的事件。它不依赖任何插件,所以只有指向它的线。

独立查看页

两棵树

一共有两个 Cordis 运行时,因此有两张图:

| | 宿主 | 浏览器 |
| 在哪运行 | Node 进程 | 页面里 |
| 谁来采集 | 宿主侧的 collectGraph(ctx) | 页面里的 collectGraph(ctx.root) |
| 谁来展示 | 本分节,经 HTTP 取回 | 由页面上报,查看页再读回 |

两者永不合并。 它们是不同的运行时:插件不同、服务名也不同——合并出来的不是更大的图,而是错的图。浏览器那一栏是第二个来源,不是第二组节点。

浏览器那棵树无法由 Node 半采集,所以只有页面能描述它:分节把它采集到的结果 POST 到 /dsh-plugin-dependency-graph/client,查看页再 GET 回来(一条路径、两个方法)。这份报告带着采集时刻,查看页会把它显示出来——一张被读者当成"当前"、其实不是的图,比一张坦白自己几点了的图更糟。

浏览器树的描述来自它自己的一条路由(/dsh-plugin-dependency-graph/descriptions):页面读不到 node_modules,而它要描述的那些包正是同一批,所以由 Node 半读出并给出「包名 → 描述」的表。这是两半能力唯一不同的地方,也是合并逻辑放在 src/describe.ts 的原因——它是纯的,两半跑同一份实现,而只有 Node 半碰 node:fs。解析顺序是:先试插件自己的目录,再试从宿主 profileContext.dir 学来的基点——实测下来,那些"显而易见"的基点全都落在仓库里,而第三方插件一个都不在那儿。

依赖是怎么获得的

一个插件拿到服务有两种方式,区别不是修饰性的:

- 声明式(插件上写 export const inject = [...]、inject: 选项,或 @Inject 装饰器)—— fiber 会一直挂起,直到它们全部解析。少了它,插件根本不会加载。
- 运行时,通过 ctx.inject(deps, callback) 助手——依赖出现后回调才跑。插件照常加载, 只有那一项贡献在等。

两者都是真实依赖,都会产生边,而第二种就是 optional 标记的含义。缺一个必需服务是组合坏了;缺一个可选服务是回调形式本来就为之存在的正常情形。

采集会读三处,而且这个区分很要紧:Loader 条目给出 id 与包名;反射存储是权威的提供者表(按隔离符号索引——fiber 自己的 store 是错的来源,会把消费者当成提供者);注册表给出所有活着的 fiber,包括运行时才启动的那些。

怎么看这张图

- 布局是数据,不是物理。 越多人依赖的插件越靠中心,角度是沿 id 走的黄金角——所以同一份组合每次画出来都一样,刷新不会让读者重新找方向。中心是枢纽,外圈是没人依赖的那些。
- 一条边都没有的插件默认折叠,收在一枚写明数量的控件后面(61 个无依赖)。在开发时对着的这份组合里它占 31%——一堆没有任何关系可画、却占着外圈(也就是占着缩放)的节点——所以是藏起来而不是删掉:按一下就回来,因为「这个插件什么都没参与」本身就是一个读者会来这儿找的答案。被搜索或状态筛选点名的节点即使没有边也会画出来,这样点结果行永远有处可落。
- 刷新重新读取这张图,但保留屏幕上已有的内容而不是先清成转圈:画布可能就是全屏元素,而一个离开文档的元素会把全屏一起带走。
- 搜索随输入过滤包名、Loader 的 entry id,以及服务名——而命中一个服务会带回这个服务的两端:谁提供它(标 提供),以及谁注入它(标 注入)。于是「谁在用 ctx.locale」变成一次查询,而不是顺着节点一个个走;这也正是画面会把该服务的线留亮的原因:画布只在两端都在结果里时才保留一条边。
没有人提供的必选服务在这里仍然搜不到——它在下面的问题清单里;订阅的事件名也不参与匹配,那由详情面板的事件区块回答。命中项每行带该插件的状态,这张列表也是够到那些被筛暗、缩到边上的节点的办法。输入框里的 × 清空查询并把光标交回;右内边距是一直留着的,所以敲字时框里的内容不会位移。
- 状态行同时是三样东西:图例、计数、筛选。图上真有的每个状态一颗胶囊,点一下就把画面窄到那个状态。只列图上确实存在的状态——一排大多是 0 的胶囊,看起来像在给看不见的颜色作说明。
图例则始终显示,而且线段用的就是"选中时"的颜色:还没点过的那个读者,才最需要知道颜色的含义。
- 滚轮缩放,拖拽平移,点击选中。但在匹配卡片或详情卡片里滚动时,滚的是那张卡片——它们是浮在画面上的面板,把手伸过去是想翻一张列表,不是想缩放它背后的图。
- 后退 / 前进沿选中轨迹走。后退之后再选一个新节点,会丢弃前进历史——与浏览器同一条规则、同一个理由;"未选中"也是一步,所以一个节点从两个方向都回得去。
- 全屏铺满窗口。工具栏与搜索框会移进画布内部、占前两行,详情作为浮层跟进去:那个位置的右侧栏在屏幕上并不存在。
- 新标签页打开把这张图交给独立查看页——一个由 Node 半服务的整页。这正是重点: iframe 或应用内的路由都会继承读者正想摆脱的那个宽度。
- 查看配置把这个条目自己的配置画在面板里:所有碰过这一行的层,已经按顺序合成好了,与其他任何插件无关。不是整份文件、也不是原生编辑器——读者人在浏览器里,而那未必是跑宿主的那台机器;再说一个盯着某个插件看的人,要的是这个插件的那一行,而不是所有插件共同住着的那份文件。
有两点它不是:没求值——!!js 是照原样显示源码(宿主的 --dump-config 也是这个选择:表达式节点是在该行自己的 fiber 上插值的,从不写回条目的 options);也没套 schema 默认值——这一行没写的字段就是没有,不会补上默认值。文本上方那条限定路径,就是想去翻文件时的入口;换选另一个插件时它会自动关闭。

一个节点上报什么

选中一个节点后,详情卡里是运行时知道的全部事实:

- 包自己的描述,读自它的 package.json。包没写、或者读不到时不显示这一行而不是显示空白—— "这个包没有自述"是事实,画一个空框则是我们的话。
- 声明的注入——这一行的 patch 里声明要哪些服务(如果它声明了)。读自条目而不是运行中的 fiber,所以要并排放在「注入」旁边而不是并进去:两者恰好在"声明没被满足"时不同,而一个从未加载的条目根本没有运行期注入可列。没有就不画:194 个条目里只有 3 个声明了东西,常驻一行「什么都没声明」等于在说另外 191 个。条目注册的其余字段(挂载路径、所属组、isolate、intercept、 config)照旧采集、也照旧由 JSON 路由提供,只是不再占行。
- 已禁用——状态旁边的一枚标签,只在被关掉的条目上出现,也是状态缺的那一半:被禁用的条目显示「未加载」,与"还在等人"看起来一模一样,而这份组合里 29 个「未加载」全都是前者。
- 提供——它的那些 fiber 注册的服务。
- 监听的事件——它的 fiber 订阅了哪些事件名,读自派发器自己的表。监听不产生边——监听等的是一个 名字,不是一个提供者,所以它不是依赖,画成边就是假边。反过来的方向是下面的发出的事件,那条运行时答不了,原委写在那一节里。
- 发出的事件——这个插件自己的代码里发出去的事件名;运行时确实派发过的会带一个「实测」标记。
这是卡片上唯一一项不来自运行中的运行时的数据,因为运行时答不了:派发器的表是「名字 → 监听者」,从不登记发布者;唯一带发布者的通道(internal/dispatch 的 thisArg)只在显式写
emit(thisArg, name, …) 时才有值——实测宿主 132 处 emit 调用里是 0 处。所以归属来自文本扫描
(emittedIn 读该模块自己的文件),运行时只负责确认。两个后果要知道:运行时拼出来的名字不是字面量,扫不到;而任何 .emit( 都会命中,包括 Node 的 EventEmitter——close、open、ready 就是这么来的。
浏览器树与独立查看页里没有这一项(不是空列表):那边没有文件系统可读,空列表会变成「它什么都不发」的假话。
点一个名字会列出监听它的插件——用的是监听者自己卡片上同一份 listens 数据、同一次采集,所以两处不可能对「谁在监听」说法不一——每行点进去就是那个插件。「监听的事件」反过来一样可点:点一个名字列出代码里发出它的插件,那是扫描的答案,标题里也照此写明。在没法读文件系统的地方采集的图(浏览器树、独立查看页)没有扫描可答,那里的监听事件保持普通标签——而不是点开一个会读成「没有插件发出它」的答案。
- 注入与运行时注入——依赖的两种获取方式,分开列是因为它们回答不同的问题:一个在问"它为什么没加载"的读者,要的只是前者。
- 依赖与被依赖——两个方向的每条边,每行给出造成这条边的服务名,以及它是否可选。

(harness) 是唯一不是插件的节点:它是运行时自己那一行。没有 Loader 条目归属的 fiber (根 fiber,以及条目树之外启动的那些)提供的服务记在这里而不是丢掉,它们的注入与监听也一并记在这里。loader 与环境那几行因此不会读成"所有注入者的未解析依赖"。

图上报了什么

画面下方有两块内容,两块都关乎"活儿"而不是"画法":

- 未解析的依赖——在本组合里没有任何提供者的必需服务。只列必需的:一个没有提供者的可选注入只是还没被提供而已,插件正按设计工作。
- 被隔离的服务——同一个服务名有多个活实现,也就是在多个隔离标签下被提供。

独立查看页

一个由 Node 半作为完整文档服务的页面。它自己没有 Cordis,所以只能展示宿主的树,以及应用上报的浏览器树。它从"被打开时的 URL"里读两样东西,因为除此之外它无从得知:

| 参数 | 为什么 |
| ?scheme=dark\|light | 页面用应用的 --dsw-* 令牌来配色,而切换这些令牌的属性属于应用,不属于这个页面 |
| ?lang=zh\|en\|ja\|ko\|es\|fr\|de | 让新标签页用应用当前的语言打开,而不是靠浏览器去猜 |

语言在进入文档之前会先过一遍字典白名单——查询串不是可以信任的地方,而这个值最终会写进页面的 lang 属性。直接打开该页(没有参数)时,依次回落到浏览器自身的语言偏好,再回落到英文。

浏览器那份报告只存在于内存里,从不落盘:它描述的是一个只在页面开着时存在的运行时,而一份熬过了宿主重启的报告,描述的是个并不存在的东西。

语言

src/client/locales.ts 里提供七本字典:宿主自带的 zh 与 en,外加 ja、ko、es、fr、de。
后五种通过单语言重载逐个注册——环境所携带的语言包里那份定义才是让一种语言可被选中的东西,本插件只往它上面补自己的字符串,且刻意不调用 addLanguage。

七本字典都标注为 Record<MessagesKey, string>:往 MessagesKey 加一个键,七本补齐之前编译不过。
用词与 session-messages 一致(那五本最早由它带上)——两个插件在同一套界面里,读者应当两处看到同样的术语。

目录

dsh-plugin-dependency-graph-plugin/
package.json dsh.bundle + dsh.client 声明、exports 映射(private,不对外发布) cordis.patch.yml 层补丁:插入 Loader 那一行 build.mjs 构建脚本:打包两半,并在构建期复制主题 tsconfig.json 仅用于 IDE 解析类型,指向检出源码(只读) src/ index.ts Node 半:collectGraph,以及下面那几条路由
graph-types.ts 两半共享的 wire 形状(类型 + 路径常量)
collect.ts 采集器,两个运行时共用一个函数 describe.ts 描述合并,纯函数——两半都跑它,只有 Node 半读 package.json emits.ts 发出事件的扫描:读包自己的代码,并合入运行时的确认(仅 Node 半) viewer-page.ts 独立查看页的文档,以字符串形式给出 viewer/main.tsx 独立查看页的主体(React 被打包进来——那个页面没有模块表可以应答一个裸的 react 导入) client/ index.ts 注册设置分节 GraphPanel.tsx 两个宿主都渲染的面板
graph-canvas.tsx 画面本身:布局、命中检测、缩放平移
search.ts 查询 → 命中的节点,以及命中的是哪个字段 locales.ts 七本字典 docs/ 上面那些截图(中文版为 -zh.png)

路由都在 /dsh-plugin-dependency-graph 之下:图本体、/view(页面)、/viewer.js、/theme.css, /client——它接受应用发来的 POST,并应答查看页的 GET——以及 /descriptions,它给浏览器树提供「包名 → 描述」的表,以及 /config——接受一个条目 id,返回那个条目组合后的配置。

开发

npm run build # 打包 lib/index.js、lib/client.js、lib/viewer.js
npx tsc -p tsconfig.json # 类型检查

在 DSH 检出里作为插件安装:把本目录的 cordis.patch.yml 加进 bundle 即可,它只插入一条 Loader 行。
这里没有任何东西需要改动宿主源码——这是本插件被构建出来时就遵循的约束,不是巧合。
预览分享卡片长什么样 ↓ewoowe/dsh-plugin-dependency-graph-plugin
分享 · DeepSeek Harness Hub
ewoowe/dsh-plugin-dependency-graph-plugin

可视化插件间的服务注入关系与运行时依赖

回到顶部