dsh-tool-edit
hy-sde/dsh-tool-edit
The rich `edit` tool for DeepSeek Harness (replace / patch / apply_patch / hashline modes) with embedded format-on-write and diagnostics — a standalone plugin with no upstream harness changes required.
安装
dsh plugin --profile web add github:hy-sde/dsh-tool-editREADME
dsh-tool-edit — the rich edit tool for DeepSeek Harness
Two standalone packages, installable as one plugin for the DeepSeek Harness CLI:
| package | role | installed by users? |
|---|---|---|
@hy-sde-org/dsh-hashline | pure line-anchored edit-patch engine (library) | no — transitive |
@hy-sde-org/dsh-tool-edit | the plugin: edit tool (replace / patch / apply_patch / hashline) + embedded format-on-write & diagnostics | yes |
The edit tool is a full parity port of oh-my-pi's coding-agent edit tool
onto the harness tool/filesystem contract (ctx.tools, ctx.fs,
ctx.systemPrompt). It reads through the filesystem before every edit,
writes through the fs/edit-intent waterfall and records fs/observed, so
the harness observation policy (when mounted) can enforce read-before-edit —
and it bundles its own LSP client, so formatOnWrite and
diagnosticsOnEdit work on stock DeepSeek Harness deployments with zero
upstream changes (the language server runs via npx typescript-language-server and degrades to edit-only when unavailable).
Why this exists. For coding agents, much of the leverage is in the
harness, not the model — the "harness problem" Stencil So frames
well: the tool surface (how a model reads, edits, and is shown errors) often
bounds reliability more than the model does. This plugin is harness work: a
better edit tool with a built-in language server, shipped as an installable
plugin. The benchmark section records the A/B run that measures
it against the harness's built-in str_replace_editor, so the "it's better"
claim is evidenced, not asserted.
Install
pnpm install --global @deepseek-ai/dsh
Direct from npm (published)
Both packages are published on the npm registry under the hy-sde-org
organization (@hy-sde-org/dsh-hashline and @hy-sde-org/dsh-tool-edit,
version 0.1.0-rc.6). Install the plugin straight from npm — the registry
resolves the hashline library dependency and the DeepSeek Harness peer
packages automatically, no tarballs, no ordering:
# one command; @hy-sde-org/dsh-hashline comes in as a transitive dependency
dsh plugin --profile web add @hy-sde-org/dsh-tool-edit
That's it. dsh plugin add reconciles the profile's bundle list from the
installed dsh.bundle.patch export, so after installation the
hy-sde-edit-fs composition (below) is immediately active in the named
profile.
You can also just depend on the packages from your own tooling as normal npm dependencies:
npm install @hy-sde-org/dsh-tool-edit # or pnpm add / yarn add
npm install @hy-sde-org/dsh-hashline # the engine, if you need it directly
Registry notes.
latestis0.1.0-rc.6; the earlier0.1.0-rc.5ofdsh-tool-editwas published with a rawworkspace:dependency spec and is deprecated on npm — never install it explicitly.
From the git checkout (pre-publish / development)
Before the registry publish (or when hacking on the repo itself), install
from the built tarballs — and pin the unpublished dependency so pnpm add
doesn't query the registry for @hy-sde-org/dsh-hashline:
git clone git@github.com:hy-sde/dsh-tool-edit.git
cd dsh-tool-edit
pnpm install
pnpm run build
HASHLINE_TGZ="$(cd packages/hashline && pnpm pack --silent --pack-destination /tmp)"
dsh plugin --profile web add "$HASHLINE_TGZ"
# Pin hashline locally so the tool-edit tarball's dependency resolves offline.
printf 'overrides:\n "@hy-sde-org/dsh-hashline": "file:%s/packages/hashline"\n' "$PWD" >> "$DSH_HOME/profiles/web/pnpm-workspace.yaml"
TOOLEDIT_TGZ="$(cd packages/tool-edit && pnpm pack --silent --pack-destination /tmp)"
dsh plugin --profile web add "$TOOLEDIT_TGZ"
(The overrides entry is a pre-publication shim; delete it once you're on
the released registry package.)
Install order note: don't try to satisfy the dependency by installing the hashline tarball "first" — pnpm re-resolves the full graph on every
addand will 404 on an unpublished@hy-sde-org/dsh-hashlineunless the override above pins it.
Verify
dsh web --dump-config # look for the hy-sde-edit-fs group rows
Uninstall
dsh plugin --profile web remove @hy-sde-org/dsh-tool-edit
dsh plugin --profile web remove @hy-sde-org/dsh-hashline
Already shipped? If a future DeepSeek Harness release adopts a rich edit tool itself, skip installation — adding this bundle on top would duplicate the loader row and fail at boot ("duplicate loader entry id").
Prompt-section collisions on raw profiles: the shipped
webprofile (the GUI) disables the base host-plane tool rows, so the plugin'sread/write/editregister cleanly there. On a rawdsh-baseprofile (e.g. some headless setups) the host still mounts its owntool-fs, whosetool:read/tool:editsystem-prompt sections collide with the plugin's — boot fails with "prompt section … is already registered". Apply the same disables a web deployment has (a user patch disabling the base tool rows), or mount the plugin rows inside a preset realm.
What the bundle does
The plugin's cordis.patch.yml is self-contained: ctx.fs is not
mounted host-wide in Harness (presets own local filesystem discovery), so the
bundle brings its own isolated fs realm with fresh row ids (hy-sde-*) that
cannot collide with shipped rows:
hy-sde-edit-fs— acordis:groupisolated onfshy-sde-fs-local—@deepseek-ai/dsh-fs-local(cwd:DSH_CWDor the harness process cwd; override by patching this row with your workspace)hy-sde-tool-fs—@deepseek-ai/dsh-tool-fswithenableEdit: falsehy-sde-tool-edit—@hy-sde-org/dsh-tool-edit(the rich editor)
Configure per deployment by patching the rows by id, e.g.:
- id: hy-sde-fs-local
config:
cwd: /path/to/workspace
- id: hy-sde-tool-edit
config:
mode: hashline # 'auto' | 'hashline' | 'replace' | 'patch' | 'apply_patch'
formatOnWrite: true
diagnosticsOnEdit: true
lspCommand: npx --yes typescript-language-server --stdio
Tool modes
The single edit tool dispatches on argument shape (or is pinned to one mode
via config.mode):
| mode | argument shape | notes |
|---|---|---|
replace | path + old_string + new_string (replace_all) | fuzzy whitespace matching by default |
patch | path + edits[] | JSON edit entries |
apply_patch | input | Codex/Aider-style patch envelope |
hashline | input | line-anchored patch language: tags the model saw (@file) + @@ blocks referencing line numbers and hashes |
LSP behavior on stock DSH
- The embedded client spawns
typescript-language-serveron first edit that writes through LSP; the server process is shared for the plugin lifetime and torn down on unmount. - With
formatOnWrite, edited files are formatted viatextDocument/formattingbefore the write lands. - With
diagnosticsOnEdit,textDocument/publishDiagnosticsare attached to the edit result as anN error(s), M warning(s)summary withline:col [severity] [source] messagelines. - Any failure (no server, spawn error, timeout) degrades to edit-only silently. Never blocks an edit.
Development
pnpm install
pnpm -r check # strict typecheck of both packages
pnpm -r test # hashline 235 tests + tool-edit 20 tests (incl. embedded LSP client)
pnpm -r build # tsc -> dist
bash scripts/release-public.sh --check # pre-publish validation
bash scripts/release-public.sh --publish # publish hashline then tool-edit
Layout
packages/hashline/ @hy-sde-org/dsh-hashline — the engine (no runtime deps)
packages/tool-edit/ @hy-sde-org/dsh-tool-edit — the plugin (embedds the LSP client)
cordis.patch.yml the installable harness bundle
src/lsp/ embedded client: stdio framing, LSP client, provider,
writethrough (port of oh-my-pi's lsp writethrough)