@wosyai/asto
v0.1.2
Published
`asto` enables agents to perform structural code changes quickly and predictably, with dry-runs, auditable diffs, and structured output for automation.
Readme
asto
Large changes, fewer errors, predictable flow for agents.
asto enables agents to perform structural code changes quickly and predictably, with dry-runs, auditable diffs, and structured output for automation.
It is built for AI-agent workflows where text patches are expensive and fragile. Instead of rewriting large code blocks, the agent declares intent on AST structure and lets asto execute the edit.
Why agents use asto
- Avoid giant patch payloads and repeated code context.
- Reduce validation failures from text-based patching.
- Make large edits practical with structural operations (
move,copy,swap,replace). - Keep execution auditable with
--dry-runand deterministic behavior. - Integrate with machine-readable output (
--json,--toon).
Install (npm)
npm i -g @wosyai/asto
asto --helpPredictable behavior
astodoes not auto-format code.astodoes not add, remove, or reorder imports.- This is intentional: agents get predictable edits and explicit control.
Recommended flow:
- Apply structural edits with
asto. - Update imports explicitly when needed (for example with
asto replace). - Run formatting/linting with your project tools (for example
biome check --write .andeslint --fix).
Fast agent workflow
# 1) discover safe targets
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }'
# 2) preview edit
asto move --dry-run --path "src/**/*.ts" --from 'const $N = $V' --to 'function $F($$$ARGS) { $$$BODY }' --place 'start $$$BODY'
# 3) apply edit
asto move --path "src/**/*.ts" --from 'const $N = $V' --to 'function $F($$$ARGS) { $$$BODY }' --place 'start $$$BODY'
# 4) explicit import update if needed
asto replace --path "src/**/*.ts" --old "import { $X } from 'old-lib'" --new "import { $X } from 'new-lib'"
# 5) format/lint
biome check --write .
eslint --fixCommand overview
find: read-only match discovery.replace: replace selected ranges using capture templates.move: move selected ranges from source matches into destination matches.copy: copy selected ranges from source matches into destination matches.swap: exchange selected ranges between left and right matches.
Selector syntax (quick reference)
<base>[filter]...
base := @match | $X | $$$X
filter := index=N | slice=A:B | kind=K | has='PATTERN' | not-has='PATTERN'index:Nis 0-based (index:0is the first item).slice:A:Bis 0-based and half-open (A <= i < B).has/not-hasuse ast-grep pattern strings in single quotes.- Used by
--pick,--where,--left-pick,--right-pick, and--placetargets.
Examples:
# first statement in $$$BODY
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }' --pick '$$$BODY[index=0]'
# statements 1..2 (second and third)
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }' --pick '$$$BODY[slice=1:3]'
# only expression statements
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }' --pick '$$$BODY[kind=expression_statement]'
# nodes containing await
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }' --pick "$$$BODY[has='await $X']"
# nodes that do not contain logger(...)
asto find --path "src/**/*.ts" --what 'function $F($$$ARGS) { $$$BODY }' --pick "$$$BODY[not-has='logger($$$A)']"Place syntax
<op> <selector>
op := start | end | before | after | replaceExamples:
asto move --path "src/**/*.ts" --from 'return $X;' --to 'function $F($$$ARGS) { $$$BODY }' --place 'start $$$BODY'
asto move --path "src/**/*.ts" --from 'return $X;' --to 'function $F($$$ARGS) { $$$BODY }' --place 'before $TARGET'
asto move --path "src/**/*.ts" --from 'return $X;' --to 'function $F($$$ARGS) { $$$BODY }' --place 'replace $$$BODY[index=0]'--placealways requires operator + selector.- If selector resolves multiple nodes, each node becomes a destination target.
astosplices raw text; it does not insert separators/newlines automatically.
Output modes for agents
- Default output is short and human/agent-readable.
--jsonemits structured JSON payloads.--toonemits structured TOON payloads.--jsonand--toonare mutually exclusive.
Help and docs
- Root help:
asto --help - Command help:
asto <command> --help - Development docs/spec:
docs/
