跳过主要内容
V

dsh-task-dispatch

vinson1101/dsh-task-dispatch

按工作空间或会话 id 给真实的 DSH 会话派发任务;结果写入持久任务台账,查询时不会触发模型。它在 127.0.0.1:7391 提供 HTTP 接口,首次运行自动生成令牌并要求 Bearer 认证(存放在 ~/.dsh/relay/token),拒绝非回环 Host 与外部 Origin;任务结果以 JSON 文件存在 ~/.dsh/relay/tasks,可选的 notifyUrl 会收到每个完成任务的结果。

安装

dsh plugin --profile web add github:vinson1101/dsh-task-dispatch

README

dsh-task-dispatch

Deliver a message to a real DSH session by session id, and optionally wait for its reply.

It removes the human copy-paste relay between two agents: Codex, a script, or CI only needs HTTP to hand a task to a running DSH session and read the answer back.

Zero dependencies. It declares no @deepseek-ai/* or third-party packages — only Node built-ins plus the host's existing sessionController / agents / sessions services.


Why not the existing bridge

hermes-dsh-bridge is broader, but as of 0.11.4 every @deepseek-ai/* dependency is pinned to ^0.1.2-rc.1. On DSH 0.2.x that installs a second copy of the same packages, the host loads the wrong version (observed: boot failure that also reset the profile's patch layer), and the plugin never runs.

This plugin deliberately declares no host packages, so that class of conflict cannot happen. The trade-off: it only sends and waits — no file tools, approval bridge, or preset management.

Use from Codex (MCP)

The plugin only speaks HTTP. To expose it as Codex tools, use the bundled mcp/ adapter:

codex mcp add dsh -- node /absolute/path/dsh-task-dispatch/mcp/index.mjs
codex mcp list

After upgrading the plugin, update and restart the MCP adapter too (Codex spawns it per new session). The adapter must read the same $DSH_HOME/relay/token; older adapters do not send a token and will get 401.

Codex then gets dsh_send / dsh_ask / dsh_result / dsh_wait / dsh_tasks / dsh_sessions / dsh_workspaces.

Install

Not published to npm yet. Install from GitHub:

# Option 1: the packed artifact from a release (recommended; always the latest stable)
dsh plugin --profile desktop add https://github.com/vinson1101/dsh-task-dispatch/releases/latest/download/dsh-task-dispatch.tgz

# Pin a specific version instead with the versioned asset name
# dsh plugin --profile desktop add https://github.com/vinson1101/dsh-task-dispatch/releases/download/v0.6.2/dsh-task-dispatch-0.6.2.tgz

# Option 2: straight from git (pulls mcp/ and test/ too)
dsh plugin --profile desktop add github:vinson1101/dsh-task-dispatch

# Option 3: a local directory (development; symlinked, edits apply immediately)
dsh plugin --profile desktop add /absolute/path/dsh-task-dispatch

Restart DSH afterwards; the log shows:

[dsh-task-dispatch] ready http://127.0.0.1:7391

30-second check

curl -s http://127.0.0.1:7391/health
# {"ok":true,"name":"dsh-task-dispatch","version":"0.6.2",...}

curl -s -X POST http://127.0.0.1:7391/send \
  -H 'content-type: application/json' \
  -d '{"workspace":"/your/project","text":"reply with the single word: ok"}'

curl -s http://127.0.0.1:7391/tasks/<taskId-from-the-previous-call>

Configuration

FieldDefaultMeaning
host127.0.0.1Loopback only; any other value fails activation
port7391Listen port
tokengeneratedCreated on first start at $DSH_HOME/relay/token (mode 600); an explicit value takes precedence. See Security

API

MethodPathPurpose
GET/healthLiveness probe, no token
GET/sessionsList live sessions (id / cwd / title / running)
POST/sendDeliver a message, return immediately (202)
POST/askDeliver, wait for the turn, return assistant text

POST /send

{ "sessionId": "session-23af063e-...", "text": "run the tests", "mode": "steer" }
  • sessionId required; cold sessions are resumed automatically
  • mode optional, steer interrupts instead of queueing
  • Returns { ok, sessionId, requestId, afterSeq }

POST /ask

{ "sessionId": "session-23af063e-...", "text": "done yet?", "timeoutMs": 120000 }
  • Same as /send plus waiting; returns { ok, reason, text, truncated }
  • reason: idle / input-required / timeout
  • text is extracted from this turn's assistant/message events
  • timeoutMs defaults to 120000

Use from Codex

curl -s -X POST http://127.0.0.1:7391/send \
  -H 'content-type: application/json' \
  -d '{"sessionId":"session-23af063e-...","text":"check the task status"}'

Wrap that curl in an MCP server if you want Codex to call it as a tool.

Security

Authentication is required by default. On first start the plugin generates a 32-byte token, writes it to $DSH_HOME/relay/token (mode 600) and reuses it across restarts. Every endpoint except /health needs it:

curl -H "Authorization: Bearer $(cat ~/.dsh/relay/token)" http://127.0.0.1:7391/tasks

Request validation, enforced in code:

CheckBehaviourBlocks
Host must be 127.0.0.1 / localhost / [::1]else 403DNS rebinding
A present Origin must be localelse 403malicious web pages
POST must use content-type: application/jsonelse 415simple-form CSRF
  • Binds loopback only; a non-loopback host throws at activation
  • Disabling auth requires an explicit allowAnonymous: true (logs a warning) and is not recommended
  • It drives a real agent, i.e. local shell-level access — do not expose the port to a LAN

Limitations

  • /sessions lists live sessions only; a cold session still accepts /send if you know its id
  • /ask waits for one turn; for long work use /send plus polling, or raise timeoutMs
  • No streaming; only the turn's final text is returned

License

MIT

相关插件