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

集群插件编排 ruby1304/dsh-fleet

DeepSeek Harnessv0.1.0
ruby130454 天前有提交已提供中文文档扫描:含敏感能力

向多台受信设备原子发布插件并派发签名任务

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

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

自动兼容检查有告警:npm 同名包「dsh-fleet」归属 scriptsnet/dsh-fleet,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ruby1304/dsh-fleet
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · dev
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 54 天前
档位由哪些信号合成

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

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

npm 同名包「dsh-fleet」归属 scriptsnet/dsh-fleet,装到的可能不是本插件

展开查看检查明细 ↓

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

✓npm 包dsh-fleet @ 0.1.0
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/9/22 17:50:55

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 282 处,展示前 88 条)
  • 执行外部命令来自配置/变量
    index.mjs:643
    const child = spawn(invocation.file, invocation.args, {
  • 读取本地文件
    index.mjs:823
    realpath(artifactStore),
  • 读取本地文件
    index.mjs:824
    realpath(candidate),
  • 读取本地文件
    index.mjs:825
    lstat(candidate)
  • 读取本地文件
    index.mjs:1261
    packageRealpath: await realpath(directory),
  • 读取本地文件
    index.mjs:1279
    const [nodeRealpath, dshEntrypointRealpath] = await Promise.all([realpath(execPath), realpath(entrypointPath)]);
  • 发起网络请求
    index.mjs:1379
    const response = await fetch(requestUrl, {
  • 发起网络请求
    index.mjs:1394
    const response = await fetch(requestUrl, {
  • 读取本地文件
    index.mjs:1453
    const raw = JSON.parse(await readFile(join(profileDir, "node_modules", id, "package.json"), "utf8"));
  • 执行外部命令来自配置/变量
    index.mjs:1773
    return execFileSync(binary, ["--version"], {
  • 发起网络请求
    testing.mjs:447
    const response = await fetch(requestUrl, {
  • 发起网络请求
    testing.mjs:462
    const response = await fetch(requestUrl, {
  • 读取本地文件
    testing.mjs:521
    const raw = JSON.parse(await readFile(join(profileDir, "node_modules", id, "package.json"), "utf8"));
  • 读取本地文件
    testing.mjs:536
    const profileManifest = JSON.parse(await readFile(join(config.profileDir, "package.json"), "utf8"));
  • 读取本地文件
    testing.mjs:542
    manifest: parseFleetManifest(await readFile(config.manifestPath, "utf8")),
  • 读取本地文件
    testing.mjs:553
    const lock = parse(await readFile(join(config.profileDir, "pnpm-lock.yaml"), "utf8"));
  • 读取本地文件
    testing.mjs:732
    const metadata = await stat(path);
  • 读取本地文件
    testing.mjs:1420
    return parseAgentConfig(JSON.parse(await readFile(path, "utf8")));
  • 执行外部命令来自配置/变量
    testing.mjs:2543
    const child = spawn(file, args, {
  • 写入本地文件
    testing.mjs:2764
    await rename(temporary, path);
  • 删除本地文件
    testing.mjs:2768
    await rm(temporary, { force: true });
  • 写入本地文件
    testing.mjs:2785
    await mkdir(path, {
  • 删除本地文件
    testing.mjs:2886
    await rm(lockPath);
  • 删除本地文件
    testing.mjs:2889
    await rm(claimPath, { force: true });
  • 删除本地文件
    testing.mjs:2900
    await rm(lockPath, { force: true });
  • 删除本地文件
    testing.mjs:2953
    await rm(destination, {
  • 删除本地文件
    testing.mjs:3001
    await rm(targetDir, {
  • 写入本地文件
    testing.mjs:3014
    await mkdir(targetDir, {
  • 发起网络请求
    testing.mjs:3188
    const response = await fetch(url, { signal: requestSignal });
  • 发起网络请求
    testing.mjs:3228
    const response = await fetch(endpoint, {
  • 写入本地文件
    testing.mjs:4060
    await rename(liveDir, backupDir);
  • 写入本地文件
    testing.mjs:4063
    await rename(stageDir, liveDir);
  • 写入本地文件
    testing.mjs:4066
    await rename(backupDir, liveDir);
  • 执行外部命令来自配置/变量
    testing.mjs:5924
    const child = spawn(launch.nodeBinary, [
  • 执行外部命令来自配置/变量
    testing.mjs:6600
    const child = spawn(config.dshBinary, [
  • 执行外部命令来自配置/变量
    testing.mjs:7715
    const child = spawn(invocation.file, invocation.args, {
  • 读取本地文件
    agent.mjs:2051
    return parseAgentConfig(JSON.parse(await readFile(path, "utf8")));
  • 读取密钥环境变量
    agent.mjs:7844
    if (node_process.env.LOG_TOKENS) console.log("|", cst.prettyToken(source));
  • 读取本地文件
    agent.mjs:8728
    realpath(artifactStore),
  • 读取本地文件
    agent.mjs:8729
    realpath(candidate),
  • 读取本地文件
    agent.mjs:8730
    lstat(candidate)
  • 读取本地文件
    agent.mjs:9104
    packageRealpath: await realpath(directory),
  • 读取本地文件
    agent.mjs:9122
    const [nodeRealpath, dshEntrypointRealpath] = await Promise.all([realpath(execPath), realpath(entrypointPath)]);
  • 执行外部命令来自配置/变量
    agent.mjs:10241
    const child = spawn(file, args, {
  • 写入本地文件
    agent.mjs:10462
    await rename(temporary, path);
  • 删除本地文件
    agent.mjs:10466
    await rm(temporary, { force: true });
  • 写入本地文件
    agent.mjs:10483
    await mkdir(path, {
  • 删除本地文件
    agent.mjs:10584
    await rm(lockPath);
  • 删除本地文件
    agent.mjs:10587
    await rm(claimPath, { force: true });
  • 删除本地文件
    agent.mjs:10598
    await rm(lockPath, { force: true });
  • 删除本地文件
    agent.mjs:10651
    await rm(destination, {
  • 删除本地文件
    agent.mjs:10699
    await rm(targetDir, {
  • 写入本地文件
    agent.mjs:10712
    await mkdir(targetDir, {
  • 发起网络请求
    agent.mjs:10886
    const response = await fetch(url, { signal: requestSignal });
  • 发起网络请求
    agent.mjs:10926
    const response = await fetch(endpoint, {
  • 写入本地文件
    agent.mjs:11769
    await rename(liveDir, backupDir);
  • 写入本地文件
    agent.mjs:11772
    await rename(stageDir, liveDir);
  • 写入本地文件
    agent.mjs:11775
    await rename(backupDir, liveDir);
  • 执行外部命令来自配置/变量
    agent.mjs:14564
    const child = spawn(launch.nodeBinary, [
  • 执行外部命令来自配置/变量
    agent.mjs:15240
    const child = spawn(config.dshBinary, [
  • 读取本地文件
    worker.mjs:1953
    root = await realpath(input.workspacePath);
  • 读取本地文件
    worker.mjs:1961
    return contained(root, await realpath(target));
  • 读取本地文件
    worker.mjs:1973
    info = await lstat(current);
  • 读取本地文件
    worker.mjs:1981
    resolved = await realpath(current);
  • 读取本地文件
    worker.mjs:2082
    directoryInfo = await lstat(directory);
  • 读取本地文件
    worker.mjs:2087
    for (const entry of await readdir(directory, { withFileTypes: true })) {
  • 写入本地文件
    worker.mjs:2218
    await mkdir(path, {
  • 写入本地文件
    worker.mjs:2242
    await rename(temporary, path);
  • 删除本地文件
    worker.mjs:2244
    await rm(temporary, { force: true });
  • 读取密钥环境变量
    bootstrap.mjs:7629
    if (node_process.env.LOG_TOKENS) console.log("|", cst.prettyToken(source));
  • 写入本地文件
    bootstrap.mjs:9584
    await mkdir(path, {
  • 读取本地文件
    bootstrap.mjs:9588
    const info = await lstat(path);
  • 读取本地文件
    bootstrap.mjs:9594
    const info = await lstat(path);
  • 读取本地文件
    bootstrap.mjs:9634
    await lstat(path);
  • 删除本地文件
    bootstrap.mjs:9759
    await Promise.all(created.map((path) => rm(path, { force: true })));
  • 删除本地文件
    bootstrap.mjs:9809
    await Promise.all(created.map((path) => rm(path, { force: true })));
  • 删除本地文件
    bootstrap.mjs:9865
    await Promise.all(created.map((path) => rm(path, { force: true })));
  • 写入本地文件
    bootstrap.mjs:9920
    await chmod(path, 448);
  • 删除本地文件
    bootstrap.mjs:9923
    await unlink(file);
  • 删除本地文件
    bootstrap.mjs:9926
    await rmdir(path);
  • 写入本地文件
    bootstrap.mjs:9954
    await mkdir(generationPath, { mode: 448 });
  • 写入本地文件
    bootstrap.mjs:10012
    await chmod(generationPath, 320);
  • 读取本地文件
    bootstrap.mjs:10108
    if (((await lstat(generationPath)).mode & 511) !== 320) throw new TypeError("generation directory must be immutable owner-only (0500)");
  • 读取本地文件
    bootstrap.mjs:10110
    if (((await lstat(join(generationPath, GENERATION_RECORD_NAME))).mode & 511) !== 256) throw new TypeError("generation.json mode must be 0400");
  • 读取本地文件
    bootstrap.mjs:10115
    const actualNames = (await readdir(generationPath)).sort();
  • 写入本地文件
    bootstrap.mjs:10216
    await rename(temporary, destination);
  • 删除本地文件
    bootstrap.mjs:10220
    await unlink(temporary);
  • 写入本地文件
    bootstrap.mjs:10433
    await rename(lockPath, quarantinePath);
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-host-apiproxy
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 声明式清单下发
  • 所有者批准后收敛
  • 原子发布插件

为 DeepSeek Harness 集群提供声明式清单,插件经所有者批准后收敛。

README

由 DeepSeek 最新模型翻译生成
dsh-fleet CI License: MIT 为在若干受信任机器上运行 DeepSeek Harness 的单一所有者提供原子化插件发布,以及经过签名、可恢复的设备到设备任务。 状态 0.4.0 面向 DSH >=0.1.0-rc.7 Fleet Host -> fixed local/SSH Agent atomic profile release or durable signed DSH task 公共包不能包含私有制品,也不能授予 task.submit、task.status 或 task.cancel。这些权限仅存在于接收设备上的私有覆盖层中。 安装生产环境配置文件应安装确切的 npm 发布版本或经过审查的 tarball。切勿将实时检出链接用作生产状态。
展开完整文档(README 剩余 1 节)
dsh-fleet

CI
License: MIT

为在若干受信任机器上运行 DeepSeek Harness 的单一所有者提供原子化插件发布,以及经过签名、可恢复的设备到设备任务。

状态

0.4.0 面向 DSH >=0.1.0-rc.7 Fleet Host -> fixed local/SSH Agent

atomic profile release or
durable signed DSH task

公共包不能包含私有制品,也不能授予 task.submit、task.status 或 task.cancel。这些权限仅存在于接收设备上的私有覆盖层中。

安装生产环境配置文件应安装确切的 npm 发布版本或经过审查的 tarball。切勿将实时检出链接用作生产状态。确切的 npm 安装形式为: bash
dsh plugin --profile web add dsh-fleet@0.4.0 --save-exact --ignore-scripts

要从源代码审查并打包: bash
git clone https://github.com/ruby1304/dsh-fleet.git
cd dsh-fleet
corepack enable
pnpm install --frozen-lockfile --ignore-scripts
pnpm run release:check
npm pack --ignore-scripts
shasum -a 256 dsh-fleet-0.4.0.tgz
dsh plugin --profile web add /absolute/path/to/dsh-fleet-0.4.0.tgz --save-exact --ignore-scripts

该包提供 dsh-fleet-agent 和 dsh-fleet-bootstrap 二进制文件。在服务和 Host 目标配置中固定其解析后的发布路径;不要依赖登录 shell 的 PATH。

快速设备设置

从 examples/team-pack.yaml 和 examples/device-overlay.yaml 的私有副本开始。替换所有示例性的版本、完整性、摘要、身份和路径。

为每台设备创建一个团队范围的 Ed25519 身份: bash
dsh-fleet-bootstrap identity \
--output-dir /Users/example/.config/dsh-fleet/identity \
--team example-team \
--principal owner \
--device worker

这会写入一个仅所有者可访问的私钥和一个公开的 identity.invite.json。仅交换邀请文件。在接收设备上,将邀请字段复制到 trustedPeers 中,并仅授予所需的消息类型。通常,提交任务的控制器需要 task.submit、task.status 和 task.cancel;工作节点响应密钥通常需要 task.progress 和 task.result。

对于生产目标,组装一个完整的不可变代际。为规范集合中的每台设备重复 --overlay,但仅选择本地身份: bash
dsh-fleet-bootstrap generation-assemble \
--pack /absolute/path/to/team-pack.yaml \
--overlay /absolute/private/path/to/device-overlay.yaml \
--device worker \
--identity-dir /Users/example/.config/dsh-fleet/identity \
--root /Users/example/.local/share/dsh-fleet/runtime \
--generation-id web-1.0.0 \
--agent-bundle /absolute/reviewed/agent.mjs \
--worker-bundle /absolute/reviewed/worker.mjs

组装器会验证密钥绑定、团队/设备/主体身份、DSH 范围、确切来源、信任能力、工作区 ID、重启健康所有权、Agent schema 和 bundle 摘要。它会拒绝符号链接输入、非仅所有者可访问(0600)的私有 overlay 或私钥,以及已存在的代际。对于更新,请创建新的代际;切勿覆盖正在工作的代际。

包中托管的 profile.id 和 taskPolicy.profiles 是有意独立的。普通控制器管理和健康检查 web profile,而远程工作则限制在明确允许的一次性 profile(如 headless)上。

输出包含:

- fleet.lock.yaml:schema-v2 原子发布分配;
- trust-store.json:能力范围的对等密钥;
- task-policy.json:用于审查的已脱敏工作区/配置文件策略;
- agent.config.json:完整的一次性 Agent 配置;
- launcher.mjs、agent.mjs 和 worker.mjs:一个与摘要绑定的执行代次;
- routes.json 和 generation.json:稳定的 Host 路由以及精确的代次记录。

在将目标添加到控制器之前,先运行直接检查: bash
/absolute/path/to/node \
/absolute/runtime/current/launcher.mjs \
--config /absolute/runtime/current/agent.config.json \
doctor

doctor 是只读的。它会验证发布绑定、实时回环 Fleet 健康状态、身份密钥、信任存储、工件/工作区目录以及固定可执行文件,而不会安装插件或运行任务。之后使用 release-inspect 来审查所提议的确切发布增量。

请参阅完整的入门检查清单。

Host 配置

将 Fleet 添加到 DSH 配置文件补丁中。在显式启用之前,变更保持关闭。
yaml
- id: fleet
name: dsh-fleet
config:
deviceId: controller
manifestPath: /absolute/dsh-home/profiles/web/fleet.lock.yaml
desiredManifestPath: /absolute/runtime/current/fleet.lock.yaml
profile: web
dshBinary: /absolute/immutable/path/to/dsh
artifactStore: /absolute/private/path/to/artifacts
convergence:
enabled: true
principalId: owner
signerDeviceId: controller
timeoutMs: 600000
targets:
- deviceId: controller
transport: local
nodeBinary: /absolute/path/to/node
agentPath: /absolute/runtime/current/launcher.mjs
configPath: /absolute/runtime/current/agent.config.json
- deviceId: worker
transport: ssh
sshHost: worker-mac
nodeBinary: /opt/homebrew/bin/node
agentPath: /Users/example/.local/share/dsh-fleet/runtime/current/launcher.mjs
configPath: /Users/example/.local/share/dsh-fleet/runtime/current/agent.config.json

sshHost 必须是具有主机密钥策略的现有别名。用户名、SSH 选项、空白字符和 shell 标点符号都会被拒绝。Agent、Node 和配置路径必须是规范化的绝对路径,且不能包含空格。

manifestPath 是配置文件本地的实时清单,仅在配置文件重命名时更改。desiredManifestPath 是当前活跃的代次候选。当二者不同时,目标可以保持在线,以便规划升级,但在实时清单与期望清单完全一致之前,签名任务将保持禁用。

原子插件发布

一个稳定的 schema-v2 设备在每个配置文件中恰好分配一个发布版本。一次审批覆盖整个配置文件增量,而不是一系列部分可见的插件变更。

- 公共 npm 插件需要精确的语义化版本和 SHA-512 SRI。
- 公共 GitHub 插件需要 owner/repository 以及小写的 40 字符提交 SHA。
- 私有插件需要精确的版本,以及位于已配置工件存储中名为 .tgz 的 tarball。
- Agent 会验证私有 tarball 摘要、包标识/版本以及 DSH bundle 元数据。
- 暂存发生在同一文件系统上、与实时 profile 相邻的位置。
- DSH 运行时读取 /profiles//fleet.lock.yaml;Agent 将已批准的不可变 generation 复制到暂存 profile 中,以便 manifest 和包一起切换并一起回滚。
- Agent 验证暂存 profile,停止其拥有的服务,通过重命名交换目录,重启,并证明 DSH/Fleet 健康状态与 release 对齐。
- 计划绑定实际运行的 Node/DSH 入口点、包版本和文件摘要。对于 launchd,它还绑定确切的服务参数向量和 DSH_HOME;Agent 在交换前和重启后重新检查这些内容,而不是信任某个 wrapper 的版本输出。
- 一个一次性的 pre-0.4 launchd 桥接可以检查尚未报告 runtimeIdentity 的 Host,但仅当确切的 launchd 定义、job PID 和监听器所有权证明正在运行的运行时。screen 目标和每次升级后健康检查都要求 Fleet RPC 运行时身份;此兼容路径不是通用回退。
- 交换后检查失败会通过重命名恢复先前的 profile。持久 release 标记可恢复提交后的崩溃。
- 成功转换会保留一个有界的两跳回滚链。较旧的精确备份仅通过单独审查的保留计划和批准来移除;未知/孤立状态会被报告,绝不会被通配删除。
- 不属于先前 Fleet release 的插件不会被移除。

旧版 schema-v1 单插件 planner 仍可读取以保持兼容,但新的稳定部署应使用 schema v2。

签名远程任务

Web 设置页面仅提交: text 目标设备 ID + 固定工作区 ID + 固定 profile ID + prompt

不存在远程路径、可执行文件、参数向量、URL 或任意 shell 字段。Host 将选定的逻辑执行 profile 解析为其确切的 profile 哈希,并将该哈希与实时 manifest、已应用的 release 和已安装策略摘要绑定。Agent 和 worker 在接受、启动、批准以及每次工具调用之前都会重新检查执行 profile。Host 请求一个固定的本地签名者 Agent 对请求进行签名,通过配置的本地/SSH 目标发送请求,并验证目标的签名响应。

任务记录是持久的。重放同一条已签名消息会返回其存储的回执;同一任务 ID 的并发提交会被串行化。worker 限制持续时间、输出和并发,支持取消,并暴露已签名的进度/结果消息。tasks-resume 仅重启那些已持久接受但从未开始的任务;丢失的运行中 worker 不会被盲目重放,因为任务副作用可能不是幂等的。

这提供了有用的异步单所有者远程执行和重连语义。它不提供实时镜像终端,也无法恢复在回合中途死亡的 DSH 进程的内部状态。

UI
Fleet 注册 settings.section 并在常规 Settings 内容流中渲染。标签页涵盖状态、公开更新、原子发布、签名任务和手动跨团队协作。它不注册侧边栏页脚操作,也不使用固定定位的碰撞几何。

协作标签页导入和导出签名信封 JSON,用于交接和咨询审批。它没有 Relay,不打开工件引用,不能铸造任务能力,也绝不会将跨团队审批转变为工具授权。

安全边界

- Web 端点和 Fleet RPC 必须保持仅限回环。
- 私钥、覆盖层、清单、信任存储、任务状态和工件均为私有运营数据。
- A2A 对消息进行认证;SSH/本地传输仍会认证并到达机器。
- 撤销是从接收设备的信任存储中移除对等方密钥,随后进行配置部署。
- 安装脚本已禁用。已批准的插件在安装后仍以 DSH 所有者的权限执行。
- 进程组是清理机制,而非操作系统沙箱。崩溃的工作进程可能留下独立分离的子进程,需要操作员检查。
- Fleet 不分发提供商凭据或机密。

有关完整的威胁模型和恢复规则,请参阅 docs/SECURITY_MODEL.md。

开发 bash corepack enable
pnpm install --frozen-lockfile --ignore-scripts
pnpm run check
npm pack --dry-run --ignore-scripts

pnpm run check 执行严格的 TypeScript 检查、完整测试套件、确定性打包验证、示例/模式验证以及仓库卫生检查。生成的发布包已提交,且必须与 src/ 匹配。

文档

- 单所有者设备入门
- 安全模型
- 开源插件清单
- 发布和升级流程
- 产品需求和路线图
- 变更日志
- 安全报告
- 支持
- 贡献

许可证

MIT。捆绑依赖声明见 THIRD_PARTY_NOTICES.md。
预览分享卡片长什么样 ↓ruby1304/dsh-fleet
分享 · DeepSeek Harness Hub
ruby1304/dsh-fleet

向多台受信设备原子发布插件并派发签名任务

这是你的仓库?认领条目

回到顶部