v0.1.0 - Move, Export, Import
Summary
First public release of cc-port, the CLI that rewrites Claude Code project state when a project directory is moved, exported, or imported. Path rewriting stays inside word boundaries. Mutating commands take an exclusive flock and abort if a Claude Code session for the project is alive. Writes are atomic with rollback on failure.
Changes
Features
The CLI ships with five subcommands.
cc-port move <old> <new>rewrites every reference to the old path under~/.claude/to the new path. Default is dry-run.--applycopies, verifies, and deletes the old encoded directory.--refs-onlyupdates references in place, and--rewrite-transcriptsextends rewriting into session transcript bodies.cc-port export <project>produces a portable archive of one project. Categories include sessions, memory, history, file-history, config, todos, usage-data, plugins-data, and tasks. Use--all, individual category flags, or omit them all for an interactive picker.cc-port export manifest <project>emits the manifest XML alone for review or hand-editing. Refuses to overwrite an existing output path.cc-port import <archive> <target>applies an archive to a target path. Placeholder values come from--resolution KEY=VALUEflags or from a manifest via--from-manifest. Mixing the two sources is rejected.cc-port import manifest <archive>reads the metadata from an archive and writes a manifest XML with empty resolve attributes for hand-editing.
Beyond the subcommand surface, every mutating operation acquires an exclusive flock on ~/.claude/.cc-port.lock and aborts if any session JSON records a live PID. LocateProject cross-checks session files before rewriting, so two distinct paths that encode to the same directory (my project and my-project both map to my-project) surface as a conflict rather than splicing one project's data into another. Project paths resolve through symlinks before encoding, imports write sensitive files at 0o600, and --resolution accepts placeholder values from the command line for non-interactive runs. Interactive prompts run a TTY preflight. Piped invocations surface a clear error instead of hanging on stdin. Help output, version output, and the interactive picker render the project logo when stdout is a TTY.
Fixes
- Prefix-sharing paths no longer corrupt each other during rewrite. A project at
/work/foois left alone when porting/work/foobar. - Embedded paths inside
~/.claude.jsonproject blocks, session transcripts, session-memory files, and text file-history snapshots are all rewritten on move. - Encoded-directory collisions abort a move before any data is touched.
- A sentence-ending period no longer suppresses path rewrites in prose.
- Free-text history entries that reference the project path are included in the rewrite scope.
~/.claude.jsonkeeps its existing formatting through targetedsjsonedits rather than a full re-marshal.- Malformed
history.jsonllines surface with the offending line number. - Imports validate placeholders before any write and roll back on failure, so a broken archive can no longer leave partial state on disk.
Closeerrors from streaming pipelines and rollback paths are aggregated viaerrors.Joininstead of being dropped.- Importer staging lands on the resolved filesystem parent so a target on a different mount does not trigger
EXDEV.
Build / Release
- Homebrew cask published to the
it-bens/taptap. macOS users canbrew install it-bens/tap/cc-port. goreleaserproduces tarballs, checksums, and the cask artifact.- A top-level
Makefileexposesbuild,test,lint, andvulntargets.
CI
ci.ymlruns test, lint,govulncheck, and a build matrix on push.release.ymldrives thegoreleaserflow on tag push.
Documentation
- README covers install, every subcommand, the experimental warning, and known limitations.
docs/architecture.mdand the per-moduleREADME.mdandAGENTS.mdfiles document the cross-cutting policies, session-keyed registry, lock contract, import cap guards, and path-rewrite boundary rules.
Upgrade Notes
No breaking changes. This is the first public release.