be755c08c166
fix code-review HIGH: home commands are local-only, bump v3.1.2 — home detection (binary, ~/.config/home-manager, $HOME/$USER flake ref) all read the LOCAL host while exec routes over SSH for a remote machine, so 'nina home --on <remote>' would decide mode/flake-ref from the wrong box. Now home() refuses a non-local machine with output.homeLocalOnly. Also (MED) homeApplyDone prints 'done' instead of 'generation 0' when the post-switch gen re-read fails (switch still succeeded). VERSION/zon -> 3.1.2. Verified on mac: 'home apply --on remotebox' -> local-only refusal; local 'home apply' unaffected. build+tests green
- time
- 2026-06-10 12:13 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- flake + home manager support
- parent
- a96eade6fa9c
↓ nina-be755c08.tar.gzatlas at this save
files changed4 files
VERSION+1 −1build.zig.zon+1 −1src/commands.zig+10 −0src/output.zig+17 −0build.zig.zon+1 −1
@@ -9,7 +9,7 @@99 .name = .nina,1010 // This is a [Semantic Version](https://semver.org/).1111 // In a future version of Zig it will be used for package deduplication.12- .version = "3.1.1",12+ .version = "3.1.2",1313 // Together with name, this represents a globally unique package1414 // identifier. This field is generated by the Zig toolchain when the1515 // package is first created, and then *never changes*. This allowssrc/commands.zig+10 −0
@@ -978,6 +978,16 @@978978 if (ctx.sub.len == 0 or std.mem.eql(u8, ctx.sub, "help"))979979 return output.subcommandHelp("home", &home_help, null);980980 981+ // Home Manager manages the local user's environment. Detection (which binary,982+ // ~/.config/home-manager, $HOME/$USER for the flake ref) all read the LOCAL983+ // host, while exec routes over SSH for a remote machine — so `home --on984+ // <remote>` would decide mode/flake-ref from the wrong box. Refuse it cleanly985+ // rather than acting on a mismatch.986+ if (!ctx.machine.local) {987+ output.homeLocalOnly(ctx.machine.name);988+ return;989+ }990+981991 const mode = exec.detectHomeManager(ctx.gpa, ctx.io, ctx.environ);982992 if (mode == .none) {983993 output.homeNotInstalled();src/output.zig+17 −0
@@ -995,11 +995,28 @@995995 996996 pub fn homeApplyDone(gen: u32, elapsed_ms: u64) void {997997 const secs = @as(f64, @floatFromInt(elapsed_ms)) / 1000.0;998+ // gen 0 means the post-switch generation re-read failed — the switch itself999+ // succeeded, so report success without a misleading "generation 0".1000+ if (gen == 0) {1001+ if (elapsed_ms >= 1000) {1002+ p("{s}done {s}[{d:.1}s]{s}\n", .{ hdr(), c(DIM), secs, c(RESET) });1003+ } else {1004+ p("{s}done\n", .{hdr()});1005+ }1006+ return;1007+ }9981008 if (elapsed_ms >= 1000) {9991009 p("{s}generation {s}{d}{s} {s}[{d:.1}s]{s}\n", .{ hdr(), c(BOLD), gen, c(RESET), c(DIM), secs, c(RESET) });10001010 } else {10011011 p("{s}generation {s}{d}{s}\n", .{ hdr(), c(BOLD), gen, c(RESET) });10021012 }1013+}1014+1015+// `home` was invoked against a remote machine. Detection + flake-ref are1016+// local-only, so we don't act on a remote — point the user at the local run.1017+pub fn homeLocalOnly(machine: []const u8) void {1018+ p("{s}home manager commands run on the local machine only\n", .{hdr()});1019+ p(" {s}-> '{s}' is remote; run nina home on that machine directly{s}\n", .{ c(DIM), machine, c(RESET) });10031020 }10041021 10051022 pub fn homeApplyDry(machine: []const u8) void {