Skip to content

Implement dotfiles CLI #1

@virtualian

Description

@virtualian

Summary

Build @virtualian/dotfiles-cli — a TypeScript + Bun CLI that syncs shell and application configuration across machines using a bare git repository. Replaces the previous Bash script approach with a cross-platform npm package.

Technique origin: StreakyCobra on Hacker News (2016), popularized by Atlassian's Git tutorial

Architecture

@virtualian/dotfiles-cli
  src/
    cli.ts              ← entry point + dispatcher
    commands/
      init.ts
      sync.ts
      audit.ts
      bootstrap.ts
      add.ts
      ls.ts
      help.ts
    git.ts              ← git wrapper (--git-dir, --work-tree)
  bin/
    dotfiles            ← shim: #!/usr/bin/env bun
  package.json

Pass-through dispatcher: known subcommands are handled in src/commands/, everything else forwards to git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME. All git commands work — unknown input goes straight through.

~/.dotfiles/      ← bare git repo (history only, no working tree)
$HOME             ← working tree (where actual config files live)

Custom Commands

Command What It Does
dotfiles help Show all commands
dotfiles init Create bare repo at ~/.dotfiles with default ignore rules
dotfiles sync [message] Stage tracked changes + commit + push. Default message: sync YYYY-MM-DD
dotfiles ls List all tracked files
dotfiles audit Scan tracked files for secrets (private keys, .env, API tokens)
dotfiles bootstrap <repo-url> Full new-machine setup: clone, backup conflicts, checkout, configure
dotfiles add <path> Add file to tracking (warns on directories, shows dry-run first)

Git Pass-Through

Every git command works as you'd expect — the CLI forwards anything it doesn't recognize:

dotfiles status          # → git status
dotfiles diff            # → git diff
dotfiles log --oneline   # → git log --oneline
dotfiles stash           # → git stash
dotfiles branch -a       # → git branch -a

Technical Details

  • Language: TypeScript + Bun (not Bash — cross-platform, testable, proper error handling)
  • Runtime: Bun (~25ms startup, built-in testing via bun test)
  • Git calls: Bun.$ for shell execution (quiet mode for capturing, passthrough for interactive)
  • Ignore rules: $GIT_DIR/info/exclude (avoids polluting $HOME with .gitignore)
  • Directory add protection: dotfiles add <dir> shows dry-run preview via git add -n, requires confirmation
  • Audit: File-level patterns (.pem, .key, .env) + content-level regex (api_key=, secret:, token=, password=)

Sensitive Data Protection

Three layers:

  1. Default ignore rulesdotfiles init configures exclusions for private keys, .env files, known sensitive paths
  2. Directory warningsdotfiles add <dir> shows dry-run preview, asks for confirmation
  3. Audit commanddotfiles audit scans tracked files for secrets, returns non-zero if found

Distribution

# npm registry (primary)
bun add -g @virtualian/dotfiles-cli

# Standalone binary (no runtime needed)
bun build --compile --target=bun-darwin-arm64 src/cli.ts --outfile dotfiles-macos
bun build --compile --target=bun-linux-x64 src/cli.ts --outfile dotfiles-linux

# Direct from repo
bun install -g github:virtualian/dotfiles-cli

Acceptance Criteria

  • dotfiles help shows all custom and pass-through commands
  • dotfiles init creates bare repo at ~/.dotfiles with default ignore rules
  • dotfiles init sets status.showUntrackedFiles no
  • dotfiles sync stages tracked changes, commits, and pushes in one command
  • dotfiles sync "custom msg" uses custom commit message
  • dotfiles sync with no changes prints clean message, exits 0
  • dotfiles ls lists tracked files
  • dotfiles audit detects secret files, returns non-zero
  • dotfiles audit passes on clean repo
  • dotfiles add <dir> warns and shows dry-run before proceeding
  • dotfiles add <file> works without prompting
  • dotfiles bootstrap <url> clones, backs up conflicts, checks out, configures
  • dotfiles bootstrap with existing ~/.dotfiles fails with clear error
  • All unknown subcommands pass through to git correctly
  • dotfiles status, dotfiles log, dotfiles diff all work
  • Published to npm as @virtualian/dotfiles-cli
  • bun test passes all tests
  • No dependencies beyond Bun + git

Reference

Full design document: Plans/dotfiles-bare-repo-guide.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions