diff --git a/nix/flake.nix b/nix/flake.nix index 0a4019cd..269aa783 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -737,6 +737,10 @@ homeModules = roles.macminiHeadless; specialArgs = { inherit user; + # hosts/macmini.nix and its home layer both take this; without it the whole macmini + # configuration stops evaluating, which is where it was found — nothing in CI builds + # this closure, so it went unnoticed until something needed the mini again. + nixpkgsAgents = nixpkgs-agents; claudeAcp = claude-acp.packages.${system}.default; sopsNix = sops-nix; # 母艦からのリモートビルドを受ける側。接続してくるユーザーが trusted-users に diff --git a/nix/home/darwin.nix b/nix/home/darwin.nix index 3b0cd4a9..ec7c633e 100644 --- a/nix/home/darwin.nix +++ b/nix/home/darwin.nix @@ -4,20 +4,10 @@ lib, user, nixpkgsUnstable, - nixpkgsAgents, secureEnclaveKey, ... }: let - # The rolling lineage the agent CLIs ride on (same one cli.nix uses). gemini-cli belongs here - # rather than on the pinned channel: Google refuses old clients outright — 0.42 answers - # "This client is no longer supported" and hands back no model at all — so a pinned version of - # this particular tool is a version that stops working on Google's schedule, not ours. - agentPkgs = import ../lib/unstable-pkgs.nix { - nixpkgsUnstable = nixpkgsAgents; - inherit (pkgs.stdenv.hostPlatform) system; - }; - # Bound here rather than inline in home.packages because the LaunchAgent below # needs the path too, and both must point at the same store path. mechvibes-dx = pkgs.callPackage ../pkgs/mechvibes-dx.nix { }; @@ -37,6 +27,7 @@ in ../modules/home/darwin-services.nix ../modules/home/darwin-apps.nix ../modules/home/darwin-ai-client.nix + ../modules/home/agy.nix ]; # Nothing puts an .app under ~/Applications any more: bundles come from environment.systemPackages @@ -219,18 +210,6 @@ in # mac-specific packages home.packages = with pkgs; [ bun # generate/type-check karabiner.ts config - # agy: Google's terminal agent, for agents that want a second model rather than a browser. - # Auth is the account's own OAuth, which is what the AI Pro subscription applies to; an API - # key would be separately billed and the subscription does not cover it. - # - # Not gemini-cli, which was tried first and is over: Google answers it with "this client is - # no longer supported" and hands back no model at all, whatever the version. nixpkgs marks - # the package for removal for the same reason. Antigravity is where that account went. - # - # Signing in through an automated browser is not the alternative, and was also tried: Google - # returns the sign-in flow to its first step for anything driven over CDP, whatever the - # password is. OAuth is a different road — the human consents in their own browser, once. - agentPkgs.antigravity-cli pngpaste # needed for macOS image paste in obsidian.nvim / img-clip syncthing # Syncthing CLI (the resident is the LaunchAgent in services.syncthing) xcodegen # generate .xcodeproj from project.yml (Mac-only, since meta.platforms = darwin in Linux nixpkgs) diff --git a/nix/home/macmini.nix b/nix/home/macmini.nix index b4039924..c30ff189 100644 --- a/nix/home/macmini.nix +++ b/nix/home/macmini.nix @@ -20,7 +20,10 @@ let }; in { - imports = [ ../modules/home/darwin-agent-state-sync.nix ]; + imports = [ + ../modules/home/darwin-agent-state-sync.nix + ../modules/home/agy.nix + ]; # macmini-specific layer. The base CLI/zsh/XDG set inherits home/common.nix # composed on the flake side (no sops/age keys are brought in). diff --git a/nix/modules/home/agy.nix b/nix/modules/home/agy.nix new file mode 100644 index 00000000..75707365 --- /dev/null +++ b/nix/modules/home/agy.nix @@ -0,0 +1,57 @@ +# Antigravity CLI component (ECS: profile). Google's terminal agent, `agy`. +# +# This is how a second model is reached from here. Not the browser: signing in to Gemini through +# an automated browser does not work, and was tried — Google returns the sign-in flow to its first +# step for anything driven over CDP, whatever the password is. And not gemini-cli, which was also +# tried and is over: it answers "this client is no longer supported" after authenticating, at any +# version, and nixpkgs marks it for removal for the same reason. Auth is the account's own OAuth +# (one interactive `agy` per machine), which is what the AI Pro subscription applies to. +# +# The rolling agents lineage on purpose: Google refuses old clients outright, so pinning this +# particular tool would only decide in advance the day it stops working. +{ + config, + lib, + pkgs, + nixpkgsAgents, + ... +}: +let + agentPkgs = import ../../lib/unstable-pkgs.nix { + nixpkgsUnstable = nixpkgsAgents; + inherit (pkgs.stdenv.hostPlatform) system; + }; + + # Declared keys only. Pro rather than Flash by default because this is the tool reached for a + # second opinion, where the answer matters more than what it costs; `--model` picks another per + # call (`agy models` lists them, Claude and gpt-oss included). + settings = { + model = "gemini-3.1-pro-high"; + enableTelemetry = false; + }; + + wanted = pkgs.writeText "agy-settings.json" (builtins.toJSON settings); + settingsFile = "${config.home.homeDirectory}/.gemini/antigravity-cli/settings.json"; +in +{ + home.packages = [ agentPkgs.antigravity-cli ]; + + # Merged rather than linked: agy owns this file and writes to it as it runs (every directory + # trusted lands here). A read-only store symlink would be a file it cannot update, so the keys + # declared above are merged into whatever it already has, and everything else is left alone. + home.activation.agySettings = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + $DRY_RUN_CMD ${pkgs.python3}/bin/python3 - <<'PY' + import json, pathlib + + target = pathlib.Path("${settingsFile}") + target.parent.mkdir(parents=True, exist_ok=True) + try: + current = json.loads(target.read_text()) + except (FileNotFoundError, json.JSONDecodeError): + current = {} + merged = {**current, **json.loads(pathlib.Path("${wanted}").read_text())} + if merged != current: + target.write_text(json.dumps(merged, indent=2) + "\n") + PY + ''; +}