| name | dosido |
| description | Move, rename, extract, create barrel exports, or migrate code/package boundaries in a TypeScript/JavaScript project without breaking imports or package metadata. Use dosido instead of hand-editing files, imports, barrel exports, or package manifests whenever the user wants to move or rename a file, split a function/type/const/class out into its own file, create a directory barrel, 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), remove exports nothing uses, or analyze/extract/clean up pnpm workspace packages. Trigger this whenever the task involves relocating, renaming, extracting, or barrel-exporting TypeScript/JavaScript code, or migrating code into workspace packages — 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. It also has workspace-package
migration helpers for extracting folders into pnpm workspace packages and
maintaining export maps/manifests. 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 |
| Generate a directory barrel and rewrite external imports through it | barrel |
| Untangle two directories that import from each other via a shared directory | decouple |
| Analyze or extract folders into workspace packages; clean/audit package metadata | workspace |
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.
move and extract preserve explicit runtime import extensions such as
.js, .mjs, .cjs, and .jsx when recalculating relative imports.
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
barrel — create a directory barrel
dosido barrel <directory> [--include <glob>] [--ignore <glob>]
[--specifier-style <preserve|js|extensionless>]
Creates or updates <directory>/index.ts, adds exports needed by files outside
the directory, then rewrites those outside imports through the barrel. It skips
dynamic imports and side-effect imports with warnings. Existing one-hop
re-exports count as satisfying generated exports when they expose the same
public name.
By default, generated barrel exports preserve explicit JS-family runtime
extensions from the incoming reference. Use --specifier-style js to force
.js specifiers in generated exports, or --specifier-style extensionless to
emit extensionless specifiers.
dosido barrel src/core --dry-run --json
dosido barrel src/core --specifier-style js
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.
workspace — extract and maintain workspace packages
dosido workspace graph <source-package-dir> --folders <glob> [--json]
dosido workspace init-package <source-root> <target-package-dir> [--name <name>]
dosido workspace extract <source-folder> <target-package-dir>
--from-package <source-package-dir> --name <name> [--no-derive-exports]
dosido workspace compat-package <source-package-dir> --packages <pattern>
dosido workspace cleanup-manifest <package-dir> [--keep <name>]
dosido workspace audit <package-dir>
Use workspace for pnpm package-boundary work instead of hand-editing package
manifests, export maps, and imports.
graph analyzes candidate folders under a source package and reports which
ones can be extracted. Run it first with --json for non-trivial migrations.
init-package converts a package root into a pnpm workspace root plus one
legacy package.
extract moves one folder into a new workspace package, rewrites imports to
the new package name, adds package dependencies, and by default derives
subpath exports and matching bin entries from the source manifest. Use
--no-derive-exports when the new package should expose only ..
compat-package creates legacy wrapper files for existing export-map
subpaths after subpackages have been extracted, and adds workspace:*
dependencies on the extracted packages.
cleanup-manifest removes manifest dependency entries not referenced by
source imports. Use repeatable --keep <name> for runtime dependencies that
do not appear in static imports.
audit reports likely stale export-map targets, files entries, script path
references, and missing build/test scripts.
graph and extract classify test-only blockers separately and include
suggested dosido move commands for common "move tests/support first" cleanup.
Dynamic imports across an extraction boundary and non-entry side-effect imports
remain blockers unless they are external bare package references.
dosido workspace graph packages/legacy --folders "src/*" --dry-run --json
dosido workspace extract packages/legacy/src/core packages/core --from-package packages/legacy --name @acme/core --dry-run --json
dosido workspace compat-package packages/legacy --packages "@acme/*" --dry-run --json
dosido workspace cleanup-manifest packages/core --keep react --dry-run --json
dosido workspace audit packages/core --json
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, barrel exports, or package
metadata by hand for work dosido can do — that's the failure mode this tool
exists to avoid.