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

Paseo 直连 Jecvay/paseo-dsh-direct

DeepSeek Harnessv0.2.13
Jecvay4 天前有提交已提供中文文档扫描:高危

DeepSeek Harness 的 Paseo Provider Plugin (Direct Provider)

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

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

自动兼容检查未通过:缺少 main/exports/bin 入口声明。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Jecvay/paseo-dsh-direct
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · model
装得上吗
npm 包存在但缺 main/exports/bin 入口声明,源码安装也可能起不来
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 4 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

缺少 main/exports/bin 入口声明

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包paseo-dsh-direct @ 0.2.13
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 00:25:07

🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

安装时即执行脚本命令参数由运行时变量拼接读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 125 处,展示前 101 条)
  • 执行外部命令来自配置/变量
    scripts/install-lefthook.mjs:43
    const result = spawnSync(command, args, {
  • 读取本地文件
    scripts/install-lefthook.mjs:166
    const entries = readdirSync(linkedDirectory, { withFileTypes: true })
  • 读取本地文件
    scripts/install-lefthook.mjs:179
    return lstatSync(path)
  • 读取本地文件
    scripts/install-lefthook.mjs:295
    return readFileSync(lockPath, 'utf8')
  • 读取本地文件
    scripts/install-lefthook.mjs:304
    return lstatSync(lockPath)
  • 删除本地文件
    scripts/install-lefthook.mjs:358
    unlinkSync(lockPath)
  • 写入本地文件
    scripts/install-lefthook.mjs:382
    writeFileSync(lockHandle, ownedRecord)
  • 读取本地文件
    scripts/install-lefthook.mjs:475
    if (!existsSync(hooksPath)) return undefined
  • 读取本地文件
    scripts/install-lefthook.mjs:476
    const hooksStat = lstatSync(hooksPath)
  • 写入本地文件
    scripts/install-lefthook.mjs:515
    mkdirSync(hooksPath, { mode: 0o700 })
  • 写入本地文件
    scripts/install-lefthook.mjs:517
    writeFileSync(markerPath, ownershipMarkerContent(hooksPath), { flag: 'wx', mode: 0o600 })
  • 写入本地文件
    scripts/install-lefthook.mjs:522
    writeFileSync(markerPath, ownershipMarkerContent(hooksPath), { mode: 0o600 })
  • 执行外部命令运行时拼接
    scripts/install-lefthook.mjs:546
    ? spawnSync(`"${lefthook}"`, args, { cwd: root, env, stdio: 'inherit', shell: true })
  • 执行外部命令来自配置/变量
    scripts/install-lefthook.mjs:547
    : spawnSync(lefthook, args, { cwd: root, env, stdio: 'inherit' })
  • 执行外部命令固定命令
    scripts/install-lefthook.mjs:600
    const probe = spawnSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' })
  • 读取本地文件
    scripts/agent-note-tree.ts:46
    for (const entry of readdirSync(agentNoteRoot, { withFileTypes: true })) {
  • 执行外部命令固定命令
    scripts/board.ts:33
    const run = spawnSync('gh', args, { encoding: 'utf8' })
  • 写入本地文件
    scripts/build.mjs:19
    await mkdir('dist', { recursive: true })
  • 写入本地文件
    scripts/build.mjs:20
    await writeFile('dist/dsh-bridge.mjs', bridge.contents)
  • 写入本地文件
    scripts/build.mjs:21
    await writeFile(
  • 读取本地文件
    scripts/build.mjs:28
    const { version } = JSON.parse(await readFile('package.json', 'utf8'))
  • 写入本地文件
    scripts/build.mjs:29
    await writeFile(
  • 读取本地文件
    scripts/repo-files.ts:76
    const lines = readFileSync(absPath, 'utf8').split('\n')
  • 发起网络请求
    scripts/smoke-bridge.ts:26
    const sessions = await bridge.request('session.list', {}, LIST_SESSIONS_TIMEOUT_MS)
  • 发起网络请求
    scripts/smoke-bridge.ts:59
    const opened = await bridge.request('session.open', { cwd })
  • 发起网络请求
    scripts/smoke-bridge.ts:61
    await bridge.request('session.prompt', { sessionId, content: [{ type: 'text', text: PROMPT }] })
  • 发起网络请求
    scripts/smoke-bridge.ts:63
    const first = await bridge.request('session.read', { sessionId })
  • 发起网络请求
    scripts/smoke-bridge.ts:64
    await bridge.request('session.close', { sessionId })
  • 发起网络请求
    scripts/smoke-bridge.ts:65
    const resumed = await bridge.request('session.open', { sessionId, resume: true, cwd })
  • 读取本地文件
    scripts/verify-agent-note-classification.ts:15
    if (existsSync(resolve(import.meta.dirname, '..', legacyRoot))) {
  • 读取本地文件
    scripts/verify-agent-note-format.ts:44
    const lines = readFileSync(resolve(agentNoteRoot, note.rel), 'utf8').split('\n')
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:31
    if (!existsSync(resolve(archiveRoot, 'AGENTS.md'))) errors.push('archived/AGENTS.md is required')
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:33
    for (const entry of readdirSync(archiveRoot, { withFileTypes: true })) {
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:47
    for (const child of readdirSync(resolve(archiveRoot, entry.name), { withFileTypes: true })) {
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:55
    artifacts.set(rel, readFileSync(resolve(archiveRoot, rel)))
  • 执行外部命令固定命令
    scripts/verify-archived-agent-notes.ts:64
    const result = spawnSync('git', args, { cwd: repoRoot, encoding: 'utf8' })
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:78
    if (existsSync(manifestPath)) {
  • 读取本地文件
    scripts/verify-archived-agent-notes.ts:80
    manifest = parseArchiveManifest(readFileSync(manifestPath, 'utf8'))
  • 写入本地文件
    scripts/verify-archived-agent-notes.ts:112
    writeFileSync(manifestPath, rendered)
  • 读取本地文件
    scripts/verify-doc-refs.ts:35
    return findReferenceViolations(root, absPath, DOC_REF, ref => ref, ref => !existsSync(resolve(root, ref)))
  • 读取本地文件
    scripts/verify-md-links.ts:146
    const anchors = documentAnchors(readFileSync(absPath, 'utf8'))
  • 读取本地文件
    scripts/verify-md-links.ts:170
    const source = readFileSync(absPath, 'utf8')
  • 读取本地文件
    scripts/verify-md-links.ts:178
    if (!existsSync(resolved)) {
  • 写入本地文件
    server/bridge-client.test.ts:70
    await writeFile(
  • 写入本地文件
    server/bridge-client.test.ts:74
    await chmod(executable, 0o755);
  • 读取本地文件
    server/bridge-client.test.ts:83
    assert.ok((await stat(path.join(f.home, "profiles", DEFAULT_PROFILE))).isDirectory());
  • 读取本地文件
    server/bridge-client.test.ts:85
    await readFile(f.log, "utf8"),
  • 删除本地文件递归
    server/bridge-client.test.ts:89
    await rm(f.root, { recursive: true, force: true });
  • 读取本地文件
    server/bridge-client.test.ts:100
    await assert.rejects(stat(f.log));
  • 写入本地文件
    server/bridge-client.test.ts:101
    await mkdir(path.join(f.home, "profiles", "custom"), { recursive: true });
  • 删除本地文件递归
    server/bridge-client.test.ts:104
    await rm(f.root, { recursive: true, force: true });
  • 读取本地文件
    server/bridge-client.ts:182
    return (await stat(directory)).isDirectory();
  • 写入本地文件
    server/bridge-client.ts:359
    await writeFile(bridgePath, options.bridgeSource, { mode: 0o600 });
  • 写入本地文件
    server/bridge-client.ts:360
    await writeFile(
  • 发起网络请求
    server/bridge-client.ts:380
    client.initialized = await client.request("bridge.initialize", {});
  • 发起网络请求
    server/bridge-client.ts:530
    this.request("bridge.shutdown", {}).catch(() => undefined),
  • 删除本地文件递归
    server/bridge-client.ts:542
    await rm(this.temporaryDirectory, { recursive: true, force: true });
  • 读取本地文件
    server/client-icons.test.ts:17
    const source = readFileSync(new URL("../index.client.tsx", import.meta.url), "utf8");
  • 写入本地文件
    server/dsh/service.test.ts:383
    await writeFile(file, "hello");
  • 读取本地文件
    server/dsh/service.ts:632
    data: await readFile(part.path),
  • 执行外部命令来自配置/变量
    server/dsh-spawn.ts:34
    return spawn(target.command, target.args, { ...options, env: target.env, windowsHide: true });
  • 写入本地文件
    server/dsh-version.test.ts:14
    await writeFile(file, `#!/bin/sh\n${body}\n`);
  • 写入本地文件
    server/dsh-version.test.ts:15
    await chmod(file, 0o755);
  • 删除本地文件递归
    server/dsh-version.test.ts:28
    await rm(f.root, { recursive: true, force: true });
  • 删除本地文件递归
    server/dsh-version.test.ts:38
    await rm(f.root, { recursive: true, force: true });
  • 删除本地文件递归
    server/dsh-version.test.ts:48
    await rm(f.root, { recursive: true, force: true });
  • 删除本地文件递归
    server/dsh-version.test.ts:58
    await rm(f.root, { recursive: true, force: true });
  • 删除本地文件递归
    server/dsh-version.test.ts:68
    await rm(f.root, { recursive: true, force: true });
  • 读取本地文件
    server/dsh-version.test.ts:79
    assert.equal((await readFile(log, "utf8")).trim().split("\n").length, 1);
  • 删除本地文件递归
    server/dsh-version.test.ts:81
    await rm(f.root, { recursive: true, force: true });
  • 执行外部命令来自配置/变量
    server/e2e-interaction.test.ts:13
    const hasDsh = spawnSync(executable, ["--version"], { stdio: "ignore" }).status === 0;
  • 读取密钥环境变量
    server/e2e-interaction.test.ts:14
    const skip = !process.env.DEEPSEEK_API_KEY
  • 发起网络请求
    server/e2e-interaction.test.ts:46
    await bridge.request("session.prompt", { sessionId, content: [{ type: "text", text }] });
  • 发起网络请求
    server/e2e-interaction.test.ts:69
    const opened = await bridge.request("session.open", { cwd, permissionPreset: strict?.id });
  • 发起网络请求
    server/e2e-interaction.test.ts:73
    await bridge.request("session.close", { sessionId: opened.sessionId }).catch(() => undefined);
  • 删除本地文件递归
    server/e2e-interaction.test.ts:77
    await rm(cwd, { recursive: true, force: true });
  • 发起网络请求
    server/e2e-interaction.test.ts:90
    await bridge.request("interaction.respond", { requestId: request.requestId, outcome: "allowed-once" });
  • 发起网络请求
    server/e2e-interaction.test.ts:112
    await bridge.request("interaction.respond", { requestId: request.requestId, answers });
  • 读取本地文件
    server/module-boundary.test.ts:12
    return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
  • 读取本地文件
    server/module-boundary.test.ts:22
    for (const file of ALLOWED.filter((dir) => existsSync(dir)).flatMap((dir) => sources(dir))) {
  • 读取本地文件
    server/module-boundary.test.ts:23
    const text = readFileSync(file, "utf8");
  • 发起网络请求
    server/provider.test.ts:830
    return super.request(method, params);
  • 发起网络请求
    server/provider.ts:448
    const result = await state.discoveryBridge.request(
  • 发起网络请求
    server/provider.ts:499
    const opened = await bridge.request("session.open", {
  • 发起网络请求
    server/provider.ts:514
    title ? bridge.request("session.rename", { sessionId: opened.sessionId, title }) : undefined,
  • 发起网络请求
    server/provider.ts:611
    await session.bridge.request("session.steer", {
  • 发起网络请求
    server/provider.ts:634
    const result = await session.bridge.request("session.prompt", { sessionId: session.nativeId, content });
  • 发起网络请求
    server/provider.ts:663
    const result = await session.bridge.request("session.command", {
  • 写入本地文件
    server/subagent-settings.e2e.test.ts:16
    await mkdir(profile, { recursive: true });
  • 写入本地文件
    server/subagent-settings.e2e.test.ts:17
    await writeFile(path.join(profile, "package.json"), JSON.stringify({
  • 写入本地文件
    server/subagent-settings.e2e.test.ts:21
    await writeFile(path.join(profile, "cordis.yml"), "[]\n");
  • 写入本地文件
    server/subagent-settings.e2e.test.ts:22
    await writeFile(path.join(profile, "cordis.patch.yml"), "[]\n");
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:36
    const initial = await first.request("subagent.settings.read", {});
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:42
    const session = await first.request("session.open", { cwd: home });
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:43
    const history = await first.request("session.read", { sessionId: session.sessionId });
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:45
    await first.request("session.close", { sessionId: session.sessionId });
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:49
    const reloaded = await second.request("subagent.settings.read", {});
  • 发起网络请求
    server/subagent-settings.e2e.test.ts:51
    const disabled = await second.request("subagent.settings.save", {
  • 发起网络请求
    server/subagent-settings.ts:47
    ? await bridge.request("subagent.settings.save", { ...input, revision: revision! })
  • 发起网络请求
    server/subagent-settings.ts:48
    : await bridge.request("subagent.settings.read", {});
  • 读取本地文件
    server/timeline-cards.test.ts:8
    const manifest = JSON.parse(readFileSync(new URL("../paseo-plugin.json", import.meta.url), "utf8")) as { id: string };
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

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

功能亮点

  • 直连Paseo服务

README

由 DeepSeek 最新模型翻译生成
paseo-dsh-direct paseo-dsh-direct 通过 Direct Provider,把本机的 DeepSeek Harness(dsh)接入 Paseo。 安装 需要 Paseo 0.11 及以上,并在运行 Paseo daemon 的机器上装好 dsh,它的 major.minor 要和你装的插件线一致。Paseo 0.8 至 0.10 请安装 npm:paseo-dsh-direct@0.2.1。 在 Paseo 里打开 Settings → Plugins → Install Plugin,npm 和 Git 两种来源任填一个: | 你的 dsh | npm | Git | | 0.2.x | npm:paseo-dsh-direct | https://github.com/Jecvay/paseo-dsh-direct | | 0.1.x | npm:paseo-dsh-direct@dsh-0.1 | 只能用命令行:paseo plugin install https://github.com/Jecvay/paseo-dsh-direct --ref rel/0.1 | 更新插件在 daemon 所在机器上运行(App 的插件菜单里没有更新入口):
展开完整文档(README 剩余 1 节)
paseo-dsh-direct

paseo-dsh-direct 通过 Direct Provider,把本机的 DeepSeek Harness(dsh)接入 Paseo。

安装

需要 Paseo 0.11 及以上,并在运行 Paseo daemon 的机器上装好 dsh,它的 major.minor 要和你装的插件线一致。Paseo 0.8 至 0.10 请安装 npm:paseo-dsh-direct@0.2.1。

在 Paseo 里打开 Settings → Plugins → Install Plugin,npm 和 Git 两种来源任填一个:

| 你的 dsh | npm | Git |
| 0.2.x | npm:paseo-dsh-direct | https://github.com/Jecvay/paseo-dsh-direct |
| 0.1.x | npm:paseo-dsh-direct@dsh-0.1 | 只能用命令行:paseo plugin install https://github.com/Jecvay/paseo-dsh-direct --ref rel/0.1 |

更新插件在 daemon 所在机器上运行(App 的插件菜单里没有更新入口):

paseo plugin update paseo-dsh-direct --check # 看有没有新版本 paseo plugin update paseo-dsh-direct --yes # 更新到最新

更多:兼容性说明 · 命令行安装、本地目录安装、环境变量

为什么叫 Direct

其他 dsh 接入大多走 ACP,那是一套所有 agent 都能用的通用协议。本插件不走 ACP,直接原生对接 dsh,dsh 的各种行为都能按 Paseo 自己的方式呈现:

- 回复和思考过程流畅地流式输出,不会被切成一段一段。
- 工具审批和 dsh 向你提的问题,显示成 Paseo 自带的审批卡片和问答卡片。
- 已有的 dsh 会话可以导入 Paseo 接着用。
- dsh 的斜杠命令(/compact、/plan 等)出现在 Paseo 的 / 菜单里。
- Paseo 的用量表显示 dsh 的 token 用量和上下文占用。
- 目标变化(dsh 自己在 /goal 命令输出里已报告的除外)、计划模式切换和权限预设变化会在对话里显示为小的时间线卡片。

版本号

插件版本号的 major.minor 跟随它支持的 dsh 线;最后一位是插件自己的发布计数,不跟 dsh 走。按本机的 dsh 版本选装对应线——见上表,完整规则和已实测的 dsh 版本见兼容性说明。

使用

新建对话时选择 DeepSeek Harness。模型和 preset 来自已配置的 DSH profile。已有原生 DSH 会话可通过 Paseo 的 Import session 导入,并保留原生会话标识。

Provider 支持连续正文和思考输出、工具执行与审批、用户问答、模型和 preset 配置、中断及会话恢复。它用插件专用的 paseo profile 启动 DSH,不修改 Paseo 或 DSH 核心。

插件使用名为 paseo 的 DSH profile。首次启动时,插件用 DSH 官方的 web 模板自动创建它(位置是 ~/.dsh/profiles/paseo;设置了 $DSH_HOME 时在其下)。模型路由、默认模型和权限预设写在 ~/.dsh/profiles/paseo/cordis.patch.yml。可在 Paseo 设置里的 DeepSeek Harness 页(dsh executable、dsh profile 两项)指定可执行文件与 profile。可执行文件的选择顺序:PASEO_DSH_EXECUTABLE、设置页、Paseo 配置的 agents.providers.dsh-pi.command、PATH 里的 dsh。profile 的选择顺序:PASEO_DSH_PROFILE、设置页、默认的 paseo;显式指定的 profile 不会被自动创建。改动对新会话生效,已在运行的会话继续使用原来的 dsh。如果 Paseo Daemon 默认关闭插件加载,请先在配置中启用 pluginsEnabled。

同一设置页的 Subagent models 区域可以按名称或提供方搜索模型、逐项勾选、全选、清空或关闭选模。首次初始化会选中当前可用的全部模型并保存到 DSH profile;已有选择(包括显式关闭)会保留,后续新增模型需要手动勾选。改动对支持选模的 preset 的新会话生效,详见设置页说明。

如果原生会话仍被另一个 DSH 客户端(如终端界面)占用,请先在那里释放,再从 Paseo 导入或恢复。

从源码安装

用于本地开发,或不走 Settings 界面直接安装:

git clone https://github.com/Jecvay/paseo-dsh-direct.git
cd paseo-dsh-direct
npm ci
npm run build
paseo plugin install "$PWD"
paseo plugin ls
paseo provider models dsh-pi

构建后也可以直接安装本地源码:paseo plugin install /absolute/path/to/paseo-dsh-direct。命令行还能指定 Settings 界面给不了的 Git ref:

paseo plugin install github:Jecvay/paseo-dsh-direct --ref <tag-or-commit>

开发

npm ci
npm run build
npm run typecheck
npm test
npm run verify:notes
npm run verify:docs

参阅文档索引、兼容性说明、插件开发与验证和 Alpha 验收规范。

许可

MIT
预览分享卡片长什么样 ↓Jecvay/paseo-dsh-direct
分享 · DeepSeek Harness Hub
Jecvay/paseo-dsh-direct

DeepSeek Harness 的 Paseo Provider Plugin (Direct Provider)

回到顶部