@backrunner/project-migrator
v0.1.0
Published
CLI for migrating project directories to another location while keeping a symlink at the original path, with optional watch mode and Codex history migration integration.
Maintainers
Readme
project-migrator
project-migrate moves a project directory to a new location and leaves a
symlink at the original path, so tools that still reference the old path keep
working. It can also watch a folder non-recursively and migrate new project
directories as they appear.
When available, it can call
codex-migrator so Codex
conversation history follows the move. If codex-migrate is not available or
does not support the required non-interactive mode, the Codex step is skipped
silently.
Install
npm install -g @backrunner/project-migratorOr run without a global install:
npx @backrunner/project-migrator ./old/project ../archive/projectUsage
Basic flow:
project-migrate ./serlink ../Work/serlink --dry-run
project-migrate ./serlink ../Work/serlinkWithout --dry-run or --yes, the CLI prints the migration plan and asks for
confirmation before moving anything. If the target does not exist, the prompt
confirms that the target should be created by moving the source directory there.
Migrate one project
project-migrate ~/Projects/serlink ~/Work/serlinkThis moves ~/Projects/serlink to ~/Work/serlink and creates a symlink at
~/Projects/serlink pointing to the new location.
Arguments:
<src>— existing project directory to move. It must be a real directory, not a symlink.<target>— destination path for the moved project directory.
<src> and <target> may be relative paths, absolute paths, or ~-based
paths. Relative paths are resolved from the directory where you run
project-migrate.
Options:
--force— replace an existing target directory or symlink.--no-codex— skip thecodex-migratehistory step.-y, --yes— confirm theproject-migrateprompts and pass--yestocodex-migratefor non-interactive operation.--dry-run— print what would happen and write nothing.--codex-project-name <name>— override the project name passed tocodex-migrate project <name> <target>. Defaults to the source basename.
Watch mode
project-migrate watch ~/Projects ~/Work --yesWatches ~/Projects non-recursively. When a new directory appears, it is
moved under ~/Work and a symlink is left at the original path. Existing
directories at start time are migrated once. Press Ctrl+C to stop.
Arguments:
<watch-dir>— existing directory to watch. Only direct children are handled.<target-parent>— parent directory that migrated projects are moved under.
Options:
--force— replace existing targets when auto-migrating.--no-codex— skip thecodex-migratehistory step.-y, --yes— confirm watcher prompts and pass--yestocodex-migrate.--dry-run— report what would happen and write nothing.--codex-project-name <name>— override the Codex project name. In watch mode the detected directory basename is used by default.
If <target-parent> does not exist, watch mode asks whether to create it unless
--yes is passed. Without --yes, each detected directory is also confirmed
before it is moved.
Codex integration
When codex-migrate is on PATH, supports project --help, supports --yes,
and --no-codex is not set, a confirmed migrate or watch step can also run:
codex-migrate project <basename> <target> --from-dir <source> --yesThis rewrites cwd and workspace_roots in Codex history so sessions follow
the move. If codex-migrate is missing or lacks non-interactive support, the
Codex step is skipped silently rather than failing the project migration.
For normal non-dry-run migrations, pass --yes when you want Codex history to
be migrated. Without --yes, project-migrate will not spawn an interactive
codex-migrate process.
Behavior notes
- The source must be a real directory, not a symlink.
- The target must not be the same as the source or inside the source.
- Without
--force, an existing target is an error. - Without
--yes, non-dry-run migrations ask for confirmation before moving. - If the target parent does not exist, it is created only after confirmation
(or automatically with
--yes). - Cross-device moves (for example
/Usersto/Volumes/...) automatically fall back to copy-then-remove when the platform refuses a direct rename. --dry-runnever writes to disk.- On Windows, directory junctions are used for the symlink when native symlinks aren't available.
- Watch mode uses
chokidarwithdepth: 0, so only direct children of the watched directory are migrated — nested new directories are ignored. - A short
awaitWriteFinishwindow (200ms) avoids racing with copy operations that are still writing files into the new directory.
Development
pnpm install
pnpm build # rollup -> bin/cli.mjs + bin/cli.cjs
pnpm typecheck # tsc --noEmit
pnpm lintSmoke test the build:
./bin/cli.mjs --help
./bin/cli.mjs watch --helpLicense
MIT. See LICENSE.
