diff --git a/flake.lock b/flake.lock index a29f04540..f51a27a5c 100644 --- a/flake.lock +++ b/flake.lock @@ -92,11 +92,11 @@ ] }, "locked": { - "lastModified": 1766843567, - "narHash": "sha256-062oL6KZCH7ePf4BBG61OdFJUh5ovw6zTpd/lVwy/xk=", + "lastModified": 1766676776, + "narHash": "sha256-2bmlDZ7eFr1gO4lMKE9aw1RRUoR+9MDMAHbuVugIoi4=", "owner": "cachix", "repo": "devenv", - "rev": "d0f2c8545f09e5aba9d321079a284b550371879d", + "rev": "85b34019389c192e10e3508745c15b98060216f5", "type": "github" }, "original": { @@ -257,11 +257,11 @@ ] }, "locked": { - "lastModified": 1766881808, - "narHash": "sha256-JR7A2xS3EBPWFeONzhqez5vp7nKEsp7eLj2Ks210Srk=", + "lastModified": 1766682973, + "narHash": "sha256-GKO35onS711ThCxwWcfuvbIBKXwriahGqs+WZuJ3v9E=", "owner": "nix-community", "repo": "home-manager", - "rev": "d2e0458d6531885600b346e161c38790dc356fa8", + "rev": "91cdb0e2d574c64fae80d221f4bf09d5592e9ec2", "type": "github" }, "original": { @@ -294,11 +294,11 @@ ] }, "locked": { - "lastModified": 1766880341, - "narHash": "sha256-yYh/TNwR9GsJUT8d73nsK39lZ/j240jDwNr6807lx60=", + "lastModified": 1766793883, + "narHash": "sha256-k5pLDiwKWQfsSSwKs6UbIWiKWZo6xKNsTNPnuzHPeNo=", "owner": "nix-community", "repo": "neovim-nightly-overlay", - "rev": "7e6bb31ced1de2c6360122173f63c44113223622", + "rev": "6c63748c49be61297332a11c984973194638d4fb", "type": "github" }, "original": { @@ -310,11 +310,11 @@ "neovim-src": { "flake": false, "locked": { - "lastModified": 1766877615, - "narHash": "sha256-iojFwrzLMqEaOLkXVjIVLWFW5DU1Vhh40Xndx3fR/Xs=", + "lastModified": 1766742707, + "narHash": "sha256-vWRPyUDlSiFucT3dwRuYm8AdZ75kzvQg+ymsiLapMwk=", "owner": "neovim", "repo": "neovim", - "rev": "ab5a92bff67d654c543d89b4803a64b2e648253a", + "rev": "899ec829be85b52202f0ce32c455ae4f4d60b85b", "type": "github" }, "original": { @@ -405,11 +405,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1766840161, - "narHash": "sha256-Ss/LHpJJsng8vz1Pe33RSGIWUOcqM1fjrehjUkdrWio=", + "lastModified": 1766747458, + "narHash": "sha256-m63jjuo/ygo8ztkCziYh5OOIbTSXUDkKbqw3Vuqu4a4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3edc4a30ed3903fdf6f90c837f961fa6b49582d1", + "rev": "c633f572eded8c4f3c75b8010129854ed404a6ce", "type": "github" }, "original": { @@ -442,11 +442,11 @@ ] }, "locked": { - "lastModified": 1766886304, - "narHash": "sha256-+I9MvwsgeYCueF1a4BoZ4UwGDJyaEaVi5UgEBCYl8zE=", + "lastModified": 1766832543, + "narHash": "sha256-997o+QF5S4+5EpEmn1dYBQtnJd2ZeM85NtGMtjZec+A=", "owner": "nix-community", "repo": "NUR", - "rev": "7c3ffbcc59a9f6d980565a8160340ee63c587b15", + "rev": "e4faf24297c2d89705d150336f5dccd2ad2c8afe", "type": "github" }, "original": { diff --git a/home-manager/services/cliproxyapi/default.nix b/home-manager/services/cliproxyapi/default.nix index 810e276ac..25dceb2a4 100644 --- a/home-manager/services/cliproxyapi/default.nix +++ b/home-manager/services/cliproxyapi/default.nix @@ -11,6 +11,12 @@ let rsync = "${pkgs.rsync}/bin/rsync"; }; + # Wrapper script that runs start.sh with docker group permissions + # Note: sg is from shadow package, available as system binary /usr/bin/sg + dockerStartScript = pkgs.writeShellScript "cliproxyapi-docker-start" '' + exec /usr/bin/sg docker -c "${pkgs.bash}/bin/bash ${startScript}" + ''; + # Create backup scripts with paths substituted at build time backupAuthScript = pkgs.replaceVars ./scripts/backup-auth.sh { aws = "${pkgs.awscli2}/bin/aws"; @@ -50,7 +56,11 @@ in systemd.user.services.cliproxyapi = lib.mkIf pkgs.stdenv.isLinux { Unit = { Description = "CLI Proxy API server"; - After = [ "network.target" ]; + After = [ + "network.target" + "docker.service" + ]; + Wants = [ "docker.service" ]; }; Service = { Type = "simple"; @@ -60,9 +70,10 @@ in pkgs.bash pkgs.coreutils pkgs.awscli2 + pkgs.docker ] }"; - ExecStart = "${pkgs.bash}/bin/bash ${startScript}"; + ExecStart = "${dockerStartScript}"; Restart = "always"; RestartSec = 3; }; diff --git a/home-manager/services/cliproxyapi/scripts/start.sh b/home-manager/services/cliproxyapi/scripts/start.sh index bf24995e3..cf3931156 100755 --- a/home-manager/services/cliproxyapi/scripts/start.sh +++ b/home-manager/services/cliproxyapi/scripts/start.sh @@ -95,12 +95,33 @@ fi # Change to config dir so logs are created there cd "$CONFIG_DIR" -# Find and exec cliproxyapi with config file +# On Linux, prefer Docker for easy upgrades +if [ "$(uname)" = "Linux" ] && command -v docker >/dev/null 2>&1; then + # Stop any existing container + docker rm -f cliproxyapi 2>/dev/null || true + + # Create logs directory if it doesn't exist + mkdir -p "$CONFIG_DIR/logs" + + exec docker run --rm \ + --name cliproxyapi \ + --network host \ + --ulimit nofile=65536:65536 \ + -v "$CONFIG:/CLIProxyAPI/config.yaml:ro" \ + -v "$CONFIG_DIR:/root/.cli-proxy-api" \ + -v "$CONFIG_DIR/logs:/CLIProxyAPI/logs" \ + -e MANAGEMENT_PASSWORD="${MANAGEMENT_PASSWORD:-}" \ + eceasy/cli-proxy-api:latest +fi + +# macOS: use Homebrew binary if [ -x /opt/homebrew/bin/cliproxyapi ]; then exec /opt/homebrew/bin/cliproxyapi -config "$CONFIG" "$@" elif [ -x /usr/local/bin/cliproxyapi ]; then exec /usr/local/bin/cliproxyapi -config "$CONFIG" "$@" else - echo 'cliproxyapi binary not found; install it with "brew install cliproxyapi"' >&2 + echo 'cliproxyapi not found' >&2 + echo 'Linux: Docker should be available' >&2 + echo 'macOS: brew install cliproxyapi' >&2 exit 1 fi diff --git a/home-manager/services/default.nix b/home-manager/services/default.nix index 1f10d31e0..f031e4e4b 100644 --- a/home-manager/services/default.nix +++ b/home-manager/services/default.nix @@ -8,6 +8,7 @@ let brewUpgrader = import ./brew-upgrader { inherit pkgs; }; cliproxyapi = import ./cliproxyapi { inherit pkgs; }; codeSyncer = import ./code-syncer { inherit pkgs; }; + docker = import ./docker { inherit lib pkgs; }; dotfilesUpdater = import ./dotfiles-updater { inherit pkgs; }; neversslKeepalive = import ./neverssl-keepalive { inherit pkgs; }; ollama = import ./ollama { inherit pkgs; }; @@ -19,6 +20,7 @@ in brewUpgrader cliproxyapi codeSyncer + docker dotfilesUpdater neversslKeepalive ollama diff --git a/home-manager/services/docker/default.nix b/home-manager/services/docker/default.nix new file mode 100644 index 000000000..f563a6557 --- /dev/null +++ b/home-manager/services/docker/default.nix @@ -0,0 +1,64 @@ +{ pkgs, lib, ... }: +let + # Systemd service file for Docker daemon + dockerServiceFile = pkgs.writeText "docker.service" '' + [Unit] + Description=Docker Application Container Engine + Documentation=https://docs.docker.com + After=network-online.target + Wants=network-online.target + + [Service] + Type=notify + ExecStart=${pkgs.docker}/bin/dockerd + ExecReload=${pkgs.coreutils}/bin/kill -s HUP $MAINPID + Restart=always + RestartSec=10s + + [Install] + WantedBy=multi-user.target + ''; + + # Script to ensure user is in docker group and system docker is running + setupDockerScript = pkgs.writeShellScript "setup-docker" '' + set -euo pipefail + + # Define paths + GROUPS=${pkgs.shadow}/bin/groups + GREP=${pkgs.gnugrep}/bin/grep + USERMOD=${pkgs.shadow}/bin/usermod + SYSTEMCTL=${pkgs.systemd}/bin/systemctl + TEE=${pkgs.coreutils}/bin/tee + DOCKER_SERVICE_FILE=${dockerServiceFile} + + # Check if docker group exists and user is in it + if ! $GROUPS | $GREP -q docker; then + echo "Adding user to docker group..." + sudo $USERMOD -aG docker $USER + echo "✅ Added to docker group. Please log out and back in, or run: newgrp docker" + fi + + # Check if system docker service exists and is running + if ! $SYSTEMCTL is-active --quiet docker 2>/dev/null; then + echo "Starting Docker daemon..." + if [ ! -f /etc/systemd/system/docker.service ]; then + echo "Installing Docker systemd service..." + sudo $TEE /etc/systemd/system/docker.service > /dev/null < "$DOCKER_SERVICE_FILE" + sudo $SYSTEMCTL daemon-reload + sudo $SYSTEMCTL enable docker + fi + sudo $SYSTEMCTL start docker + echo "✅ Docker daemon started" + else + echo "✅ Docker daemon is already running" + fi + ''; +in +{ + # Provide setup script for system Docker + home.packages = lib.mkIf pkgs.stdenv.isLinux [ + (pkgs.writeShellScriptBin "docker-setup" '' + exec ${setupDockerScript} + '') + ]; +} diff --git a/spec/cliproxyapi_spec.sh b/spec/cliproxyapi_spec.sh index 09f6c1d09..a1e7baecb 100644 --- a/spec/cliproxyapi_spec.sh +++ b/spec/cliproxyapi_spec.sh @@ -90,8 +90,8 @@ The output should include '/usr/local/bin/cliproxyapi' End It 'shows error message when binary not found' -When run bash -c "grep 'cliproxyapi binary not found' '$SCRIPT'" -The output should include 'cliproxyapi binary not found' +When run bash -c "grep 'cliproxyapi not found' '$SCRIPT'" +The output should include 'cliproxyapi not found' End It 'suggests installation command in error message'