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

跨工具导入 Free-LZJ/free-dsh-plugins

DeepSeek Harness
Free-LZJ24 天前有提交已提供中文文档扫描:含敏感能力

把 Codex 与 Claude Code 的 MCP 和技能导入 dsh

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

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · skill
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 42 处,展示前 42 条)
  • 读取本地文件
    packages/agent-import/src/index.ts:560
    return await readFile(path, 'utf8')
  • 读取本地文件
    packages/agent-import/src/skill-file.ts:42
    raw = await readFile(path, 'utf8')
  • 写入本地文件
    packages/agent-import/src/skill-import.ts:254
    await mkdir(root.path, { recursive: true })
  • 读取本地文件
    packages/agent-import/src/skill-links.ts:54
    const info = await stat(path)
  • 读取本地文件
    packages/agent-import/src/skill-links.ts:71
    if (!(await lstat(path)).isSymbolicLink()) return undefined
  • 读取本地文件
    packages/agent-import/src/skill-links.ts:72
    return normalizeTarget(await readlink(path))
  • 读取本地文件
    packages/agent-import/src/skill-links.ts:105
    info = await lstat(linkPath)
  • 删除本地文件
    packages/agent-import/src/skill-links.ts:113
    await unlink(linkPath)
  • 删除本地文件
    packages/agent-import/src/skill-links.ts:120
    await rmdir(linkPath)
  • 读取本地文件
    packages/agent-import/src/skill-routes.ts:214
    return (await stat(path)).size
  • 读取本地文件
    packages/agent-import/src/skill-scan.ts:156
    const dirents = await readdir(root.path, { withFileTypes: true, encoding: 'utf8' })
  • 读取本地文件
    packages/agent-import/src/skill-scan.ts:173
    return await realpath(path)
  • 读取本地文件
    packages/agent-import/src/skill-state.ts:54
    raw = await readFile(path, 'utf8')
  • 写入本地文件
    packages/agent-import/src/skill-state.ts:93
    await mkdir(dirname(path), { recursive: true })
  • 写入本地文件
    packages/agent-import/src/skill-state.ts:94
    await writeFile(temporary, `${JSON.stringify(state, null, 2)}\n`, 'utf8')
  • 写入本地文件
    packages/agent-import/src/skill-state.ts:95
    await rename(temporary, path)
  • 读取本地文件
    packages/console/src/store.ts:39
    text = await readFile(join(home, STATE_DIR, 'prefs.json'), 'utf8')
  • 写入本地文件
    packages/console/src/store.ts:59
    await mkdir(directory, { recursive: true })
  • 写入本地文件
    packages/console/src/store.ts:60
    await writeFile(temporary, `${JSON.stringify(prefs, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 })
  • 写入本地文件
    packages/console/src/store.ts:61
    await rename(temporary, target)
  • 读取本地文件
    packages/console/src/tools.ts:157
    isDirectory = statSync(path).isDirectory()
  • 发起网络请求
    packages/mail/src/imap.ts:170
    fetch(range: unknown, query: unknown, options?: unknown): AsyncGenerator<{
  • 发起网络请求
    packages/mail/src/imap.ts:415
    for await (const message of client.fetch([...uids], { uid: true, flags: true }, { uid: true })) {
  • 发起网络请求
    packages/mail/src/imap.ts:800
    for await (const message of client.fetch(range, { uid: true }, { uid: true })) {
  • 发起网络请求
    packages/mail/src/imap.ts:828
    for await (const message of client.fetch(batch, SUMMARY_QUERY, { uid: true })) {
  • 读取本地文件
    packages/mail/src/index.ts:146
    return existsSync(bundled) ? bundled : join(here, '..', '..', 'assets', 'panel.html')
  • 读取本地文件
    packages/mail/src/index.ts:160
    return existsSync(bundled) ? bundled : join(here, '..', '..', 'defaults', 'basic.yml')
  • 读取本地文件
    packages/mail/src/index.ts:924
    panelDocument: (): string => readFileSync(panelDocumentPath(), 'utf8'),
  • 写入本地文件
    packages/mail/src/store.ts:166
    await rename(from, to)
  • 写入本地文件
    packages/mail/src/store.ts:326
    await mkdir(dirname(path), { recursive: true })
  • 写入本地文件
    packages/mail/src/store.ts:327
    await writeFile(temporary, `${JSON.stringify(file, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 })
  • 写入本地文件
    packages/mail/src/store.ts:331
    await chmod(path, 0o600).catch(() => undefined)
  • 读取本地文件
    packages/mail/src/store.ts:339
    raw = await readFile(path, 'utf8')
  • 发起网络请求
    packages/web-search-account/src/index.ts:256
    response = await fetch(endpoint, {
  • 读取本地文件
    packages/worktree/src/git.ts:61
    await stat(path)
  • 读取本地文件
    packages/worktree/src/git.ts:130
    info = await stat(dir)
  • 写入本地文件
    packages/worktree/src/git.ts:160
    await mkdir(parent, { recursive: true })
  • 写入本地文件
    packages/worktree/src/git.ts:161
    if (insideRepository && freshParent) await writeFile(join(parent, '.gitignore'), '*\n', 'utf8')
  • 读取本地文件
    packages/worktree/src/git.ts:227
    info = await stat(dir)
  • 读取本地文件
    packages/worktree/src/store.ts:40
    raw = await readFile(settingsFile(), 'utf8')
  • 写入本地文件
    packages/worktree/src/store.ts:74
    await mkdir(dirname(settingsFile()), { recursive: true })
  • 写入本地文件
    packages/worktree/src/store.ts:75
    await writeFile(settingsFile(), `${JSON.stringify(next, null, 2)}\n`, 'utf8')
扫描于 2026/10/31(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 导入MCP服务
  • 导入技能
  • 卡片式插件页

README

由 DeepSeek 最新模型翻译生成
free-dsh-plugins 把 Codex / Claude Code 已经声明好的 MCP 服务器接进 DeepSeek Harness(dsh),并把各 Agent 工具的技能以符号链接导入 dsh 自己的技能目录统一管理。 English · npm · 包文档 · 示例 overlay 同一台机器上同时用 dsh 和别的 Agent 工具时,MCP 服务器与技能只需要声明一次。插件在激活时读另一侧的声明:服务器挂到 dsh 的 mcp-client 上,技能则以符号链接(Windows 用 junction,免管理员权限)进入 dsh 自己的技能目录——不复制文件,所以改一处两边同步,移除导入也只删链接、源文件不动。设置页提供一页,用来看这次导入实际挂载了什么、用每行一个开关启停单项技能、以及按来源调整导入范围。 仓库里有什么 | 包 | 一句话 | | @free-lzj/dsh-agent-import | Host 插件 + 浏览器半边(双面包):Host 半边导入并挂载,浏览器半边提供设置页那一页 | 一个包、一条 Loader 行:0.3.0 起这两半合并了,此前是两个包、两行(见从 0.2.x 升级)。
展开完整文档(README 剩余 1 节)
free-dsh-plugins

把 Codex / Claude Code 已经声明好的 MCP 服务器接进 DeepSeek Harness(dsh),并把各 Agent 工具的技能以符号链接导入 dsh 自己的技能目录统一管理。

English · npm · 包文档 · 示例 overlay

同一台机器上同时用 dsh 和别的 Agent 工具时,MCP 服务器与技能只需要声明一次。插件在激活时读另一侧的声明:服务器挂到 dsh 的 mcp-client 上,技能则以符号链接(Windows 用 junction,免管理员权限)进入 dsh 自己的技能目录——不复制文件,所以改一处两边同步,移除导入也只删链接、源文件不动。设置页提供一页,用来看这次导入实际挂载了什么、用每行一个开关启停单项技能、以及按来源调整导入范围。

仓库里有什么

| 包 | 一句话 |
| @free-lzj/dsh-agent-import | Host 插件 + 浏览器半边(双面包):Host 半边导入并挂载,浏览器半边提供设置页那一页 |

一个包、一条 Loader 行:0.3.0 起这两半合并了,此前是两个包、两行(见从 0.2.x 升级)。

当前发布 0.3.2:声明 dsh.bundle,作为 bundle 安装时(dsh plugin add)会自动插入那一条 Loader 行,不再需要手工声明;peer 范围补上 0.2.0 预发布分支(原范围会静默排除 0.2.0-rc.)。0.3.1 的改动是技能改为逐行开关启停(关掉的名字显示为「已停用」而不是没导入过),配置页的来源改为一行一个开关、明细可折叠,打开后才显示该工具的目录项。明细见更新日志。

能做什么

| 能力 | 说明 |
| MCP 服务器 | [mcp_servers.](Codex config.toml)、mcpServers(Claude Code ~/.claude.json、项目 .mcp.json)经 dsh 的 mcp-client 变成 mcp__<server>__<tool> 工具 |
| 技能 | 各 Agent 的技能目录(共 22 个来源:21 个工具 + 项目级根)按 frontmatter 的 name 归并,同名时按 rank 自动选一个,以符号链接导入 ~/.dsh/skills;同一份文件(realpath 相同,例如经 CC Switch 中转的多个工具)只导入一次,dsh 自己放的真实技能永不被覆盖或删除;移除会被记住(记在 ~/.dsh/agent-import/state.json 里,只存名字),重启后不会被自动补回,直到你再次导入它 |
| 不拖垮整场导入 | 读不懂的声明只记一条 agent-import: … 警告并跳过,其余照常导入 |
| 热生效 | 插件自己的配置是热生效的:设置页保存后立即重新导入,不需要重启 |
| 一页说清结果 | 设置页分「已加载」「技能」「配置」三个 tab:「已加载」用表格列出本次导入实际挂载的 MCP 服务器(状态、命令或 URL、跳过原因)与已导入的技能;「技能」可搜索、按状态与来源浏览、查看技能正文,每一行自带启停开关(被关掉过的技能显示为「已停用」而不是没导入过),同名冲突可就地改选来源;「配置」里每个来源占一行、右侧一个开关,打开后才显示该工具的目录项,可折叠展开 |
| 最小暴露 | 报告里只有名字与位置:服务器的参数、环境变量与请求头不进响应 |

安装

装一个包就够:Host 半边提供设置命名空间,同一个包的浏览器半边提供设置页那一页 —— 页面挂在声明了 dsh.client 的那条 Loader 行上,所以它天然跟着 Host 走。

环境要求:@deepseek-ai/cordis ^4.0.3,以及 @deepseek-ai/dsh-mcp-client / @deepseek-ai/dsh-skill >=0.1.7-alpha.2 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0(peer 依赖,由 dsh 运行时提供;范围覆盖 0.1.7 起的 0.1.x,以及含预发布在内的 0.2.x,包括桌面端自带的运行时)。页面本身只要有设置外壳就出现;只有「已加载」一节读 /agent-import/report,所以它需要组合里的 ctx.webServer(dsh Web 与桌面端都有)。
为什么是设置页,不是插件页的「官方」分组。 浏览器半边注册的是设置页的 settings.section 分栏,与 general / models / account / plugins 并列。插件页那个 plugins.item slot 按契约是官方设置卡的位置(官方占用者:agent-loop / shell / subagent / web-search);第三方插件自己的配置页用 settings.section,或插件区内的 settings.plugins.tab。

1. 装包

dsh plugin --profile web add @free-lzj/dsh-agent-import

从本仓库安装(改插件本身时才需要)

pnpm install
pnpm run build

dsh plugin --profile web add "<本仓库绝对路径>/packages/agent-import"
或者先 pnpm pack,再装生成的 .tgz

桌面端(Electron)

桌面端不是另一个客户端:它用同一套 dsh-web-app 组合,外加一个自带版本的 dsh 运行时,页面由 Host 自己的 ctx.webServer 在本机端口上提供 —— 所以两个半边都照常工作,只是 Profile 是 desktop,不是 web:

dsh plugin --profile desktop add @free-lzj/dsh-agent-import

桌面端自带的运行时版本与全局 CLI 通常不是同一个版本。若它落在本包 peer 范围之外,dsh 启动时的兼容性预检会把这一行整行禁用(stderr 打印 dsh: disabling profile plugin row "agent-import": …),插件与设置页都不会出现。两种解法:装一个 peer 范围覆盖该运行时的版本,或对精确版本授权 —— dsh plugin --profile desktop allow-version <包@版本> --dsh-version <运行时版本> --accept-risk(桌面端插件页对不兼容项也提供授权入口)。

2. 声明一行(必须)

装包只让它可解析;插件要真正启用,还得有这么一行。本包自带 dsh.bundle(补丁文件就是包目录里的 cordis.patch.yml),所以 dsh plugin add(或把包列进 profile 的 dsh.profile.bundles)会自动插入这一行;从本仓库安装或自己维护 profile 时,照下面手写亦可。可以写进 $DSH_HOME/profiles/<profile>/cordis.patch.yml(web、desktop 等),也可以用 overlay 启动:

- insert:
- id: agent-import
name: '@free-lzj/dsh-agent-import'

dsh web --patch examples/agent-import.cordis.yml

agent-import 这个 id 不能改。 dsh 用行自身的条目 id 命名它的设置命名空间,而设置页那一页跟随的正是这个命名空间;换个 id 就是另一个命名空间,页面不会出现。

3. 生效

Host 半边是启动时加载的 JS,改了要重启 dsh web;浏览器半边(lib/client.js)刷新页面即可。

从 0.2.x 升级

0.2.x 是两个包、两条 Loader 行(@free-lzj/dsh-agent-import + @free-lzj/dsh-client-ui-settings-agent-import)。0.3.0 把它们合成一个包,@free-lzj/dsh-client-ui-settings-agent-import 不再发布:

dsh plugin --profile web remove @free-lzj/dsh-client-ui-settings-agent-import
dsh plugin --profile web add @free-lzj/dsh-agent-import

然后把 profile 里那两条 insert 行删掉 ui-settings-agent-import 那条,只留 id: agent-import(内容与上面示例一致),重启 dsh web。设置页来自包自身的 dsh.client 声明,不需要再单独声明。

配置

设置页覆盖全部字段;配置文件里等价于:

- id: agent-import
name: '@free-lzj/dsh-agent-import'
config:
sources: ['codex', 'claude-code']
serverDenyList: ['node_repl']

| 字段 | 默认值 | 含义 |
| sources | ['codex', 'claude-code'] | 要读取 MCP 服务器的工具,按优先级排列 |
| skillSources | ['codex', 'claude-code'] | 自动导入的来源(22 个可选值见包 README);技能目录始终全部读取并列出,没打开的来源可以逐个手动导入 |
| skillAutoImport | true | 激活时是否把来源技能自动建为链接 |
| codex.home | $CODEX_HOME,否则 ~/.codex | 存放 Codex config.toml 与 skills/ 的目录 |
| codex.configPath | <home>/config.toml | 要读的 Codex 配置文件 |
| codex.includeSystemSkills | false | 连 Codex 自带的 skills/.system 一起导入 |
| claudeCode.configDir | $CLAUDE_CONFIG_DIR,否则 ~/.claude | 存放 Claude Code 技能的目录 |
| claudeCode.configPath | ~/.claude.json | 存放用户级服务器与工作区覆盖的 Claude Code 配置 |
| projectRoot | 空,取进程工作目录 | 读取项目级服务器与技能目录的工作区 |
| mcp | true | 是否挂载导入的 MCP 服务器 |
| skills | true | 是否导入并管理技能 |
| serverDenyList | [] | 不挂载的服务器名,按声明工具里的原名匹配 |
| maxServers | 64 | 最多挂载多少个导入的服务器 |
| maxSkills | 200 | 一次最多读取多少个技能 |
| failOnStartupError | false | 某个导入的服务器启动失败时是否拒绝激活本插件 |

「已加载」怎么来的

Host 插件在 GET /agent-import/report 上公布当前那次导入的结果,设置页的「已加载」一节用同源 fetch 读它。这条路由和 dsh 自己的页面同源,但不在 API 网关的会话校验之内,所以它只回答同源请求(Sec-Fetch-Site 既不是 same-origin/none、或 Origin 与 Host 不一致,直接 403;非 GET/HEAD 405),并且只带名字与位置:服务器的参数、环境变量与请求头不出现在响应里。

技能这一侧是按请求现读磁盘的:skills 说的是 dsh 自己技能目录里当前有什么(导入的链接与手工放的真实技能)——那才是 dsh 真正加载的东西;在外部增删技能后点一次「刷新」即可看到。服务器的挂载结果来自当前这次导入生成。

「技能」一节的读写走另外三条路由:GET /agent-import/skills(整份目录)、GET /agent-import/skills/content?name=&source=(一条技能的正文)、POST /agent-import/skills/import 与 POST /agent-import/skills/remove。写路由除了同源之外还要求 x-dsh-agent-import: 1 与 content-type: application/json:跨站表单发不出这个自定义头,所以你在浏览器里打开的任意页面都无法借你的手导入或移除技能。

开发

pnpm install
pnpm run typecheck # 单包(两个半边一起)
pnpm run build # tsc 出类型 + tsdown 出 lib/index.js(Node 半边)、lib/client.js(浏览器半边)
pnpm run test # vitest:16 个 spec 文件 / 250 个测试

先 build 再 test:tests/package-faces.client.spec.ts 校验的是产物(注册 id、dsh.client 声明、exports["./client"]、浏览器入口有没有向 Host 半边取值),没有 lib/ 时其中一条会显示为 skipped。

CI(.github/workflows/ci.yml)在 windows-latest 上跑:adapter 的 spec 断言 Windows 盘符路径(Codex / Claude Code 主目录用 C:、D: 夹具),在 Linux 上这些夹具会被当成相对路径。

浏览器半边的 spec 需要 dsh 客户端包的 Node 半边与模块表,vitest.config.ts 与 packages/agent-import/tests/support/ 说明了这两处接线(见包 README 的「测试如何拿到 dsh 的客户端代码」)。

发布

cd packages/agent-import
npm publish # prepublishOnly 会先 build;--access public 写在 publishConfig 里

- 版本号在 packages/agent-import/package.json;npm 上已占用的版本不能重发。
- 账号开了 auth-and-writes 2FA 时,npm publish 需要 OTP,或者用勾了 Bypass 2FA 的 granular access token:普通 token 会以 403 … bypass 2fa enabled is required 失败。
- npm 包页的 README 取自 tarball,发布之后再改 README 不会同步到 npm,要发一个新版本。

已知限制

- 这个包不在 dsh 自带 Web 组合里,必须在 profile 中声明上面那一行(本包自带 dsh.bundle,作为 bundle 安装时会自动插入,不必手写)。
- 「已加载」走的是 dsh Web 自身的 HTTP 路由,所以这一节需要有 ctx.webServer 的组合。dsh Web 与 Electron 桌面端都有(桌面端的页面就是 Host 的 ctx.webServer 在本机端口上提供的);在没有 ctx.webServer 的组合里,这一节显示为不可用,其余配置照常。
- dsh 启动时会做兼容性预检:peer 范围不含当前运行时的插件会被整行禁用(stderr 里打印 dsh: disabling profile plugin row …),此时设置页完全不出现,看起来像没装上。用 dsh plugin --profile <profile> allow-version <包@版本> --dsh-version <运行时版本> --accept-risk 对精确版本授权即可放行。本包的 peer 范围覆盖 0.1.x 与 0.2.x 运行时,再往后的运行时需要放宽范围或授权。
- 「已加载」一节只回答「挂载了吗」:服务器挂载成功但自身连不上时,连接错误由 dsh 的 mcp-client 自己记日志(failOnStartupError: false 时它会持续重连),这一行仍显示「已挂载」。
- 外部配置文件只在激活时读取一次(本插件自身配置除外):在 Codex / Claude Code 那边改了声明,需要重载或重启 dsh。
- Windows 上的文件型技能(<root>/<name>.md,而不是一个目录)建符号链接需要开发者模式;本插件不会退化成复制或硬链接(硬链接无法被识别为链接),而是跳过并报 unsupported。目录型技能在 Windows 上用 junction,任何权限下都能导入。
- 与 @michengai/dsh-skills-manager 并存时两者互不感知:那个插件会跳过 ~/.dsh/skills 下的符号链接,因此看不到也不管理本插件导入的技能;同一批技能建议只用其一管理。
- 两边工具的插件市场(如 Codex plugin.json)不会展开,只导入服务器声明和技能目录。
- 真实组合的端到端测试(真装 dsh 启动一次、断言工具与技能可见)留在 dsh 主仓库里跑 —— 它依赖主仓库自带的 profile 启动夹具;本仓库的 CI 跑类型检查、构建与单元/组件测试。

License

MIT
预览分享卡片长什么样 ↓Free-LZJ/free-dsh-plugins
分享 · DeepSeek Harness Hub
Free-LZJ/free-dsh-plugins

把 Codex 与 Claude Code 的 MCP 和技能导入 dsh

回到顶部