diff --git a/.cache-home/nix/fetcher-cache-v4.sqlite b/.cache-home/nix/fetcher-cache-v4.sqlite new file mode 100644 index 0000000..518af80 Binary files /dev/null and b/.cache-home/nix/fetcher-cache-v4.sqlite differ diff --git a/README.md b/README.md index a8a7bc7..14e16f4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The repo now owns the active shell/editor/tool config directly: - `home/` contains the Home Manager modules for user-facing tools - `config/` contains the repo-owned config trees copied from your daily setup -- `modules/homebrew.nix` is intentionally narrow and should keep shrinking over time +- `modules/homebrew.nix` is intentionally narrow and should eventually disappear - Homebrew cleanup is still set to `"none"` so the first switch is non-destructive ## Layout @@ -16,7 +16,7 @@ The repo now owns the active shell/editor/tool config directly: - `modules/base.nix`: Nix settings and core packages - `modules/macos.nix`: macOS defaults and host-level settings - `modules/packages.nix`: system packages and fonts -- `modules/homebrew.nix`: the remaining Homebrew-managed apps and packages +- `modules/homebrew.nix`: the remaining Homebrew-managed GUI apps - `home/`: Home Manager modules for shell, editor, CLI tools, and app config - `config/`: repo-owned config files consumed by Home Manager @@ -42,4 +42,13 @@ just check - Launch agents that are currently outside Nix - App state under `~/Library/Application Support` - Anything that depends on local credentials, keychains, or encrypted stores -- Deciding whether the remaining Homebrew entries should stay there or be eliminated +- Replacing or intentionally dropping the remaining GUI apps still delivered via Homebrew + +## Current Homebrew Scope + +The current Homebrew boundary is only: + +- `cap` +- `raycast` +- `thebrowsercompany-dia` +- `wispr-flow` diff --git a/home/zsh.nix b/home/zsh.nix index 90228f5..3bd35be 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -57,13 +57,6 @@ '') (lib.mkOrder 1000 '' - export HOMEBREW_PREFIX="/opt/homebrew" - export HOMEBREW_CELLAR="/opt/homebrew/Cellar" - export HOMEBREW_REPOSITORY="/opt/homebrew" - export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH" - export MANPATH="/opt/homebrew/share/man''${MANPATH+:$MANPATH}:" - export INFOPATH="/opt/homebrew/share/info:''${INFOPATH:-}" - if [[ -f ~/.config/secrets/shell.zsh ]]; then source ~/.config/secrets/shell.zsh elif [[ -f ~/.secrets ]]; then @@ -71,7 +64,7 @@ fi export PATH="$HOME/.local/bin:$PATH" - export PATH="${pkgs.postgresql_16}/bin:$PATH" + export PATH="${pkgs.postgresql_17}/bin:$PATH" export PATH="$HOME/.opencode/bin:$PATH" eval "$(zoxide init zsh)" diff --git a/justfile b/justfile index 9c64db7..182b281 100644 --- a/justfile +++ b/justfile @@ -2,14 +2,16 @@ default: just --list check: - nix flake check + nix --extra-experimental-features 'nix-command flakes' flake check build: - nix build .#darwinConfigurations.hari-macbook-pro.system + nix --extra-experimental-features 'nix-command flakes' build .#darwinConfigurations.hari-macbook-pro.system switch: - nix run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake .#hari-macbook-pro + sudo env PATH="$PATH" nix --extra-experimental-features 'nix-command flakes' run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake .#hari-macbook-pro + +backup: + ./scripts/backup-machine.sh fmt: - nix fmt - + nix --extra-experimental-features 'nix-command flakes' fmt diff --git a/modules/homebrew.nix b/modules/homebrew.nix index 83718ac..9195360 100644 --- a/modules/homebrew.nix +++ b/modules/homebrew.nix @@ -8,18 +8,9 @@ cleanup = "none"; }; - taps = [ - "nicosuave/tap" - "withgraphite/tap" - ]; + taps = []; - brews = [ - "nicosuave/tap/memex" - "postgresql@17" - "python@3.13" - "withgraphite/tap/graphite" - "worktrunk" - ]; + brews = []; casks = [ "cap" diff --git a/modules/packages.nix b/modules/packages.nix index a9d156f..575f200 100644 --- a/modules/packages.nix +++ b/modules/packages.nix @@ -1,21 +1,81 @@ { inputs, + lib, pkgs, - username, ... }: let - berkeleyMono = pkgs.stdenvNoCC.mkDerivation { - pname = "berkeley-mono"; - version = "local"; - src = /. + "/Users/${username}/Library/Fonts/BerkeleyMono-Regular.otf"; - dontUnpack = true; - installPhase = '' - install -Dm644 "$src" "$out/share/fonts/opentype/BerkeleyMono-Regular.otf" - ''; - }; - gwsPackage = inputs.googleworkspace-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; + + memex = pkgs.stdenvNoCC.mkDerivation rec { + pname = "memex"; + version = "0.3.1"; + + src = pkgs.fetchurl { + url = "https://github.com/nicosuave/memex/releases/download/v${version}/memex-${version}-macos-arm64.tar.gz"; + hash = "sha256-OIqT0xS+8vc0dQNi+YdDXLmN8V/7AT4Q/cnvbbhZ+3s="; + }; + + dontUnpack = true; + + installPhase = '' + tar -xzf "$src" + install -Dm755 memex "$out/bin/memex" + ''; + + meta = { + description = "Fast local history search for Claude and Codex logs"; + homepage = "https://github.com/nicosuave/memex"; + license = lib.licenses.mit; + mainProgram = "memex"; + platforms = lib.platforms.darwin; + }; + }; + + graphite = pkgs.stdenvNoCC.mkDerivation rec { + pname = "graphite"; + version = "1.7.20"; + + src = pkgs.fetchurl { + url = "https://github.com/withgraphite/homebrew-tap/releases/download/v${version}/gt-macos-arm64"; + hash = "sha256-ho9VQw1ic3jhG3yxNwUL0W1WvNFku9zw6DQnGehs7+8="; + }; + + dontUnpack = true; + + installPhase = '' + install -Dm755 "$src" "$out/bin/gt" + ''; + + meta = { + description = "Manage stacked Git changes and submit them for review"; + homepage = "https://graphite.dev/"; + license = lib.licenses.agpl3Only; + mainProgram = "gt"; + platforms = lib.platforms.darwin; + }; + }; + + worktrunk = pkgs.rustPlatform.buildRustPackage rec { + pname = "worktrunk"; + version = "0.23.1"; + + src = pkgs.fetchurl { + url = "https://github.com/max-sixty/worktrunk/archive/refs/tags/v${version}.tar.gz"; + hash = "sha256-cdQDUz7to3JkriWE9i5iJ2RftJFZivw7CTwGxDZPAqw="; + }; + + cargoHash = "sha256-DHjwNqMiVkWqL3CuOCITvyqkdKe+GOZ2nlMSstDIcTg="; + doCheck = false; + + meta = { + description = "CLI for Git worktree management"; + homepage = "https://worktrunk.dev"; + license = with lib.licenses; [asl20 mit]; + mainProgram = "wt"; + platforms = lib.platforms.darwin; + }; + }; in { environment.systemPackages = with pkgs; [ codex @@ -24,6 +84,7 @@ in { diff-so-fancy git-filter-repo git-lfs + graphite google-cloud-sdk gwsPackage imagemagickBig @@ -31,17 +92,18 @@ in { libpq librsvg llmfit + memex mise ngrok - postgresql_16 + postgresql_17 redis tailscale terraform + worktrunk yt-dlp ]; fonts.packages = with pkgs; [ - berkeleyMono jetbrains-mono nerd-fonts.symbols-only ]; diff --git a/scripts/backup-machine.sh b/scripts/backup-machine.sh new file mode 100755 index 0000000..c19b67f --- /dev/null +++ b/scripts/backup-machine.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -euo pipefail + +umask 077 + +backup_root="${HOME}/Backups/nix-migration" +timestamp="$(date +%Y%m%d-%H%M%S)" +backup_dir="${1:-${backup_root}/${timestamp}}" + +mkdir -p "${backup_dir}/archives" "${backup_dir}/manifests" + +snapshot_log="$(tmutil localsnapshot 2>&1 || true)" +printf '%s\n' "${snapshot_log}" > "${backup_dir}/manifests/apfs-localsnapshot.log" +tmutil listlocalsnapshots / > "${backup_dir}/manifests/apfs-localsnapshots.txt" 2>&1 || true + +{ + printf 'created_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" + printf 'hostname=%s\n' "$(scutil --get HostName 2>/dev/null || hostname)" + printf 'local_host_name=%s\n' "$(scutil --get LocalHostName 2>/dev/null || true)" + printf 'computer_name=%s\n' "$(scutil --get ComputerName 2>/dev/null || true)" + printf 'repo_root=%s\n' "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +} > "${backup_dir}/manifests/backup-meta.txt" + +sw_vers > "${backup_dir}/manifests/sw_vers.txt" +uname -a > "${backup_dir}/manifests/uname.txt" +df -h / /System/Volumes/Data /nix > "${backup_dir}/manifests/disk-usage.txt" + +if command -v brew >/dev/null 2>&1; then + brew bundle dump --file=- --force --describe > "${backup_dir}/manifests/Brewfile" 2> "${backup_dir}/manifests/brew-bundle.stderr" || true + brew list --formula --versions > "${backup_dir}/manifests/brew-formulae.txt" 2> "${backup_dir}/manifests/brew-formulae.stderr" || true + brew list --cask --versions > "${backup_dir}/manifests/brew-casks.txt" 2> "${backup_dir}/manifests/brew-casks.stderr" || true + brew services list > "${backup_dir}/manifests/brew-services.txt" 2> "${backup_dir}/manifests/brew-services.stderr" || true +fi + +if command -v nix >/dev/null 2>&1; then + nix --version > "${backup_dir}/manifests/nix-version.txt" 2>&1 || true +fi + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +git -C "${repo_root}" status --short > "${backup_dir}/manifests/nix-repo-status.txt" 2>&1 || true +git -C "${repo_root}" rev-parse HEAD > "${backup_dir}/manifests/nix-repo-head.txt" 2>&1 || true + +find /Applications -maxdepth 1 -type d -name "*.app" | sort > "${backup_dir}/manifests/applications-system.txt" +find "${HOME}/Applications" -maxdepth 1 -type d -name "*.app" | sort > "${backup_dir}/manifests/applications-user.txt" 2>/dev/null || true + +{ + printf '%s\n' "${HOME}/.claude" + printf '%s\n' "${HOME}/.codex" + printf '%s\n' "${HOME}/Library/Application Support/Claude" + printf '%s\n' "${HOME}/Library/Application Support/Code" + printf '%s\n' "${HOME}/Library/Application Support/Cursor" + printf '%s\n' "${HOME}/Library/Application Support/Zed" +} > "${backup_dir}/manifests/excluded-paths.txt" + +home_paths=( + ".config" + ".ssh" + ".gnupg" + ".aws" + ".npmrc" + ".gitconfig" + ".gitignore" + ".zshenv" + ".zprofile" + ".zshrc" + ".zlogin" + ".zlogout" + ".bash_profile" + ".profile" + ".secrets" + ".claude.json" + ".claude.json.backup" + "dots" + "Documents/GitHub/nix" +) + +library_paths=( + "Library/Preferences" + "Library/Fonts" + "Library/Application Support/Codex" +) + +archive_from_home() { + local archive_name="$1" + shift + local source_root="$1" + shift + local -a requested=("$@") + local -a existing=() + + for path in "${requested[@]}"; do + if [[ -e "${source_root}/${path}" || -L "${source_root}/${path}" ]]; then + existing+=("${path}") + fi + done + + printf '%s\n' "${existing[@]}" > "${backup_dir}/manifests/${archive_name%.tar.gz}-contents.txt" + + if ((${#existing[@]} == 0)); then + return + fi + + COPYFILE_DISABLE=1 tar \ + --exclude ".ssh/agent" \ + --exclude ".ssh/controlmasters" \ + -C "${source_root}" \ + -czf "${backup_dir}/archives/${archive_name}" \ + "${existing[@]}" +} + +archive_from_home "home-config.tar.gz" "${HOME}" "${home_paths[@]}" +archive_from_home "library-config.tar.gz" "${HOME}" "${library_paths[@]}" + +( + cd "${backup_dir}" + shasum -a 256 archives/*.tar.gz > manifests/archive-checksums.txt +) + +printf 'Backup written to %s\n' "${backup_dir}"