ab2b04787858
fix log --last N truncation (OF-7) — readNinaLog now keeps only the final N non-empty lines when last>0 (was '_ = last'), copying out before freeing content; default last=50 unaffected when fewer entries — build+tests green, --last 2 verified returns exactly 2 of 4 entries
- time
- 2026-06-05 02:18 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- nina finishing brief
- parent
- f1e9d723cc0f
↓ nina-ab2b0478.tar.gzatlas at this save
files changed1 file
src/exec.zig+22 −2src/exec.zig+22 −2
@@ -786,8 +786,28 @@786786 const home = environ.get("HOME") orelse return error.FileNotFound;787787 const path = try std.fmt.allocPrint(gpa, "{s}/.nina.log", .{home});788788 defer gpa.free(path);789- _ = last;790- return std.Io.Dir.readFileAlloc(.cwd(), io, path, gpa, .unlimited) catch return error.FileNotFound;789+ const content = std.Io.Dir.readFileAlloc(.cwd(), io, path, gpa, .unlimited) catch return error.FileNotFound;790+ if (last == 0) return content;791+792+ // Collect non-empty lines, then keep only the final `last`. Slices point into793+ // `content`, so copy them out before freeing it.794+ var lines: std.ArrayList([]const u8) = .empty;795+ defer lines.deinit(gpa);796+ var it = std.mem.splitScalar(u8, content, '\n');797+ while (it.next()) |line| {798+ if (std.mem.trim(u8, line, " \t\r").len == 0) continue;799+ try lines.append(gpa, line);800+ }801+ if (lines.items.len <= last) return content;802+803+ var out: std.ArrayList(u8) = .empty;804+ errdefer out.deinit(gpa);805+ for (lines.items[lines.items.len - last ..]) |line| {806+ try out.appendSlice(gpa, line);807+ try out.append(gpa, '\n');808+ }809+ gpa.free(content);810+ return out.toOwnedSlice(gpa);791811 }792812 793813 // nina is a one-shot process, so "did the last apply fail this session?" can't