把单机连接器扩展成多节点统一入口,按策略路由到任意机器
28.2/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/lixiaoshuang79/dsh-helm.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 70 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 66 处,展示前 66 条)
- 执行外部命令来自配置/变量packages/cli/src/cli.ts:256
const res = spawnSync(name, args, { stdio: 'inherit', shell: true }) - 读取本地文件packages/cli/src/doctor.ts:107
if (!existsSync(path)) return { found: false, display_name: '', node_id: '', hub_url: '', hasToken: false } - 读取本地文件packages/cli/src/doctor.ts:109
const raw = JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown> - 执行外部命令来自配置/变量packages/cli/src/doctor.ts:133
const r = spawnSync(cmd, args, { encoding: 'utf8', timeout: 5000, shell }) - 读取本地文件packages/cli/src/doctor.ts:329
} else if (!existsSync(plistPath)) { - 读取本地文件packages/cli/src/doctor.ts:333
const id = parseTunnelIdFromPlist(readFileSync(plistPath, 'utf8')) - 发起网络请求packages/cli/src/ha-proxy.ts:62
return fetch(url, { signal: AbortSignal.timeout(timeoutMs) }) - 读取本地文件packages/cli/src/install.ts:41
if (existsSync(configPath)) { - 发起网络请求packages/cli/src/pair.ts:194
.request(HUB_METHODS.ENROLLMENT_CONSUME, params, { timeoutMs: 10_000 }) - 读取本地文件packages/cli/src/pair.ts:241
if (existsSync(target) && !opts.force) { - 写入本地文件packages/cli/src/pair.ts:269
mkdirSync(dir, { recursive: true }) - 写入本地文件packages/cli/src/pair.ts:276
writeFileSync(target, JSON.stringify(nodeConfig, null, 2), { mode: 0o600 }) - 写入本地文件packages/cli/src/pair.ts:277
chmodSync(target, 0o600) - 发起网络请求packages/dashboard/src/hub.ts:69
const res = await fetch(url, { - 发起网络请求packages/dashboard/src/hub.ts:95
const healthzRes = await fetch(healthzUrl, { signal: AbortSignal.timeout(timeoutMs) }) - 发起网络请求packages/dashboard/src/metrics.ts:56
const res = await fetch(new URL('/metrics', baseUrl), { signal: AbortSignal.timeout(timeoutMs) }) - 发起网络请求packages/dashboard/src/pair.ts:26
const res = await fetch(new URL(path, hubUrl), { signal: AbortSignal.timeout(timeoutMs) }) - 读取本地文件packages/dashboard/src/server.ts:87
let html = await readFile(path.join(PUBLIC_DIR, 'index.html'), 'utf8') - 执行外部命令固定命令packages/dashboard/src/services.ts:64
execFileSync('pgrep', ['-f', escapePgrepPattern(pattern)], { stdio: 'ignore', timeout: 3000 }) - 执行外部命令固定命令packages/dashboard/src/services.ts:120
const output = execFileSync('launchctl', ['list'], { encoding: 'utf8', timeout: 5000 }) - 执行外部命令固定命令packages/dashboard/src/services.ts:129
const output = execFileSync('systemctl', ['--no-pager', 'list-units', '--all'], { encoding: 'utf8', timeout: 5000 }) - 发起网络请求packages/dashboard/src/status.ts:104
const res = await fetch(new URL('/cp-status', hubUrl), { signal: AbortSignal.timeout(timeoutMs) }) - 发起网络请求packages/dashboard/src/tunnel.ts:108
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }) - 发起网络请求packages/hub/src/connection.ts:83
return this.peer.request(method, params, { timeoutMs }) - 发起网络请求packages/hub/src/control-plane.ts:242
const res = await conn.request(NODE_METHODS.MCP_CALL, { tool: op, args: params }, 60_000) - 发起网络请求packages/hub/src/control-plane.ts:258
const ws = (await conn.request(NODE_METHODS.LIST_WORKSPACES, {}, 15_000)) as WorkspaceInfo[] - 发起网络请求packages/hub/src/control-plane.ts:274
const ss = (await conn.request(NODE_METHODS.LIST_SESSIONS, {}, 15_000)) as SessionInfo[] - 发起网络请求packages/hub/src/ha.ts:846
const resp = (await this.rpcPeerFor(peer).request(CP_METHODS.ELECT, req, { timeoutMs: 10_000 })) as ElectResponse | undefined - 发起网络请求packages/hub/src/ha.ts:892
const resp = (await this.rpcPeerFor(peer).request(CP_METHODS.LEASE_RENEW, req, { timeoutMs: 10_000 })) as { ok?: boolean } | undefined - 发起网络请求packages/hub/src/ha.ts:914
const resp = (await this.rpcPeerFor(peer).request(CP_METHODS.LEASE_RENEW, req, { timeoutMs: 10_000 })) as { ok?: boolean } | undefined - 发起网络请求packages/hub/src/ha.ts:1097
const resp = (await out.peer.request(CP_METHODS.SYNC, full, { timeoutMs: 10_000 })) as CpPeerState | undefined - 发起网络请求packages/hub/src/ha.ts:1131
await this.outbound.peer.request(CP_METHODS.HEARTBEAT, state, { timeoutMs: 10_000 }) - 发起网络请求packages/hub/src/ha.ts:1141
await st.inbound.request(CP_METHODS.HEARTBEAT, state, { timeoutMs: 10_000 }) - 读取本地文件packages/hub/src/hub-cli.ts:54
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version?: string } - 读取本地文件packages/hub/src/hub-cli.ts:86
const raw = JSON.parse(readFileSync(`${process.env.HOME ?? '.'}/.dsh/helm/node.json`, 'utf8')) as { node_id?: string } - 读取密钥环境变量packages/hub/src/hub-cli.ts:166
const envTokenLookup = tokenLookupFromEnv(process.env.DSH_HELM_TOKEN) - 读取密钥环境变量packages/node-agent/src/agent-cli.ts:45
if (process.env.DSH_HELM_MCP_TOKEN) cfg.local_mcp_token = process.env.DSH_HELM_MCP_TOKEN - 发起网络请求packages/node-agent/src/agent.ts:110
void this.peer.request(HUB_METHODS.PRESENCE_REPORT, { node_id: this.cfg.node_id, claim }).catch(() => { - 发起网络请求packages/node-agent/src/agent.ts:308
await this.peer?.request(HUB_METHODS.NODE_REGISTER, { node: this.nodeInfo() }) - 发起网络请求packages/node-agent/src/agent.ts:316
await this.peer?.request('catalog.reconcile', { node_id: this.cfg.node_id, sessions, workspaces }) - 发起网络请求packages/node-agent/src/agent.ts:379
await this.peer?.request('catalog.reconcile', { node_id: this.cfg.node_id, sessions, workspaces }) - 发起网络请求packages/node-agent/src/agent.ts:488
await this.peer?.request('node.heartbeat', { node_id: this.cfg.node_id, status }, { timeoutMs: 10_000 }) - 读取本地文件packages/node-agent/src/bridge.ts:60
if (readFileSync(c, 'utf8').trim().length > 0) return c - 发起网络请求packages/node-agent/src/bridge.ts:99
this.fetchImpl = opts.fetchImpl ?? ((...args: Parameters<typeof fetch>) => fetch(...args)) - 读取本地文件packages/node-agent/src/bridge.ts:263
return readFileSync(path, 'utf8').trim() - 读取本地文件packages/node-agent/src/config.ts:66
disk = JSON.parse(readFileSync(path, 'utf8')) as NodeConfigFile - 写入本地文件packages/node-agent/src/config.ts:86
mkdirSync(cfgDir, { recursive: true }) - 写入本地文件packages/node-agent/src/config.ts:87
writeFileSync(path, JSON.stringify({ ...cfg, token }, null, 2), { mode: 0o600 }) - 写入本地文件packages/node-agent/src/config.ts:88
chmodSync(path, 0o600) - 发起网络请求packages/node-agent/src/steer.ts:60
const fetchImpl = opts.fetchImpl ?? ((...args: Parameters<typeof fetch>) => fetch(...args)) - 删除本地文件packages/node-agent/src/summary.ts:214
rmSync(this.cachePath(sessionId), { force: true }) - 读取本地文件packages/node-agent/src/summary.ts:227
const parsed = JSON.parse(readFileSync(this.cachePath(sessionId), 'utf8')) as SessionSummary - 写入本地文件packages/node-agent/src/summary.ts:239
mkdirSync(this.cacheDir, { recursive: true }) - 写入本地文件packages/node-agent/src/summary.ts:240
writeFileSync(this.cachePath(sessionId), JSON.stringify(data, null, 2), { mode: 0o600 }) - 执行外部命令来自配置/变量packages/platform/src/tailscale.ts:21
const defaultExec: TailscaleExec = (file, args, opts) => execFileSync(file, args, opts) - 写入本地文件packages/store/src/db.ts:81
mkdirSync(dirname(opts.file), { recursive: true }) - 写入本地文件patches/goal-guard.mjs:64
writeFileSync(tmp, content) - 执行外部命令来自配置/变量patches/goal-guard.mjs:66
execFileSync(process.execPath, ['--check', tmp], { stdio: 'pipe' }) - 读取本地文件patches/goal-guard.mjs:75
if (!existsSync(target)) { - 读取本地文件patches/goal-guard.mjs:79
let src = readFileSync(target, 'utf8') - 写入本地文件patches/goal-guard.mjs:94
copyFileSync(target, bak) - 写入本地文件patches/goal-guard.mjs:95
writeFileSync(target, src) - 读取本地文件patches/goal-guard.mjs:102
let pluginSrc = existsSync(pluginTarget) ? readFileSync(pluginTarget, 'utf8') : '' - 读取本地文件patches/goal-guard.mjs:102
let pluginSrc = existsSync(pluginTarget) ? readFileSync(pluginTarget, 'utf8') : '' - 读取本地文件patches/goal-guard.mjs:126
let tgSrc = existsSync(toolGoalTarget) ? readFileSync(toolGoalTarget, 'utf8') : '' - 读取本地文件patches/goal-guard.mjs:126
let tgSrc = existsSync(toolGoalTarget) ? readFileSync(toolGoalTarget, 'utf8') : ''
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 多节点统一入口
- 按策略路由到任意机器
README
由 DeepSeek 最新模型翻译生成dsh-helm
DSH 多节点控制平面:把单机「ChatGPT ↔ DSH」连接器扩展成多节点控制平面。多台机器上的 DeepSeek Harness(DSH)通过节点代理(node-agent)注册到统一 Hub,ChatGPT 经一个入口即可路由到任意节点——读写代码、管理会话、查看健康,且不暴露任何节点给公网。
ChatGPT Web(连接器/插件) │ OpenAI Secure MCP Tunnel(tunnel-client,TLS) ▼ Hub 控制平面 MCP 127.0.0.1:3471(ChatGPT 入口) mesh :3470(节点接入) │ 路由:显式 target → session owner → workspace owner → presence → default ├──────────────┬──────────────┬──────────────┐ ▼ ▼ ▼ ▼ node-agent node-agent node-agent node-agent (每台机器:出站 WS + HMAC 握手) │ │ │ │ ▼ ▼ ▼ ▼ daemon 3457 → DSH daemon 3457 → DSH ……
展开完整文档(README 剩余 1 节)
dsh-helm
DSH 多节点控制平面:把单机「ChatGPT ↔ DSH」连接器扩展成多节点控制平面。多台机器上的 DeepSeek Harness(DSH)通过节点代理(node-agent)注册到统一 Hub,ChatGPT 经一个入口即可路由到任意节点——读写代码、管理会话、查看健康,且不暴露任何节点给公网。
ChatGPT Web(连接器/插件) │ OpenAI Secure MCP Tunnel(tunnel-client,TLS) ▼ Hub 控制平面 MCP 127.0.0.1:3471(ChatGPT 入口) mesh :3470(节点接入) │ 路由:显式 target → session owner → workspace owner → presence → default ├──────────────┬──────────────┬──────────────┐ ▼ ▼ ▼ ▼ node-agent node-agent node-agent node-agent (每台机器:出站 WS + HMAC 握手) │ │ │ │ ▼ ▼ ▼ ▼ daemon 3457 → DSH daemon 3457 → DSH …… (各节点本地 helm daemon,Bearer 鉴权)
- 每个节点跑 dsh-helm agent:只出站连 hub(mesh WS),向内桥接本机 helm daemon 的 MCP(127.0.0.1:3457/mcp)。
- hub 是唯一入口:ChatGPT 经 hub MCP(3471)调用工具,hub 按路由策略转发到正确节点;节点数对 ChatGPT 透明。
- 单机兼容:单节点且 node_id == hub defaultNodeId 时,路由与工具调用行为等价于单机 daemon(摘要/guard/steer 为上层增强,不影响既有调用语义)。
功能特性
- 多节点注册与心跳:节点身份 node_id(UUID)+ HMAC 挑战握手;15s 心跳、45s 租约;新版 agent 心跳超时自动重连(半开连接检测重连)。
- 五级路由:显式 target_node → session owner → workspace owner → 无歧义 presence → defaultNodeId 兜底;destructive/write 操作目标不清晰时 fail-closed 拒绝(route_confirmation_required),绝不猜。
- 转发可溯源:每次转发结果附带 _route.node_name(display_name)标注执行节点;route_explain 预演不执行。
- MCP 工具面 19+5:单机 daemon 的 19 个工具(code_/sessions_/projects_list/supervisor_health 等,snake_case 参数不变)原样保留,新增 nodes_list/node_get/route_explain/presence_claim/presence_release;所有可路由工具带可选 target_node。
- presence:手动声明(10 分钟 pin)+ macOS 前台应用自动探测(桌面 sidecar);15s 歧义窗口内双节点高置信 → 判 ambiguous,不自动选。
- 分层健康:control / channel / adapter / datapath / serena / tunnel 各层独立上报,绝不折叠成单一 status: ok。
- 跨节点聚合:workspaces_list/sessions_list/agents_list/projects_list 返回多节点扁平结果(每条带 node_id)。
- 审计与路由日志:节点注册、心跳、路由决策、presence 变更全部落库(audit/route_log)。
- 元数据红线:hub 存储只含元数据(节点/租约/会话与工作区目录/审计),从不存储 DSH 会话正文。
目录结构
dsh-helm/
├── packages/
│ ├── protocol/ # wire 协议:envelope、JSON-RPC、HMAC 握手、常量 │ ├── store/ # SQLite:节点注册表、presence、目录、审计 │ ├── hub/ # 控制面:Router、WS mesh 3470、MCP 3471 │ ├── node-agent/ # 节点代理:出站 WS、重连、本地 DSH 桥 │ ├── presence/ # presence providers(手动/macOS/浏览器) │ ├── platform/ # 跨平台适配(launchd/systemd/Windows 模板) │ └── cli/ # dsh-helm CLI(init/agent/hub/status/nodes/…)
├── tests/integration/ # 双 fake node 端到端测试 └── scripts/ # ops 脚本(bash,macOS 优先)
快速开始
前置:Node.js >= 22.5、pnpm、curl;每台节点机先装好 DSH 与 helm daemon(127.0.0.1:3457/mcp,Bearer token 在 ~/.agent-chatgpt-helm/token)。
1. 安装 CLI(构建 + 写 ~/.local/bin/{dsh-helm,dsh-helm-agent,dsh-helm-hub},幂等) ./scripts/install.sh
2. 初始化节点身份(生成 ~/.dsh/helm/node.json,权限 0600) dsh-helm init
3. 编辑 ~/.dsh/helm/node.json:设置 hub_url 与 local_mcp_token hub_url:内网/Tailscale 用 ws://:3470,生产用 wss://
4. hub 机器:启动控制面(mesh 3470 + MCP 3471;默认只绑 127.0.0.1) dsh-helm hub 多机场景:dsh-helm hub --bind --mcp-bind 127.0.0.1
5. 节点机器:启动 agent(先前台验证,再装自启服务) dsh-helm agent ./scripts/install-service.sh # macOS:launchd 服务(com.dsh-helm.node-agent)
6. 自检与状态 ./scripts/verify.sh # 0 全绿 / 1 警告 / 2 严重 ./scripts/health.sh # 节点状态表(走 hub MCP supervisor_health) dsh-helm status # 本地配置与连接状态
加入更多节点:新节点机 dsh-helm init 后,把 node.json 的 node_id 与 token 经安全渠道交给 hub 管理员,在 hub 机器上执行(幂等:追加/更新 token 表,自动重载 launchd 服务): bash ./scripts/register-node.sh
详细流程见 docs/onboarding.md。
接入 ChatGPT
两条路径,按部署阶段选择:
- A. 单机直连(起步):本机已有 helm daemon 时,hub 把本机节点当 local node,行为与单机连接器一致,无需隧道。
- B. 多节点(控制平面,推荐):OpenAI Secure MCP Tunnel 接入 hub MCP(3471),ChatGPT 一个入口管所有节点。
OpenAI Platform 侧完整教程(建 tunnel / 绑定 workspace / 建 API key / tunnel-client 参数 / 代理)见 docs/chatgpt-tunnel-setup.md;ChatGPT Web 侧(开发者模式 / 创建连接器 / 测试)见 docs/chatgpt-connector.md。
已有单机 connector 的机器升级:旧形态(tunnel 直连 daemon 3457)没有会话瘦身/插队/响应守卫等升级能力;按 docs/single-connector-upgrade.md 迁移到单机兼容模式(本地 hub + agent,tunnel 指向 hub MCP 3471),ChatGPT 侧零改动即获得全部升级能力(内容瘦身 / steer 插队 / 响应守卫,见下节)。
两种拓扑取舍:每台 daemon 各配一个 tunnel+连接器(多入口、各管各),或一个 hub tunnel + 一个连接器管 N 台节点(单入口,推荐——hub 路由 target_node/路由规则,回复带 node_name)。
控制面 HA(双 Control Plane)
两台 hub 组成一个 quorum(2/2)控制面,任一台故障时另一台仍可服务读路由与节点入口。
- 角色与租约:--cp-priority 小者胜出为 leader(唯一写者);leader 每 10s 向 peer 续写租约,peer 失联超过租约 TTL(--cp-failover-ms,默认 45s)→ 双方进入 read-only-no-quorum,写操作返回 QUORUM_LOST。follower 永不单方提升——失去 quorum 时只读不写(CAP 优先安全)。
- 恢复:peer 重连 → 注册表全量同步 → 强制重选(term+1)→ 租约双方确认 → 写恢复。整个恢复窗口内双方保持只读。
- agent 多 endpoint:node.json 配 hub_url + fallback_urls,重连时轮询尝试、成功后 pin;故障时自动切到第二 CP。
- 观测:GET /cp-status 返回 role/phase/writeMode/quorum/term/leaderId/peers/syncOk/leaseEpoch/failoverCount;dsh-helm doctor 与 Dashboard「控制面 HA」卡直接展示。
- ChatGPT 入口 HA:OpenAI tunnel-client 的 --mcp.server-url 是 channel 限定、无同连接器多后端 failover。本地起 dsh-helm ha-proxy(默认 127.0.0.1:3481,--primary http://127.0.0.1:3471 --secondary http://:3471),tunnel 仍指向一个连接器(3481);主 CP 失联自动切副 CP、恢复后切回。双 tunnel + 双连接器是备选拓扑。
- 第二 CP 部署:dsh-helm hub --cp-peer ws://:3470 --cp-priority 1 --cp-id --cp-token-env DSH_HELM_CP_TOKEN;两侧 DSH_HELM_TOKEN 都含双方节点 token 表(任一 agent 故障切换时对方 CP 都能认证)。MCP 需跨机可达时用 --mcp-bind (Tailscale ACL 围栏,单机场景保持 loopback)。
设备配对(新增 DSH 设备)
Dashboard「新增 DSH 设备」→ 生成一次性配对码(10 分钟有效、单次消费、仅存哈希);新机器执行 dsh-helm join --control-plane ws://:3470 --code 完成入网(生成长期 node token 写入 ~/.dsh/helm/node.json,hub 只存 hash/状态)。配对 API 仅 loopback + 防 CSRF 头;日志只记哈希前缀。详见 docs/security.md §5。
MCP Context Isolation(大上下文稳定性) ChatGPT ↔ DSH 连接器在长时间运行、大上下文 session 下的响应瘦身与监控(兼容层,链路不变):
- sessions_get 默认摘要:默认只返回结构化摘要(id/title/status/workspace/created_at/updated_at/last_message_summary/last_assistant_summary/current_goal/current_goal_seq/last_user_message/recent_evidence{commits,paths,errors,tests}/history_ref/safety_sanitized/token_estimate/continuation_available,无 messages)。摘要由 node agent 生成:只向 DSH 要最后 20 条消息(SUMMARY_WINDOW),current_goal 取窗口内行动性最高的用户指令(附来源 seq),recent_evidence 为正则启发式提取,疑似凭据行在进入任何摘要字段前剔除(safety_sanitized 标记)。实测基线:早期大 session 响应 75KB → 1.2KB;信息保真验收 fixture(1000 条消息)约 107KB → 0.7KB,默认响应 .json(60s TTL,写操作后失效)。
- 完整历史按需取:include_messages=true(可配 max_messages,默认 20)返回完整消息;before_seq 参数透传但 DSH 0.1.1 未实现真实翻页(探测实测:max_messages ≤100 且 beforeSeq 无效)——最近 100 条之外的历史当前不可达,history_ref 显式标注可达范围(reachable_max_messages:100);旧调用(不带参数)自动走摘要,调用方无需改动参数,但注意返回内容从完整消息变为摘要(需要原文时显式 include_messages=true)。
- Response Size Guard:hub 所有 MCP 响应统一 middleware,MAX_RESPONSE_BYTES=50000;超限自动 smart-truncate(保证仍是合法 JSON,挂 truncated 元数据),日志 [mcp-guard] original=.. returned=.. truncated。
- 健康监控:hub 新增 GET /metrics(请求数/平均与最大响应字节/截断与错误计数/活跃连接/perTool 明细)、GET /readyz(HA quorum 就绪)、GET /version;Dashboard 新增「MCP 控制面」页签展示。
- 纠错插队/立即干预:sessions_prompt 支持 mode=queue|steer(默认 queue 排队语义不变);steer 绕过队列经 DSH 宿主 API 注入运行中回合(结构化返回 steered/queued/rejected/unavailable),DSH 历史事件 agent/inbox/spliced 证实注入。设计评审与实施细节见 docs/priority-queue.md。
模型门禁(ChatGPT 指令须声明 gpt-5-6-thinking)
隧道/协议层不带调用方模型(实测确认),因此采用声明式门禁:ChatGPT 总导演
每次下发指令时在消息文本里声明当前模型([model-check] 当前模型是 ),
hub 路由前校验 sessions_prompt / sessions_create(initial_message):
- 声明 gpt-5-6-thinking → 放行;
- 声明 5.5-mini → 拒绝 model_rejected(附 received 原文);
- 无声明 → 拒绝 model_declaration_required。
被拒返回 MCP isError + 结构化 JSON,ChatGPT 可读原因并切模型重试。
实现见 packages/hub/src/mcp/model-gate.ts,ChatGPT 侧指令模板见 docs/model-gate.md。
Goal 守卫(ChatGPT 指令禁止在 DSH 开启 goal)
问题(2026-08-25 代码级定位):链路中 @beforewave/dsh-chatgpt-helm 插件(DSH web profile)的 DshAdapter.prompt() 把 ChatGPT 发来的消息以 source:{kind:"user"} 注入 DSH 会话——伪装成「直接人类输入」。而 DSH 的 create_goal 权威校验(dsh-tool-goal 的 requireDirectHuman)只认 source.kind === "user" 的回合事件,于是 ChatGPT 一条长任务指令就能让 DSH 开 goal;回合结束 goal 自动注入下一段(source.kind="goal")自主续跑,根本不听 ChatGPT 的指挥。
修复(patches/goal-guard.mjs v2,幂等补丁):两处——对插件 lib/index.js 三处修改,另补丁 DSH 核心 dsh-tool-goal 权威校验:
1. createSession/prompt() 的消息注入 source:{kind:"user"} → source:{kind:"user", relayedBy:"dsh-chatgpt-helm"}:消息在 DSH GUI 正常显示原文(与本人消息一致),但带转发标记;
2. prompt() 注入前:会话存在 active goal 时自动 pause(disarm 自动续跑)——存量 goal 也不会在 ChatGPT 指挥期间继续「一段结束自动注入下一段」;
3. inject 数组补充 "goals" 服务;
4. dsh-tool-goal 的 hasDirectHumanInput 增加 && relayedBy === void 0:带转发标记的消息不算「直接人类输入」,ChatGPT 指令从此无法通过 create_goal/update_goal 的人类权威校验(GOAL_TOOL_DRIVER_REQUIRED 拒绝),系统提示中「直接人类请求」的 goal 推断前提也不成立。
本机 GUI 管理 goal 不受影响(web 消息无 relayedBy 标记)。应用后需重启 DSH web 生效;DSH 升级或插件重装/升级后重跑一次即可(node patches/goal-guard.mjs,自动备份 .bak-goalguard-)。端到端验证方法见 docs/goal-guard.md。
平台支持
| 平台 | hub | node agent | presence | 服务自启 |
| macOS | ✅ 已验证 | ✅ 已验证 | ✅ 桌面 sidecar 自动 + 手动 | ✅ launchd(install-service.sh) |
| Linux | ✅ 部分支持 | ✅ 部分支持 | ✅ 手动 | ✅ systemd 模板(@dsh-helm/platform) |
| Windows | ⚠️ 需 Node ≥22.5 | ⚠️ 脚手架 | 🚧 待真机验证 | 🚧 Task Scheduler 模板 |
核心代码零平台特定逻辑(launchd/osascript/PowerShell 全部隔离在 packages/platform 与 packages/presence);macOS 双机(Tailscale)已真机验证,Linux/Windows 待真机验证。
文档
| 文档 | 内容 |
| docs/architecture.md | 架构、协议、路由决策、数据模型、工具面 |
| docs/chatgpt-tunnel-setup.md | OpenAI Platform 隧道创建与 tunnel-client 配置 |
| docs/chatgpt-connector.md | ChatGPT Web 连接器创建与使用 |
| docs/onboarding.md | 新机器加入控制平面 |
| docs/security.md | 凭据、网络边界、Tailscale ACL、威胁模型摘要 |
| docs/troubleshooting.md | 症状 → 排查 → 解决 |
| docs/threat-model.md | 完整威胁模型(15 条威胁) |
| docs/upstream-compat.md | 上游 beforewave helm 兼容基线 |
安全要点
- 凭据:~/.dsh/helm/node.json(节点 token)与 daemon token 文件均 0600;hub token 表经 DSH_HELM_TOKEN 环境注入(不落盘);token 不出现在 argv/git/日志;隧道凭据用 env: 语法注入。
- 绑定:hub 默认只绑 127.0.0.1;跨机建议 Tailscale + --bind ,--mcp-bind 127.0.0.1 保持 MCP 仅 loopback。hub MCP(3471)v1 无鉴权——严禁直接暴露公网;生产 mesh 走 wss://(TLS 由反代/外部 https server 负责)。
- fail-closed:破坏性操作(sessions_prompt/sessions_resume)无明确目标即拒绝;presence 歧义窗口内不猜测。
- 无正文存储:store 只存元数据与审计,不落 DSH 会话内容。
- 详细安全模型见 docs/security.md 与 docs/threat-model.md。
状态与事实分层
版本 v0.1.0。自动化验证全绿(单元 + 双 fake node 全协议端到端集成测试 + 信息保真验收:399/399(48 文件),build/lint 干净);macOS 双机 Tailscale 真机冒烟完成。doctor/dashboard/install 已实现;CLI 在线 RPC 命令(nodes/node/route-explain/presence/rotate-token)仍需 live hub 连接(当前提示 requires live hub connection,计划下一里程碑),同一能力可经 hub MCP 工具(nodes_list 等)使用;session handoff v1 诚实返回 unsupported。
能力状态按证据强度分层(不混淆):
| 层次 | 内容 | 证据 |
| 已实现并测试 | 五级路由 + fail-closed、HMAC 握手、presence(手动 + macOS 桌面探测)、分层健康、HA 双 CP(quorum/租约/failover + ha-proxy)、设备配对(pair/join)、MCP Context Isolation(默认摘要/Response Guard/steer 插队)、CLI 15 子命令 | 单元 + 集成测试全绿;acceptance 报告见 docs/fidelity-acceptance.md 与 docs/priority-queue.md |
| 依赖上游但已实测 | DSH 0.1.1 sessions_prompt mode=queue/steer(宿主 API 注入;agent/inbox/spliced 验证)、max_messages 生效、beforeSeq 翻页无效(协议限制) | 真实链路 smoke + 探测记录(docs/priority-queue.md §2/§5) |
| 官方未说明 / 实验性 | 同一 OpenAI tunnel 多 tunnel-client 双实例语义(容灾阶梯 2,需实测);Linux/Windows 平台支持 | OpenAI 官方文档零表述(docs/chatgpt-disaster-recovery.md);平台表见前文 |
| 已知限制与未闭环风险 | ①最近 100 条之外的历史不可达(DSH 0.1.1 beforeSeq 无效;修复路径=agent 历史归档,见 fidelity §7);②hub MCP(3471)v1 无鉴权——严禁公网暴露;③CLI 在线 RPC 命令未接通 live hub;④审计无防篡改/哈希链、token 静态明文存储(详见 threat-model §4/§5) | 验收/冒烟实测;威胁模型逐条 docs/threat-model.md |
明确不承诺:非 production-ready 保证;HA 为自管控制面冗余,无 SLA / zero-downtime 承诺;OpenAI 官方能力边界(tunnel 多实例 HA、密钥自动轮换)未获得前不承诺。验收判定为 CONDITIONAL PASS(保真与安全闭环,完备性受 DSH 0.1.1 协议边界限制)。
ops 脚本
| 脚本 | 作用 |
| scripts/install.sh | 安装 CLI(node 检查 / 构建 / 三个 wrapper),幂等 |
| scripts/uninstall.sh | 卸载(--purge 全删) |
| scripts/verify.sh | 自检(node / wrapper / node.json 0600 / 本地 daemon / hub 端口),退出码 0/1/2 |
| scripts/health.sh | 节点状态表(hub MCP 优先,本地 store 退化) |
| scripts/install-service.sh | 装 node agent 为 launchd 服务(macOS),--stop 卸载 |
| scripts/register-node.sh | hub 机注册/更新节点 token(幂等,自动重载 launchd) |
| scripts/dsh-helm-watchdog.sh | 15s 自愈 watchdog(进程级拉起,单实例锁) |
所有脚本 bash 3.2 兼容、[dsh-helm] 输出前缀、幂等、只探测不修改生产端口(3080/3457/3458)上的现有服务。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
lixiaoshuang79/dsh-helm
把单机连接器扩展成多节点统一入口,按策略路由到任意机器
相关插件 · 市场 / 管理
插件精选列表awesome-dsh-plugin/awesome-dsh-plugin
DeepSeek Harness(dsh)插件精选列表
★ 22,025未汉化DSH
73.6
新词雷达zhuyansen/new-term-radar
new-term-radar新词雷达
★ 2,049已汉化MCP
72.8
插件生态导航0xsline/awesome-deepseek-harness
安装 贡献指南 DeepSeek Docs 公开插件目录 Issues
★ 1,188已汉化DSH
72.6
技能注册中心iflytek/skillhub
企业级开源智能体技能注册中心——发布、发现并管理组织内可复用的技能包。
★ 5,358已汉化DSH
71.9
插件市场目录imsai-sh/awesome-deepseek-harness-plugins
面向 DeepSeek Harnessdsh生态的社区插件目录,共收录 13938 个插件含 PR 收录与…
★ 350已汉化DSH
71.8
插件精选清单Anil-matcha/awesome-dsh-plugin
DeepSeek Harnessdsh精选指南——DeepSeek…
★ 1,013已汉化DSH
71.7