dushaobindoudou / dsh-acp

已收录

Agent Client Protocol (ACP) server plugin for the DeepSeek Harness (dsh) - drive dsh agents from Zed and any ACP v1 client

main其他 查看源代码

安装

npx -y @deepseek-ai/dsh plugin --profile web add github:dushaobindoudou/dsh-acp

此安装命令根据 GitHub 仓库地址生成,是未经验证的安装起点。

README

维护者编写的文档快照。

在 GitHub 查看 ↗
提交版本 25331b6同步于 2026年8月17日

dsh-acp

npm CI License: MIT

Agent Client Protocol (ACP) server for the DeepSeek Harness (dsh).

Drive a full dsh coding agent - streaming output, tool calls, permission prompts, durable sessions - from Zed, JetBrains, or any ACP v1 client, exactly like opencode or Gemini CLI.

English | 中文

What it does

dsh-acp is a dsh profile bundle: booting dsh --profile acp starts the entire DeepSeek Harness (agent loop, tools, sandbox, session persistence) with an ACP v1 JSON-RPC server on stdio instead of the web UI.

M1 (current release) implements:

ACP methodStatus
initialize✅ capabilities + agent info
session/new✅ creates a durable dsh agent (persisted under $DSH_HOME/sessions)
session/prompt✅ streaming agent_message_chunk / agent_thought_chunk (reasoning), plan updates, {stopReason}
tool calls✅ full lifecycle: tool_call (pending, with title/kind/locations/rawInput) → in_progresscompleted/failed with content
session/request_permission✅ dsh's approval seam bridged to the client (allow once/always, reject once/always)
session/cancel✅ aborts the turn, prompt resolves cancelled
session/close✅ cancels, flushes, disposes the agent

Roadmap: session/load replay, session/resume/list, modes (plan mode) + config options (model), slash commands, images, elicitation - see the design doc.

Install

Requires Node.js ≥ 22, pnpm, and the dsh CLI (npm i -g @deepseek-ai/dsh).

Install the bundle into an acp profile with the official plugin command (it initializes the profile, installs the package, and keeps dsh.profile.bundles in sync - see the harness docs, 打包与安装插件):

# prebuilt from npm (recommended — no build authorization needed)
dsh plugin --profile acp add dsh-acp-server

# or from a tarball
dsh plugin --profile acp add ./dsh-acp-server-0.1.0.tgz

# or from GitHub (source install; see note below)
dsh plugin --profile acp add github:dushaobindoudou/dsh-acp

# boots the ACP server on stdio
dsh --profile acp

node bin/setup-profile.mjs --pkg <spec> is a thin convenience wrapper over the same command.

GitHub installs pull source, not build output. The package's prepare script builds lib/ on install; pnpm ≥ 10 refuses to run it until you add the key it prints to the profile's pnpm-workspace.yaml:

allowBuilds:
  dsh-acp: true

then re-run the add. Prefer locking a commit (github:…/dsh-acp#<sha>), or avoid the authorization entirely with a prebuilt npm package or tarball. Verify any time with dsh --profile acp --dump-config (a # == dsh-acp layer should appear).

The two final forms

dsh-acp-server                    # 1) standalone: ACP on stdio (editors) or `serve` for remote
dsh web                           # 2) together: the GUI and ACP on one port
  1. dsh-acp-server (after npm i -g dsh-acp-server, or via npx) boots dsh --profile acp with the current stdio; every launcher flag passes through (serve --port 7800, --patch extra.yml). First use in a DSH home bootstraps the acp profile with the official dsh plugin command - bootstrap output goes to stderr, so an editor's stdout only ever sees ACP frames.
  2. dsh web - install once into the web profile (below) and every web boot serves the GUI and /acp on one port.

Why a bin instead of the literal dsh acp-server: the dsh launcher hardcodes its app subcommands (web, plugin) and parses argv before any plugin loads, so a bundle cannot register one; the wrapper is the same single-command shape.

Share one port with the Web GUI (dsh web + ACP)

Install into the web profile once, and every plain dsh web boot serves the GUI and ACP in one process on one port:

node bin/setup-webacp.mjs        # official `dsh plugin --profile web add` + the web-mounted row
dsh web                          # http://127.0.0.1:3080 = GUI, /acp = ACP
node bin/acp-chat.mjs --url http://127.0.0.1:3080

Prefer to keep web untouched? node bin/setup-webacp.mjs --clone webacp gives the same on dsh --profile webacp.

The script writes a row-level inject: [agents, agentDefaultModel, webServer] so Cordis starts the acp-server fiber only after the shared webServer service exists - the stdio transport can never race a web boot. A hand install without that row is safe too: the plugin detects a web composition late via service provisioning (terminal boots skip stdio entirely; daemon boots get an EOF grace window before exiting). Set a token in the acp-server config to require bearer auth.

Remote access (serve, like opencode serve)

Editors get ACP over stdio, but you can also run a long-lived HTTP+SSE endpoint - for remote machines, shared agents, or curl - following the shape of the ACP streamable-HTTP RFD (POST sends client->server messages, a long-lived SSE GET stream carries all server->client messages, Acp-Connection-Id binds them):

dsh --profile acp serve --port 7800            # bind 127.0.0.1 by default
dsh --profile acp serve --host 0.0.0.0 --port 7800 --token s3cret
EndpointPurpose
POST /acpone JSON-RPC message per body; initialize -> 200 + Acp-Connection-Id; everything else -> 202 (response arrives on SSE)
GET /acp/streamSSE stream for the connection (header or ?connection=)
DELETE /acpclose the connection
GET /healthzliveness (no auth)

Several clients can be attached to one dsh process (one SDK connection each). Connect from anywhere with the bundled client:

node bin/acp-chat.mjs --url http://127.0.0.1:7800 --token s3cret

Without serve the profile still boots stdio-first, so Zed keeps working unchanged. Default bind is loopback; use --token whenever you bind beyond it.

Try it without an editor

acp-chat is a zero-install interactive terminal client bundled in this repo (REPL with streaming, tool-call display, plan rendering, and inline permission prompts):

node bin/acp-chat.mjs            # spawns `dsh --profile acp` and drops you into a chat

Third-party ACP clients that work today:

ClientTypeTry it
Zededitor (reference client)agent_servers custom entry below
acpxCLInpx acpx@latest --agent 'dsh --profile acp' "hello"
ghost.nvim / acpear.nvimNeovimplugin config → command dsh-acp
acp.elEmacs(setq acp-agent-command '("dsh" "--profile" "acp"))
obsidian-agent-clientObsidianplugin settings
ACP-inspectorconformance/debugvalidates wire traffic

Configuration

All knobs have schema defaults, so the shipped bundle row carries no config; override only the keys you want in your own profile layer ($DSH_HOME/profiles/acp/cordis.patch.yml):

- id: acp-server
  config:
    agentName: my-dsh            # initialize.agentInfo.name shown to clients
    provider: deepseek           # pin the model for ACP sessions
    model: reasoner              # (provider and model must be set together)
    offerAlwaysPermissions: false # hide allow_always/reject_always (M1 maps
                                  # "always" grants to one-shot decisions)
    flushOnTurnEnd: true         # flush session persistence after each turn

Behavior follows the harness config conventions: the schema validates at plugin load (wrong types or a half-set provider/model pin fail loudly with the exact key), missing keys fall back to defaults (a patch layer replaces the whole config value, the schema refills the rest), and unset provider/model follows the profile's agent-default-model. Config is read when the process boots - editors spawn one per session.

Use with Zed

Zed → Settings → agent_servers:

{
  "dsh": {
    "type": "custom",
    "command": "dsh-acp-server",
    "args": []
  }
}

The npm package is dsh-acp-server (the plain dsh-acp name on npm belongs to another project); its dsh-acp-server bin is a thin launcher for dsh --profile acp. Point DSH_BIN at a non-PATH dsh. Model credentials come from the usual dsh places ($DSH_HOME settings / DEEPSEEK_API_KEY), shared with the web UI - no second setup.

Development

pnpm install
pnpm run build     # tsc -> lib/
pnpm test          # unit tests (pure translation layer)

# end-to-end: boots the REAL dsh --profile acp in a throwaway $DSH_HOME
# with a deterministic mock LLM, and asserts the full M1 wire behavior
node test/e2e/e2e.test.mjs

The e2e harness is also the fastest way to iterate on protocol behavior: it drives initialize → new → prompt (text) → prompt (tool call) → close over real stdio.

How it maps

ACP client (Zed) ⇄ NDJSON JSON-RPC ⇄ dsh-acp plugin ⇄ dsh services
                                          ├─ ctx.agents.create/resume   (session/new, load)
                                          ├─ agent.followup/cancel      (session/prompt, cancel)
                                          ├─ 'session/event'            (streaming session/update)
                                          ├─ 'approval/request'         (session/request_permission)
                                          └─ dsh-base: tools, sandbox, persistence, settings

Full research behind every mapping: research/ - ACP protocol, DSH architecture, prior art, design blueprint.

Contributing

PRs welcome - see CONTRIBUTING.md. Milestone plan lives in research/acp-dsh-design.md §4.

License

MIT

项目文件与信号

以下项目是目录快照中检测到的公开仓库信号。

测试已检测
贡献指南已检测

仓库信息

开发语言
JavaScript
许可证
MIT
最后更新
2026年8月17日 09:01

谨慎安装

请检查源代码、权限、生命周期脚本、依赖与网络访问;不受信任的插件应先在隔离环境中测试。