| name | dosido |
| description | Move, rename, or extract code in a TypeScript/JavaScript project without breaking imports. Use dosido instead of hand-editing files whenever the user wants to move or rename a file, split a function/type/const/class out into its own file, pull shared code out of two directories that import from each other, split React component files that mix components with hooks/constants/types (for HMR), or remove exports nothing uses. Trigger this whenever the task involves relocating, renaming, or extracting TypeScript/JavaScript code — even if the user just says "move this to its own file" or "rename this file" without mentioning dosido by name. Do not use it for non-JS/TS files or for renaming symbols in place (that's a plain find-and-replace, not a move). |
dosido
dosido is a CLI that performs structural refactors on a TypeScript/JavaScript
project — moving files, extracting definitions, splitting mixed files — and
rewrites every import affected by the change. Use it instead of manually
moving code and then grepping for imports to fix, which is slow and error-prone
on anything but the smallest projects.
Invoke it as npx dosido <command> ... or pnpm dlx dosido <command> ... if
it isn't already a project dependency; use the bare dosido command if it is
(check package.json devDependencies/dependencies or node_modules/.bin).
Picking a command
| The user wants to... | Command |
|---|
| Rename a file, or move one/several files into another directory | move |
| Pull a function/type/const/class/interface/enum out into its own or existing file | extract |
| See what code depends on a file or directory | incoming |
| Untangle two directories that import from each other via a shared directory | decouple |
Split a .tsx file that mixes a React component with other exports (for HMR) | unmix-react |
Delete unused export keywords nothing imports | cleanup-exports |
All commands accept these global flags:
--dry-run — compute the change set without writing any files. Use this
first whenever you're not fully sure what a command will do, then inspect
the result before re-running for real.
--json — print the full result ({ changes, messages, warnings }) as JSON
instead of human-readable lines. Prefer this when you (the agent) need to
parse the output — e.g. to check exactly which files were created/updated
before reporting back to the user.
--root <path> — project root, defaults to the current directory.
--plain — force plain (non-colored) output.
Short aliases exist: mv/m → move, ex/x → extract, react →
unmix-react, cleanup → cleanup-exports.
move — move or rename files
dosido move <source-file> <target-file>
dosido move <source-file-1> [source-file-2 ...] <target-directory>
Renames/relocates the file(s) and fixes imports in both directions: internal
imports inside the moved file are recalculated relative to its new location,
and every other file in the project that imported the old path is updated to
point at the new one. Errors if the target already exists.
dosido move src/utils.ts src/helpers/utils.ts
dosido move src/a.ts src/b.ts src/c.ts src/dest/
dosido move src/utils.ts src/shared/utils.ts --dry-run --json
extract — pull definitions into their own file
dosido extract <source-file> <name[,name...]> <target-file>
Extracts one or more named definitions (function, class, const/variable,
type, interface, enum) from source-file into target-file, creating the
target if needed or appending to it if it already exists. It automatically:
- exports the extracted definitions if they weren't already exported
- exports any un-exported local dependency that an extracted definition needs
- rewrites every file that imported those names from the source file
- adds an import back into the source file if it still uses the extracted code
- switches the target file's extension to
.tsx if the extracted code contains JSX
dosido extract src/utils.ts formatDate src/formatDate.ts
dosido extract src/utils.ts formatDate,parseDate src/dates.ts
dosido extract src/types.ts ButtonProps,CardProps src/components/types.ts --dry-run
Use this whenever the ask is "pull this function/type out into its own file"
rather than moving a whole file.
incoming — find what depends on a file or directory
dosido incoming <path> [--include <glob>] [--ignore <glob>] [--json]
Analyzes the project's imports and lists every file that imports from <path>.
If <path> is a directory, it lists files outside the directory that import
something inside it. If <path> is a file, it lists every other file that
imports that file. --include/--ignore are repeatable globs that scope which
files are scanned. Useful for scoping a decoupling effort before running
decouple, or just to answer "what would break if I moved this file/folder?"
dosido incoming src/shared --json
dosido incoming src/shared/util.ts --json
dosido incoming src/shared --include src/**/*.ts --ignore src/**/*.test.ts
decouple — untangle two directories that import from each other
dosido decouple <folder-a> <folder-b> <shared-dir> [--include <glob>] [--ignore <glob>]
[--no-extract] [--min-lines <n>] [--max-extract-defs <n>]
Analyzes imports to find every definition that both folder-a and
folder-b depend on, then plans moving or extracting each one into
shared-dir, so neither folder imports from the other anymore.
--include/--ignore are repeatable globs scoping the dependency analysis.
By default it prefers extract over a full move (falling back to move
for small files, files needing many extracted names, or non-named imports).
Each plan includes the exact dosido move/dosido extract command it would
run.
dosido decouple src/frontend src/backend src/shared/domain --dry-run
dosido decouple src/a src/b src/shared --no-extract
dosido decouple src/a src/b src/shared --include src/**/*.ts --ignore **/*.test.ts
Always run with --dry-run --json first and show the plan before applying —
this command can touch many files at once.
unmix-react — split component files for HMR
dosido unmix-react [--include <glob>] [--ignore <glob>] [--group-types]
[--group-consts] [--group-related]
Scans .tsx files for a React component mixed with other top-level exports
(hooks, constants, types, helper functions) — a common cause of broken
hot-module-reloading — and extracts the non-component exports into their own
files. --include/--ignore are repeatable globs (default include is all
src/**/*.{ts,tsx,js,jsx}). --group-types and --group-consts consolidate
all extracted types/consts per file into one *.types.ts/*.consts.ts
instead of one file per export; --group-related keeps exports that depend
on each other together. Skips files with React Router route exports
(loader, action, meta, etc).
dosido unmix-react --include src/components/**/*.tsx --group-types --dry-run
cleanup-exports — drop unused export keywords
dosido cleanup-exports [--entry <path,path,...>] [--ignore <glob,glob,...>] [--verbose] [--json]
Finds exports nothing in the project imports and removes the export
keyword (never deletes the code itself). Preserves: exports in entry-point
files (default src/index.ts,src/run.tsx — pass --entry to add more), a
default export that's the only export in its file, files with
client.tsx/server.tsx in their path, route files with route metadata, and
anything reached via a namespace import or export *.
dosido cleanup-exports --entry src/index.ts,src/run.tsx --dry-run
Workflow notes
- These commands mutate files directly (unless
--dry-run is passed) — run
with --dry-run --json first for anything touching more than one or two
files, review the changes/messages, then re-run without the flag.
- After running a mutating command for real, it's still worth spot-checking
the affected files and running the project's typecheck/build, since dosido
operates on the AST but doesn't run the type checker itself.
- Don't fall back to manually editing imports by hand for a move/extract that
dosido can do — that's the failure mode this tool exists to avoid.