dotswap
v0.1.17
Published
Manage .env file profiles globally per project
Readme
dotswap
Manage .env file profiles globally per project.
Staying up to date
dotswap version shows the version you have installed alongside the latest
published on npm, and tells you whether an update is available:
dotswap versiondotswap update (alias upgrade) fetches the latest version and installs it.
For a global install it runs npm install --global dotswap@<latest-version> to
upgrade to the newest published release. When you're running through npx —
which always resolves the newest version on demand — it points you at
npx dotswap@latest <command> instead of installing anything. When dotswap is a
project dependency, it leaves the global install alone and tells you to update it
with your own package manager (e.g. npm install dotswap@latest):
dotswap updateShowing the active env in your shell
dotswap current prints just the active environment for the current directory —
nothing else — so you can surface it in your shell prompt. It stays quiet
(prints nothing, exits 0) outside a dotswap project, so it is safe to call on
every prompt:
dotswap current # e.g. prints "preview"; prints nothing outside a projectOh My Zsh
dotswap shell install sets everything up: it writes the plugin into your Oh My
Zsh custom plugins directory and adds dotswap to the plugins=(...) list in
~/.zshrc. Restart your shell (or source ~/.zshrc) afterward:
dotswap shell install # install the plugin and enable it in ~/.zshrc
dotswap shell uninstall # reverse both steps
dotswap shell print # print the plugin to stdout (for manual/other setups)The plugin adds a right-hand prompt segment (❖ <env>) that refreshes when you
cd between projects and immediately after dotswap switch. It only spawns
dotswap in directories that contain a .dotswap.json, so other directories
cost nothing. Options (set before Oh My Zsh loads):
DOTSWAP_CMD— override the invocation (default: globaldotswap, elsenpx --yes dotswap). Install globally (npm install --global dotswap) for the snappiest prompt — this avoids npx entirely, which is both faster and immune to npx's install prompt stalling your shell after a new version is published.DOTSWAP_PROMPT_PREFIX— text before the env name (default:"❖ ").DOTSWAP_NO_RPROMPT=1— leaveRPROMPTalone and place$(dotswap_prompt_info)in your ownPROMPT/RPROMPTinstead.
The dotswap shell commands are Oh My Zsh–specific; they detect it via $ZSH
and ~/.oh-my-zsh and refuse (without changing anything) when it is absent.
Other shells (bash, plain zsh, fish)
dotswap current is shell-agnostic, so any shell can build the same segment on
top of it. Gate on a .dotswap.json first so non-project directories stay fast:
# bash — in ~/.bashrc
_dotswap_ps1() {
[[ -r .dotswap.json ]] || return
local env
env="$(dotswap current)"
# Strip to a safe charset before interpolating: PS1 re-evaluates $(...) /
# backticks embedded in the result on every prompt render.
printf ' (%s)' "${env//[^a-zA-Z0-9._-]/}"
}
PROMPT_COMMAND='__dotswap=$(_dotswap_ps1)'
PS1='\u@\h \w${__dotswap}\$ '# plain zsh (no Oh My Zsh) — in ~/.zshrc
setopt PROMPT_SUBST
_dotswap_ps1() {
[[ -r .dotswap.json ]] || return
local env
env="$(dotswap current)"
# Strip to a safe charset before interpolating: PROMPT_SUBST re-evaluates
# $(...) / backticks embedded in the result on every prompt render.
printf ' (%s)' "${env//[^a-zA-Z0-9._-]/}"
}
PROMPT='%n@%m %~$(_dotswap_ps1)%# '# fish — in ~/.config/fish/functions/fish_prompt.fish (or your prompt function)
function dotswap_prompt
test -r .dotswap.json; or return
set -l env (dotswap current)
# Strip to a safe charset before printing — the env name is only checked
# for path separators, not terminal escape sequences.
printf ' (%s)' (string replace -ra '[^a-zA-Z0-9._-]' '' -- $env)
end
# then call `dotswap_prompt` from your fish_promptBrowsing the store
The store keeps one directory per project under ~/.dotswap. Most commands
(info, tree, list) act on the project of the current directory. To see
every project saved on the machine, use projects (alias who):
# List all stored projects with env, file, and workspace counts
dotswap projects
# Inspect one: its environments, shared files, and the workspaces using it
dotswap projects swite-app
# Reveal absolute store paths, or emit machine-readable JSON
dotswap projects --paths
dotswap projects swite-app --jsonInspecting a project summarizes its workspaces by active env and lists the
first few directories; pass --json for the complete, unabridged list.
To permanently delete a project's stored data — every environment, the shared
segment, and the workspaces map — use remove (alias purge). It prints the
blast radius and asks for confirmation (defaulting to No) before deleting:
dotswap remove old-project # prompts before purging
dotswap remove old-project --yes # skip the prompt (for scripts)Only the store under ~/.dotswap/<project> is removed; the .dotswap.json
files checked into your repos are left untouched.
Sharing envs with a teammate
dotswap export bundles a project's stored environments into a single file you
can hand to someone else; dotswap import unpacks it into their store.
Exports are encrypted by default: export generates a random secret, prints
it once, and locks the bundle with it. Send the file and the secret through
separate channels — the bundle is useless without the secret.
# Bundle every env (production excluded by default) into ./<project>.dotswap
# and print the generated secret to share separately
dotswap export
# Use your own secret instead of a generated one
dotswap export --secret "our-agreed-passphrase"
# Only a couple of envs, to a chosen path
dotswap export -o team.dotswap --env local preview
# Skip the shared segment (envs only)
dotswap export --no-shared
# Opt out of encryption (not recommended — asks for confirmation)
dotswap export --plaintext
# On the other machine (prompts for the secret, or pass it with --secret)
dotswap import team.dotswap
dotswap import team.dotswap --secret "the-secret"
dotswap switch preview
dotswap restoreThe bundle contains the stored files for the selected envs plus the .shared
segment (drop it with --no-shared) and a copy of .dotswap.json. It never
includes .workspaces.json
(your machine-specific active-env map). Import validates every path, re-applies
0600/0700 permissions, and skips files that are already identical.
Bundles written to a path inside a git repo are added to
.git/info/exclude automatically, so they never end up staged by
git add . (--stdout output is unaffected, since nothing is written to
disk).
