4c34ae00a009
add nina mood: plain-language machine health (systemctl is-system-running + current gen + last-applied age + system closure size); registered in dispatch and help
- time
- 2026-06-04 23:17 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- mood command
- parent
- 11ccaf00b0c5
↓ nina-4c34ae00.tar.gzatlas at this save
files changed4 files
src/commands.zig+10 −0src/exec.zig+13 −0src/main.zig+1 −0src/output.zig+14 −0src/commands.zig+10 −0
@@ -169,6 +169,16 @@169169 }170170 }171171 172+pub fn mood(ctx: Ctx) !void {173+ const gen = exec.getCurrentGeneration(ctx.gpa, ctx.io, &ctx.machine) catch 0;174+ const st = exec.systemStatus(ctx.gpa, ctx.io, &ctx.machine);175+ defer ctx.gpa.free(st.size);176+ defer ctx.gpa.free(st.age);177+ const state = exec.systemRunningState(ctx.gpa, ctx.io, &ctx.machine) catch try ctx.gpa.dupe(u8, "unknown");178+ defer ctx.gpa.free(state);179+ output.mood(ctx.machine.name, state, gen, st.age, st.size);180+}181+172182 pub fn doctor(ctx: Ctx) !void {173183 output.doctorHeader(ctx.machine.name);174184 const checks = try exec.runDoctorChecks(ctx.gpa, ctx.io, &ctx.machine);src/exec.zig+13 −0
@@ -394,6 +394,19 @@394394 };395395 }396396 397+// `systemctl is-system-running` -> "running" / "degraded" / "starting" ... A398+// one-word health signal; exits non-zero when degraded, so we read stdout, not399+// the code. Caller owns the returned slice.400+pub fn systemRunningState(gpa: std.mem.Allocator, io: std.Io, machine: *const types.Machine) ![]u8 {401+ const r = capture(gpa, io, machine, &.{ "systemctl", "is-system-running" }) catch402+ return gpa.dupe(u8, "unknown");403+ defer gpa.free(r.stderr);404+ const state = std.mem.trim(u8, r.stdout, " \t\n\r");405+ const owned = try gpa.dupe(u8, if (state.len > 0) state else "unknown");406+ gpa.free(r.stdout);407+ return owned;408+}409+397410 fn humanAgo(gpa: std.mem.Allocator, secs: u64) ![]u8 {398411 if (secs < 60) return std.fmt.allocPrint(gpa, "{d}s ago", .{secs});399412 if (secs < 3600) return std.fmt.allocPrint(gpa, "{d}m ago", .{secs / 60});src/main.zig+1 −0
@@ -159,6 +159,7 @@159159 if (std.mem.eql(u8, cmd, "status")) return commands.statusCmd(ctx);160160 if (std.mem.eql(u8, cmd, "diff")) return commands.diff(ctx);161161 if (std.mem.eql(u8, cmd, "doctor")) return commands.doctor(ctx);162+ if (std.mem.eql(u8, cmd, "mood")) return commands.mood(ctx);162163 if (std.mem.eql(u8, cmd, "update")) return commands.update(ctx);163164 if (std.mem.eql(u8, cmd, "upgrade")) return commands.upgrade(ctx);164165 if (std.mem.eql(u8, cmd, "log")) return commands.log(ctx);src/output.zig+14 −0
@@ -475,6 +475,19 @@475475 p("{s}removing {s}{s}{s}\n", .{ hdr(), c(PINK), pkg, c(RESET) });476476 }477477 478+// Plain-language health summary. No kaomoji, no hearts — just the facts.479+pub fn mood(machine: []const u8, state: []const u8, gen: u32, age: []const u8, size: []const u8) void {480+ const healthy = std.mem.eql(u8, state, "running");481+ const verdict = if (healthy) "all good" else state;482+ const color = if (healthy) GREEN else YELLOW;483+ p("{s}{s} {s}{s}{s}\n", .{ hdr(), machine, c(color), verdict, c(RESET) });484+ if (age.len > 0 or size.len > 0) {485+ p(" generation {d}, last applied {s}, {s} system closure\n", .{ gen, age, size });486+ } else {487+ p(" generation {d}\n", .{gen});488+ }489+}490+478491 pub fn installEditorPrompt(pkg: []const u8, config_path: []const u8, line: u32, editor: []const u8) void {479492 p("{s}opening {s} add {s}{s}{s} to systemPackages\n", .{ hdr(), config_path, c(PINK), pkg, c(RESET) });480493 const cmd = std.fmt.allocPrint(std.heap.page_allocator, "{s} {s} +{d}", .{ editor, config_path, line }) catch editor;@@ -560,6 +573,7 @@560573 .{ "upgrade", "update and rebuild" },561574 .{ "log", "operation history" },562575 .{ "doctor", "diagnose issues" },576+ .{ "mood", "plain-language health" },563577 .{ "develop", "enter dev shell" },564578 .{ "flake", "flake management" },565579 .{ "build", "build a package" },