- Home
- Plugins
- Tools & Capabilities
- dsh-tool-ast
dsh-tool-ast
hy-sde/dsh-tool-ast
The ast_grep (structural code search) and ast_edit (structural rewrite) tools for DeepSeek Harness over the packaged ast-grep native engine — a standalone plugin with no upstream harness changes required.
Install
dsh plugin --profile web add github:hy-sde/dsh-tool-astREADME
dsh-tool-ast — structural search & rewrite for DeepSeek Harness
A standalone package, installable as one plugin (two tools) for the DeepSeek Harness CLI:
| package | tools | installed by users? |
|---|---|---|
@hy-sde-org/dsh-tool-ast | ast_grep (structural code search) + ast_edit (structural rewrite, preview-first) | yes |
ast_grep and ast_edit are a full parity port of oh-my-pi's coding-agent
ast tools onto the harness tool contract (ctx.tools, ctx.fs,
ctx.subprocess, ctx.systemPrompt). The engine is the packaged
@ast-grep/cli native binary — it ships inside the npm dependency, so the
plugin works on stock DeepSeek Harness deployments with zero upstream
changes and no system ast-grep install.
The two tools
ast_grep— syntax-aware structural search. Find every function, call, class, or declaration matching a tree pattern instead of a text substring:console.log($MSG)finds every console.log call,fn($X)finds every functionfnwith one argument. Patterns bind metavariables ($NAME,$_,$$$NAME) so a search can be turned directly into a rewrite.ast_edit— structural rewrite. Replace every node matching a pattern with a template that references the captured metavariables (console.log($MSG)→log.debug($MSG)). It always PREVIEWS first (applydefaults tofalse); passapply: trueto write the files. Rewrites are 1:1 structural substitutions — never text search-and-replace.
Both share one engine, one error vocabulary (AST_*), one set of caps, and
one filesystem seam — which is why they ship in one package rather than two.
Relationship to the edit tool
For coding agents, edit (targeted, literal, line-anchored text changes) and
ast_edit (structural AST changes) are complementary, not alternatives:
edit / ast_edit in omp | edit / ast_edit in this package | |
|---|---|---|
| pairing | auto-added together when edit is requested | both tools ship in this one package |
| apply model | edit applies directly; ast_edit previews + staged resolve | ast_edit previews by default; apply: true writes |
| guidance | "For one-off text edits, prefer the Edit tool" | idiomatic: ast_edit for codemods → edit for follow-ups |
Both mutation paths write through the same ctx.fs seam (observation
watermark, version guard, sandbox policy), so they compose safely in one
session. The harness companion-preset pattern (code-edit) mounts a rich
edit beside ast_edit; this package's bundle (below) provides
read/write beside ast_grep/ast_edit, and can be pointed at the rich
@hy-sde-org/dsh-tool-edit if you want the full editor.
Install
pnpm install --global @deepseek-ai/dsh
Direct from npm (published)
# both tools arrive in one command
dsh plugin --profile web add @hy-sde-org/dsh-tool-ast
dsh plugin add reconciles the profile's bundle list from the installed
dsh.bundle.patch export, so after installation the hy-sde-ast-fs
composition below is immediately active in the named profile.
You can also just depend on the package from your own tooling:
npm install @hy-sde-org/dsh-tool-ast # or pnpm add / yarn add
From the git checkout (pre-publish / development)
git clone git@github.com:hy-sde/dsh-tool-ast.git
cd dsh-tool-ast
pnpm install
pnpm run build
AST_TGZ="$(cd packages/tool-ast && pnpm pack --silent --pack-destination /tmp)"
dsh plugin --profile web add "$AST_TGZ"
Verify
dsh web --dump-config # look for the hy-sde-ast-fs group rows
Uninstall
dsh plugin --profile web remove @hy-sde-org/dsh-tool-ast
Already shipped? If a future DeepSeek Harness release adopts structural search/rewrite itself, skip installation — adding this bundle on top would duplicate the loader row and fail at boot.
Prompt-section collisions on raw profiles: the shipped
webprofile (the GUI) disables the base host-plane tool rows, so the plugin'sread/writeregister cleanly there. On a rawdsh-baseprofile the host still mounts its owntool-fs, whosetool:readsections collide with the plugin's — boot fails with "prompt section … is already registered". Apply the same disables a web deployment has, or mount the plugin rows inside a preset realm (the harness preset pattern).
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; the subprocess seam stays on the host
plane, exactly as in the shipped presets:
hy-sde-ast-fs— acordis:groupisolated onfshy-sde-ast-fs-local—@deepseek-ai/dsh-fs-local(cwd:DSH_CWDor the harness process cwd; override by patching this row)hy-sde-ast-tool-fs—@deepseek-ai/dsh-tool-fswithenableEdit: false(read/write only — theeditname belongs to dsh-tool-edit or the host). On harness releases whosetool-fspredates theenableEditoption (thedsh-v0.1.0-rc.7tag and the published@deepseek-ai/dsh-tool-fs@0.1.0-rc.7) the key is silently ignored and the bundle also registersedit— harmless when installed standalone, fatal only if a secondedit-owner (dsh-tool-edit) lands in the same realm.hy-sde-ast-tool-ast—@hy-sde-org/dsh-tool-ast
Configure per deployment by patching the rows by id:
- id: hy-sde-ast-fs-local
config:
cwd: /path/to/workspace
- id: hy-sde-ast-tool-ast
config:
astGrepMaxMatches: 200
astEditMaxHunkBytes: 8000
timeoutMs: 45000
Pairing with the rich edit plugin
Install @hy-sde-org/dsh-tool-edit and this package's tools inside one
filesystem realm rather than both bundles standalone (each bundle owns a
tool-fs and the second would collide). Follow the harness code-edit preset
shape (hy-sde fork) or the rc.7 preset recipe in the tool-edit README: mount
both tool rows under a single isolated group, and mount the tool-edit row at
the agent plane.
Harness releases without
enableEdit(officialrc.7): the pairing dependency ontool-fs'senableEdit: falsedoes not exist there — atool-fsrow always registersedit, and a secondedit-owner collides. On such a release:
- Install this bundle standalone and keep the shipped
edit—ast_grep/ast_editcomplement the stock editor with no conflicts (verified).- For the rich editor, use the
dsh-tool-editrc.7 posture instead: its bundle disables the shippedstr_replace_editortool and mounts the richeditat the agent plane (examples/agent-preset/), where its scopededitshadows the stock global one. Mountthisplugin'shy-sde-ast-*realm rows beside that preset row if you also wantast_grep/ast_editnext to the rich editor.
Engine behavior
- Spawn. The engine is a subpath of the
@ast-grep/clipackage, resolved bycreateRequirefrom the plugin — the platform binary arrives withpnpm install, identical to how ripgrep tooling ships. - No shell layer. Every model input (pattern, rewrite, lang, strictness, globs, paths) is its own argv element — a hostile pattern stays inert.
- Strict parse.
--json=streamoutput is parsed line-by-line; a malformed line fails the run (AST_FAILED) rather than being dropped. - Exit semantics. exit 0 = matches; exit 1 + clean stderr = zero matches;
exit 1 + stderr =
AST_FIND_ERROR(bad path); exit 2 =AST_USAGE_ERROR; elseAST_FAILED. Cooperative timeout / cancellation →AST_ABORTED. - Apply is preview-first and version-guarded.
ast_editdefaults to preview;apply: truewrites only through the fs edit-intent waterfall with the observation/version guard, never a raw engine write. - Caps. All result caps are configurable (see
Config). The defaults:astGrepMaxMatches100,astGrepMaxNodeBytes2000,astEditMaxHunkBytes4000,astEditMaxFiles200,searchMetaMaxBytes65536,rawOutputMaxBytes8 MiB,graceMs3000,stderrMaxBytes64 KiB,timeoutMs30000.
Development
pnpm install
pnpm -r check # strict typecheck (tsc --noEmit)
pnpm -r test # engine unit tests + real-engine integration suite
pnpm -r build # tsc -> dist
bash scripts/release-public.sh --check # pre-publish validation
bash scripts/release-public.sh --publish # publish to npm
The test suite runs the REAL packaged ast-grep against real temp files,
exercising ast_grep, ast_edit preview and apply (observation/version
guard), sandbox denial mapping, and abort classification — no mocks of the
engine.
Layout
packages/tool-ast/ @hy-sde-org/dsh-tool-ast — the plugin (both tools)
cordis.patch.yml the installable harness bundle
src/core.ts the engine: binary resolution, spawn, argv, JSON parse,
error vocabulary
src/search.ts the ast_grep tool body
src/edit.ts the ast_edit tool body (preview / apply)