const std = @import("std"); const debug_trace = @import("../core/shared/debug_trace.zig"); const display_width = @import("../core/shared/display_width.zig"); const io_mod = @import("../core/shared/io.zig"); const text_utils = @import("../core/shared/text_utils.zig"); const tool_result_display = @import("../core/tooling/tool_result_display.zig"); const command_output_content = @import("../core/tooling/command_output_content.zig"); const command_replay_store = @import("../core/session/command_replay_store.zig"); const result_store = @import("../core/session/result_store.zig"); const session_child_store = @import("../core/session/session_child_store.zig"); const diff_mod = @import("../core/output/diff.zig"); const transcript_presentation = @import("../core/output/transcript_presentation.zig"); const full_transcript_metadata = @import("../core/output/full_transcript_metadata.zig"); const assistant_wrap = @import("render_engine/assistant_wrap.zig"); const build_checkpoint = @import("render_engine/build_checkpoint.zig"); const transcript_blocks = @import("render_engine/transcript_blocks.zig"); const command_output_runtime = @import("transcript/command_output_runtime.zig"); const tool_group_projection = @import("transcript/tool_group_projection.zig"); const user_message_card = @import("assistant/user_message_card.zig"); const ui_render = @import("render.zig"); const types = @import("../core/shared/types.zig"); const Allocator = std.mem.Allocator; const ToolDetailRecord = transcript_blocks.ToolDetailRecord; const BuildCheckpoint = build_checkpoint.BuildCheckpoint; const PendingInputProbe = struct { polls: usize = 0, fn pending(context: *anyopaque) bool { const self: *PendingInputProbe = @ptrCast(@alignCast(context)); self.polls += 1; return true; } }; test "projection source index resolves direct tool and command associations" { const alloc = std.testing.allocator; const block_call_id = try alloc.dupe(u8, "command-7"); defer alloc.free(block_call_id); const lookup_call_id = try alloc.dupe(u8, "command-7"); defer alloc.free(lookup_call_id); var block = command_output_runtime.CommandOutputBlock{ .entry_id = 20, .lifecycle_id = .{ .turn_id = 7, .call_id = block_call_id }, .retention_overflow = true, }; try block.source_entry_ids.append(alloc, 21); defer block.source_entry_ids.deinit(alloc); const blocks = [_]command_output_runtime.CommandOutputBlock{block}; const details = [_]ToolDetailRecord{.{ .entry_id = 10, .tool_name = @constCast("run_command"), .lifecycle_id = .{ .turn_id = 7, .call_id = lookup_call_id }, .command_output_entry_id = 20, }}; var index = try ProjectionSourceIndex.build(alloc, &details, &blocks, null); defer index.deinit(alloc); try std.testing.expect(index.detailForEntry(10) == &details[0]); try std.testing.expectEqual(@as(?usize, 0), index.commandBlockIndexForEntry(20)); try std.testing.expectEqual( @as(?usize, 0), index.commandBlockIndexForLifecycle(.{ .turn_id = 7, .call_id = lookup_call_id }), ); try std.testing.expectEqual(@as(?usize, 0), index.commandBlockIndexForDetail(&details[0])); try std.testing.expect(index.commandSourceOwned(21)); } test "interruptible full projection checks inside one oversized assistant entry" { const alloc = std.testing.allocator; var entries = [_]transcript_blocks.TranscriptEntry{.{ .assistant_turn = .{ .id = 1, .segments = .{}, } }}; defer entries[0].assistant_turn.segments.deinit(alloc); try entries[0].assistant_turn.segments.text.appendNTimes(alloc, 'x', 16 * 1024); var probe = PendingInputProbe{}; var checkpoint = BuildCheckpoint.init(&probe, PendingInputProbe.pending); try std.testing.expectError( error.InputPending, buildProjectionWithDiffResolverInterruptible( alloc, &entries, &.{}, &.{}, .{}, 80, null, null, &checkpoint, ), ); try std.testing.expectEqual(@as(usize, 1), probe.polls); var retry = try buildProjectionWithDiffResolverInterruptible( alloc, &entries, &.{}, &.{}, .{}, 80, null, null, null, ); defer retry.deinit(alloc); var baseline = try buildProjectionWithDiffResolverInterruptible( alloc, &entries, &.{}, &.{}, .{}, 80, null, null, null, ); defer baseline.deinit(alloc); const retry_bytes = try renderProjectionViewportSource( alloc, &retry, null, 80, std.math.maxInt(u16), 0, ); defer alloc.free(retry_bytes); const baseline_bytes = try renderProjectionViewportSource( alloc, &baseline, null, 80, std.math.maxInt(u16), 0, ); defer alloc.free(baseline_bytes); try std.testing.expectEqualStrings(baseline_bytes, retry_bytes); } test "interruptible full projection measurement checks inside one static segment" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); const bytes = try alloc.alloc(u8, 16 * 1024); @memset(bytes, 'x'); try projection.segments.append(alloc, .{ .static = bytes }); var probe = PendingInputProbe{}; var checkpoint = BuildCheckpoint.init(&probe, PendingInputProbe.pending); try std.testing.expectError( error.InputPending, measureProjectionInterruptible(alloc, &projection, null, 80, &checkpoint), ); try std.testing.expectEqual(@as(usize, 1), probe.polls); const completed = try measureProjectionInterruptible(alloc, &projection, null, 80, null); try std.testing.expect(completed.total_rows > 0); } test "interruptible stored result measurement preserves projection state" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const content = try alloc.alloc(u8, 16 * 1024); defer alloc.free(content); @memset(content, 'x'); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "interruptible-result", "read_file", content, ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = "preview", } }); var probe = PendingInputProbe{}; var checkpoint = BuildCheckpoint.init(&probe, PendingInputProbe.pending); try std.testing.expectError( error.InputPending, measureProjectionInterruptible(alloc, &projection, &capability, 80, &checkpoint), ); const stored = projection.segments.items[0].stored_result; try std.testing.expectEqual(StoredResultKind.tool_result, stored.kind); try std.testing.expectEqualStrings(handle, stored.handle); try std.testing.expect(stored.fallback_handle == null); try std.testing.expect(!stored.unavailable); var baseline = Projection{ .styles = .{} }; defer baseline.deinit(alloc); try baseline.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = "preview", } }); const retry_measurement = try measureProjection(alloc, &projection, &capability, 80); const baseline_measurement = try measureProjection(alloc, &baseline, &capability, 80); try std.testing.expectEqual(baseline_measurement.total_rows, retry_measurement.total_rows); const retry = try renderProjectionViewportSource( alloc, &projection, &capability, 80, @intCast(retry_measurement.total_rows), 0, ); defer alloc.free(retry); const uninterrupted = try renderProjectionViewportSource( alloc, &baseline, &capability, 80, @intCast(baseline_measurement.total_rows), 0, ); defer alloc.free(uninterrupted); try std.testing.expectEqualStrings(uninterrupted, retry); } test "interruptible full projection rendering retries after cancellation" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); const bytes = try alloc.alloc(u8, 16 * 1024); @memset(bytes, 'x'); try projection.segments.append(alloc, .{ .static = bytes }); _ = try measureProjection(alloc, &projection, null, 80); var probe = PendingInputProbe{}; var checkpoint = BuildCheckpoint.init(&probe, PendingInputProbe.pending); try std.testing.expectError( error.InputPending, renderProjectionViewportSourceWithSelection( alloc, &projection, null, 80, std.math.maxInt(u16), .{ .fixed_offset = 0 }, &checkpoint, std.math.maxInt(usize), ), ); const completed = try renderProjectionViewportSource( alloc, &projection, null, 80, std.math.maxInt(u16), 0, ); defer alloc.free(completed); try std.testing.expect(completed.len > 0); } pub const FullDiffResolver = struct { context: *anyopaque, full_for_marker: *const fn (context: *anyopaque, id: u32) ?[]const u8, has_full_for_lifecycle: *const fn (context: *anyopaque, lifecycle_id: types.ToolLifecycleId) bool, }; pub const ViewportOffsetSelector = struct { context: *anyopaque, select_offset: *const fn (context: *anyopaque, measurement: ProjectionMeasurement, visible_rows: u16) u32, }; const StoredResultKind = enum { tool_result, command_result, command_artifact, command_replay, }; const StoredResult = struct { kind: StoredResultKind = .tool_result, handle: []const u8, preview: ?[]const u8, framed_bytes: usize = 0, fallback_handle: ?[]const u8 = null, fallback_artifact_handle: ?[]const u8 = null, retained_command_fallback: ?[]u8 = null, start_record: usize = 0, end_record: ?usize = null, unavailable: bool = false, required_replay_unavailable: bool = false, line_prefix: []const u8 = " ", fn deinit(self: StoredResult, alloc: Allocator) void { if (self.retained_command_fallback) |bytes| alloc.free(bytes); } }; const CommandArtifactReader = struct { file: session_child_store.ManagedFile, size: usize, fn deinit(self: *CommandArtifactReader) void { self.file.deinit(); self.* = undefined; } }; const StoredResultReader = union(StoredResultKind) { tool_result: result_store.ResultReader, command_result: result_store.ResultReader, command_artifact: CommandArtifactReader, command_replay: command_replay_store.Reader, fn deinit(self: *StoredResultReader) void { switch (self.*) { .tool_result => |*reader| reader.deinit(), .command_result => |*reader| reader.deinit(), .command_artifact => |*reader| reader.deinit(), .command_replay => |*reader| reader.deinit(), } self.* = undefined; } fn size(self: *const StoredResultReader) usize { return switch (self.*) { .tool_result => |reader| reader.size, .command_result => |reader| reader.size, .command_artifact => |reader| reader.size, .command_replay => |reader| reader.size, }; } fn readPage( self: *StoredResultReader, alloc: Allocator, offset: usize, max_bytes: usize, ) ![]u8 { return switch (self.*) { .tool_result => |*reader| reader.readPage(alloc, offset, max_bytes), .command_result => |*reader| reader.readPage(alloc, offset, max_bytes), .command_artifact => |*reader| reader.file.readRange( alloc, @intCast(offset), @min(max_bytes, reader.size -| offset), ), .command_replay => error.InvalidReplayPageRead, }; } }; const Segment = union(enum) { static: []u8, stored_result: StoredResult, }; const ProjectionCheckpoint = struct { row: u32, col: u16, row_has_bytes: bool, }; const ProjectionWindowStart = struct { segment_index: usize, checkpoint: ProjectionCheckpoint, }; /// A width-rendered Ctrl-O document. Static transcript bytes and retained /// command fallbacks are owned by the projection; stored-result handles remain /// borrowed and are read through the session capability only on demand. pub const Projection = struct { segments: std.ArrayList(Segment) = .empty, anchor_segment_index: ?usize = null, item_boundaries: std.ArrayList(ItemBoundary) = .empty, measured_item_rows: std.ArrayList(transcript_presentation.ItemRow) = .empty, measured_segment_checkpoints: std.ArrayList(ProjectionCheckpoint) = .empty, measurement_cols: ?u16 = null, measured_total_rows: u32 = 0, measured_anchor_row: ?u32 = null, styles: transcript_blocks.Styles, fn invalidateMeasurement(self: *Projection) void { self.measurement_cols = null; self.measured_total_rows = 0; self.measured_anchor_row = null; } fn windowStart(self: *const Projection, cols: u16, start_row: u32) ProjectionWindowStart { const origin = ProjectionCheckpoint{ .row = 0, .col = 1, .row_has_bytes = false, }; if (self.measurement_cols != cols or self.measured_segment_checkpoints.items.len != self.segments.items.len) { return .{ .segment_index = 0, .checkpoint = origin }; } var selected = ProjectionWindowStart{ .segment_index = 0, .checkpoint = origin }; for (self.measured_segment_checkpoints.items, 0..) |checkpoint, index| { if (checkpoint.row > start_row) break; const starts_inside_visible_row = checkpoint.row == start_row and (checkpoint.row_has_bytes or checkpoint.col != 1); if (starts_inside_visible_row) continue; selected = .{ .segment_index = index, .checkpoint = checkpoint }; } return selected; } pub fn deinit(self: *Projection, alloc: Allocator) void { for (self.segments.items) |segment| switch (segment) { .static => |bytes| alloc.free(bytes), .stored_result => |stored| stored.deinit(alloc), }; self.segments.deinit(alloc); self.item_boundaries.deinit(alloc); self.measured_item_rows.deinit(alloc); self.measured_segment_checkpoints.deinit(alloc); self.* = undefined; } }; const ItemBoundary = struct { entry_id: u32, segment_index: usize, }; test "projection applies actions by transcript position after lifecycle reposition" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 2, .bytes = "second\n" } }, .{ .raw_bytes = .{ .id = 3, .bytes = "third\n" } }, .{ .raw_bytes = .{ .id = 1, .bytes = "old status\n" } }, }; const actions = [_]transcript_blocks.EntryRenderAction{ .keep, .keep, .{ .override = .{ .kind = .tool_status, .bytes = "new status\n" } }, }; var projection = try buildProjectionWithEntryActionsInterruptible( alloc, &entries, &.{}, &.{}, .{}, 80, null, null, &actions, null, ); defer projection.deinit(alloc); const rendered = try renderProjectionViewportSource(alloc, &projection, null, 80, 10, 0); defer alloc.free(rendered); try std.testing.expect(std.mem.find(u8, rendered, "new status") != null); try std.testing.expect(std.mem.find(u8, rendered, "old status") == null); } pub const ProjectionMeasurement = struct { total_rows: u32, anchor_row: ?u32, item_rows: []const transcript_presentation.ItemRow = &.{}, }; /// Owns the in-progress static writer while composing a Projection, so every /// build-time segment boundary transfers through one place. const ProjectionBuilder = struct { alloc: Allocator, projection: Projection, projection_cols: u16, out: std.Io.Writer.Allocating, fn init( alloc: Allocator, projection_styles: transcript_blocks.Styles, projection_cols: u16, ) ProjectionBuilder { return .{ .alloc = alloc, .projection = .{ .styles = projection_styles }, .projection_cols = projection_cols, .out = .init(alloc), }; } fn deinit(self: *ProjectionBuilder) void { self.out.deinit(); self.projection.deinit(self.alloc); self.* = undefined; } fn staticOut(self: *ProjectionBuilder) *std.Io.Writer.Allocating { return &self.out; } fn styles(self: *const ProjectionBuilder) transcript_blocks.Styles { return self.projection.styles; } fn markAnchor(self: *ProjectionBuilder) !void { try self.flushStatic(); self.projection.anchor_segment_index = self.projection.segments.items.len; } fn markEntry(self: *ProjectionBuilder, entry_id: u32) !void { try self.flushStatic(); try self.projection.item_boundaries.append(self.alloc, .{ .entry_id = entry_id, .segment_index = self.projection.segments.items.len, }); } fn appendStoredResult(self: *ProjectionBuilder, stored: StoredResult) !void { errdefer stored.deinit(self.alloc); try self.flushStatic(); try self.projection.segments.append(self.alloc, .{ .stored_result = stored }); } fn finish(self: *ProjectionBuilder) !Projection { try self.flushStatic(); try self.projection.measured_item_rows.ensureTotalCapacity( self.alloc, self.projection.item_boundaries.items.len, ); try self.projection.measured_segment_checkpoints.ensureTotalCapacity( self.alloc, self.projection.segments.items.len, ); self.out.deinit(); const projection = self.projection; self.* = undefined; return projection; } fn flushStatic(self: *ProjectionBuilder) !void { if (self.out.written().len == 0) return; const bytes = try self.out.toOwnedSlice(); errdefer self.alloc.free(bytes); try self.projection.segments.append(self.alloc, .{ .static = bytes }); self.out = .init(self.alloc); } }; test "full projection replaces a compact command entry with the retained command block" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ first\n│ ... 2 command lines folded\n"), .class = .command_output } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2 }}; defer blocks[0].deinit(alloc); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "first\n") }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "second\n") }); try blocks[0].lines.append(alloc, .{ .stream = .stderr, .text = try alloc.dupe(u8, "third\n") }); blocks[0].total_lines = blocks[0].lines.items.len; blocks[0].retained_text_bytes = "first\n".len + "second\n".len + "third\n".len; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_entry_id = 2, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, 1, ); defer projection.deinit(alloc); const rendered = try renderProjectionViewportSource(alloc, &projection, null, 80, 12, 0); defer alloc.free(rendered); try std.testing.expect(std.mem.indexOf(u8, rendered, "│ first") != null); try std.testing.expect(std.mem.indexOf(u8, rendered, "│ second") != null); try std.testing.expect(std.mem.indexOf(u8, rendered, "│ third") != null); try std.testing.expect(std.mem.indexOf(u8, rendered, "folded") == null); try std.testing.expectEqual(@as(?u32, 0), (try measureProjection(alloc, &projection, null, 80)).anchor_row); } test "full projection wraps retained command records with a gutter on every physical row" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("│ compact\n"), .class = .command_output, } }}; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 1 }}; defer blocks[0].deinit(alloc); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "paragraph words"), }); blocks[0].total_lines = 1; blocks[0].retained_text_bytes = "paragraph words".len; var projection = try buildProjection( alloc, &entries, &.{}, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 16, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 16, 8, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "│ paragraph\n│ words\n") != null); try std.testing.expect(std.mem.indexOf(u8, source, "│ paragraph words") == null); } test "full projection keeps noncontiguous retained command records at source entries" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .subagent_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact first\n"), .class = .command_output, } }, .{ .raw_bytes = .{ .id = 3, .created_at_ms = 0, .bytes = @constCast("UNRELATED_NOTICE\n"), .class = .subagent_status, } }, .{ .raw_bytes = .{ .id = 4, .created_at_ms = 0, .bytes = @constCast("│ compact second\n"), .class = .command_output, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2 }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.appendSlice(alloc, &.{ 2, 4 }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "FULL_FIRST"), .record_ordinal = 0, .entry_id = 2, .terminated = true, }); try blocks[0].lines.append(alloc, .{ .stream = .stderr, .text = try alloc.dupe(u8, "FULL_SECOND"), .record_ordinal = 1, .entry_id = 4, .terminated = true, }); blocks[0].total_lines = 2; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe(u8, "exit_code=0\n\nSTORED_DUPLICATE\n\n"), .command_output_entry_id = 2, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 20, 0); defer alloc.free(source); const first = std.mem.indexOf(u8, source, "FULL_FIRST") orelse return error.TestExpectedFirstRecord; const notice = std.mem.indexOf(u8, source, "UNRELATED_NOTICE") orelse return error.TestExpectedNotice; const second = std.mem.indexOf(u8, source, "FULL_SECOND") orelse return error.TestExpectedSecondRecord; try std.testing.expect(first < notice and notice < second); try std.testing.expect(std.mem.indexOf(u8, source, "STORED_DUPLICATE") == null); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, source, " result")); } test "full projection matches file details to full diffs by marker and lifecycle" { const alloc = std.testing.allocator; const compact_first = try @import("../core/output/diff.zig").wrapWithMarkers( alloc, 101, "\x1b[38;5;252m │ \x1b[38;5;203m1 -\x1b[38;5;252m ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnCOMPACT_FIRST_TAIL\x1b[0m\n", ); defer alloc.free(compact_first); const compact_second = try @import("../core/output/diff.zig").wrapWithMarkers( alloc, 102, "\x1b[38;5;252m │ \x1b[38;5;77m1 +\x1b[38;5;252m ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnCOMPACT_SECOND_TAIL\x1b[0m\n", ); defer alloc.free(compact_second); const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Write first.txt\n"), .class = .tool_status } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = compact_first, .class = .diff_block } }, .{ .raw_bytes = .{ .id = 3, .created_at_ms = 0, .bytes = @constCast("● Write second.txt\n"), .class = .tool_status } }, .{ .raw_bytes = .{ .id = 4, .created_at_ms = 0, .bytes = compact_second, .class = .diff_block } }, }; var details = [_]ToolDetailRecord{ .{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "write_file"), .arguments_json = try alloc.dupe(u8, "{\"content\":\"RAW_FIRST\\\\n\"}"), .lifecycle_id = .{ .turn_id = 41, .call_id = try alloc.dupe(u8, "first") }, }, .{ .entry_id = 3, .tool_name = try alloc.dupe(u8, "write_file"), .arguments_json = try alloc.dupe(u8, "{\"content\":\"RAW_SECOND\\\\n\"}"), .lifecycle_id = .{ .turn_id = 41, .call_id = try alloc.dupe(u8, "second") }, }, }; defer for (&details) |*detail| detail.deinit(alloc); const Resolver = struct { const full_first = "\x1b[38;5;252m │ \x1b[38;5;203m1 -\x1b[38;5;252m ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnFULL_FIRST_TAIL\x1b[0m\n"; fn fullForMarker(_: *anyopaque, id: u32) ?[]const u8 { return if (id == 101) full_first else null; } fn hasFullForLifecycle(_: *anyopaque, lifecycle_id: types.ToolLifecycleId) bool { return lifecycle_id.turn_id == 41 and std.mem.eql(u8, lifecycle_id.call_id, "first"); } }; var resolver_context: u8 = 0; const styles: transcript_blocks.Styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }; var projection = try buildProjectionWithResolver( alloc, &entries, &details, &.{}, styles, 48, null, .{ .context = &resolver_context, .full_for_marker = Resolver.fullForMarker, .has_full_for_lifecycle = Resolver.hasFullForLifecycle, }, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, null, 48); const source = try renderProjectionViewportSource(alloc, &projection, null, 48, @intCast(measurement.total_rows), 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, " │ FULL_FIRST_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, source, "COMPACT_FIRST_TAIL") == null); try std.testing.expect(std.mem.indexOf(u8, source, "RAW_FIRST") == null); try std.testing.expect(std.mem.indexOf(u8, source, " │ COMPACT_SECOND_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, source, "RAW_SECOND") != null); var wide_projection = try buildProjectionWithResolver( alloc, &entries, &details, &.{}, styles, 120, null, .{ .context = &resolver_context, .full_for_marker = Resolver.fullForMarker, .has_full_for_lifecycle = Resolver.hasFullForLifecycle, }, ); defer wide_projection.deinit(alloc); const wide_measurement = try measureProjection(alloc, &wide_projection, null, 120); const wide_source = try renderProjectionViewportSource( alloc, &wide_projection, null, 120, @intCast(wide_measurement.total_rows), 0, ); defer alloc.free(wide_source); try std.testing.expect(std.mem.indexOf(u8, wide_source, "FULL_FIRST_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, wide_source, "COMPACT_SECOND_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, wide_source, " │ ") == null); try std.testing.expect(std.mem.indexOf(u8, wide_source, "RAW_SECOND") != null); } test "full projection preserves inline block gaps around expanded tool detail" { const alloc = std.testing.allocator; var entries = [_]transcript_blocks.TranscriptEntry{ .{ .user_turn = .{ .id = 1, .turn = .{ .text = try alloc.dupe(u8, "Read the config."), .images = try alloc.alloc(types.ImageAttachment, 0), } } }, .{ .assistant_turn = .{ .id = 2, .segments = .{} } }, .{ .raw_bytes = .{ .id = 3, .bytes = try alloc.dupe(u8, "● Read config\n"), .class = .subagent_status, } }, .{ .assistant_turn = .{ .id = 4, .segments = .{} } }, }; defer for (&entries) |*entry| entry.deinit(alloc); try entries[1].assistant_turn.segments.text.appendSlice(alloc, "Summary before tool"); try entries[3].assistant_turn.segments.text.appendSlice(alloc, "Summary after tool"); var details = [_]ToolDetailRecord{.{ .entry_id = 3, .tool_name = try alloc.dupe(u8, "read_file"), .arguments_json = try alloc.dupe(u8, "{\"path\":\"config\"}"), .result = try alloc.dupe(u8, "value"), }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 20, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "\n\n Summary before tool") != null); try std.testing.expect(std.mem.indexOf(u8, source, " value\n\n Summary after tool") != null); } test "full tool detail keeps wrapped rails primary while output stays secondary" { const alloc = std.testing.allocator; const styles = transcript_blocks.Styles{ .reset_style = "", .dim_style = "", }; var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit(); try appendTerminalSafeToolOutput( &out.writer, alloc, styles, "alpha beta gamma delta", 16, ); try std.testing.expectEqualStrings( "│ alpha beta\n" ++ "│ gamma delta\n", out.written(), ); } test "full projection retains consecutive in-memory tool details" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Listed .\n"), .class = .tool_status } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("● Read README.md\n"), .class = .tool_status } }, }; var details = [_]ToolDetailRecord{ .{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "glob_files"), .arguments_json = try alloc.dupe(u8, "{\"path\":\".\"}"), .result = try alloc.dupe(u8, "LIST_FULL_DETAIL_MARKER"), }, .{ .entry_id = 2, .tool_name = try alloc.dupe(u8, "read_file"), .arguments_json = try alloc.dupe(u8, "{\"path\":\"README.md\"}"), .result = try alloc.dupe(u8, "READ_FULL_DETAIL_MARKER"), }, }; defer for (&details) |*detail| detail.deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 24, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "LIST_FULL_DETAIL_MARKER") != null); try std.testing.expect(std.mem.indexOf(u8, source, "READ_FULL_DETAIL_MARKER") != null); } test "full projection applies modern width clipping to a tool status" { const alloc = std.testing.allocator; var entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .bytes = try alloc.dupe(u8, "● Searched a deliberately long query that reaches FULL_STATUS_TAIL\n"), .class = .tool_status, } }}; defer entries[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &.{}, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 24, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 24, 8, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "FULL_STATUS_TAIL") == null); try std.testing.expect(std.mem.indexOf(u8, source, "…") != null); } test "full projection preserves semantic arguments clipped from a tool heading" { const alloc = std.testing.allocator; const command = "printf a deliberately long command with FULL_ARGUMENT_TAIL"; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .bytes = @constCast("● Ran printf a deliberately long command with FULL_ARGUMENT_TAIL\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "terminal"), .captured_command = true, .arguments_json = try std.fmt.allocPrint( alloc, "{{\"action\":\"exec\",\"command\":\"{s}\",\"profile\":\"clean\"}}", .{command}, ), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 24, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, null, 24); const source = try renderProjectionViewportSource( alloc, &projection, null, 24, @intCast(measurement.total_rows), 0, ); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "command: printf") != null); try std.testing.expect(std.mem.indexOf(u8, source, "FULL_ARGUMENT_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, source, "action: exec") == null); try std.testing.expect(std.mem.indexOf(u8, source, "profile: clean") != null); try std.testing.expect(std.mem.indexOf(u8, source, "{\"command\"") == null); } test "stored result projection streams terminal-safe head middle and tail pages" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); var content: std.ArrayList(u8) = .empty; defer content.deinit(alloc); try content.appendSlice(alloc, "HEAD-SENTINEL "); try content.appendNTimes(alloc, 'x', result_store.full_read_chunk_bytes - 16); try content.appendSlice(alloc, "\x1b[31m\xf0\x9f\x98\x80"); const half_result_bytes = 4 * 1024 * 1024; try content.appendNTimes(alloc, 'x', half_result_bytes - content.items.len); try content.appendSlice(alloc, "MIDDLE-SENTINEL"); try content.appendNTimes(alloc, 'x', half_result_bytes); try content.appendSlice(alloc, "TAIL-SENTINEL"); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "paged-detail", "read_file", content.items, ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "before\n") }); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = "preview", } }); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "after\n") }); const measurement = try measureProjection(alloc, &projection, &capability, 24); try std.testing.expect(measurement.total_rows > 3); var bounded_memory: [512 * 1024]u8 = undefined; var bounded_alloc = std.heap.FixedBufferAllocator.init(&bounded_memory); const bounded_measurement = try measureProjection( bounded_alloc.allocator(), &projection, &capability, 24, ); try std.testing.expectEqual(measurement.total_rows, bounded_measurement.total_rows); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 24, 3, measurement.total_rows - 3, ); defer alloc.free(tail); try std.testing.expect(std.mem.indexOf(u8, tail, "TAIL-SENTINEL") != null); try std.testing.expect(std.mem.indexOf(u8, tail, "after") != null); // Every physical row reserves the two-cell result prefix. Escaping ESC // adds three cells while the four-byte emoji occupies two, so the marker // begins one content cell past its raw byte offset. const middle_marker_row = @as(u32, 1) + @as(u32, @intCast((half_result_bytes + 1) / (24 - 2))); const middle = try renderProjectionViewportSource( alloc, &projection, &capability, 24, 3, middle_marker_row, ); defer alloc.free(middle); try std.testing.expect(std.mem.indexOf(u8, middle, "MIDDL") != null); try std.testing.expect(std.mem.indexOf(u8, middle, "E-SENTINEL") != null); const head = try renderProjectionViewportSource(alloc, &projection, &capability, 24, 3, 0); defer alloc.free(head); try std.testing.expect(std.mem.indexOf(u8, head, "before") != null); try std.testing.expect(std.mem.indexOf(u8, head, "HEAD-SENTINEL") != null); } test "stored Unicode result remains pageable at the minimum projection width" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); var content: std.ArrayList(u8) = .empty; defer content.deinit(alloc); try content.appendSlice(alloc, "MIN_WIDTH_HEAD_"); for (0..8_192) |_| try content.appendSlice(alloc, "👩‍💻界é"); try content.appendSlice(alloc, "_MIN_WIDTH_TAIL"); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "minimum-width-unicode", "read_file", content.items, ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = null, .line_prefix = "│ ", } }); var bounded_memory: [512 * 1024]u8 = undefined; var bounded = std.heap.FixedBufferAllocator.init(&bounded_memory); const measurement = try measureProjection( bounded.allocator(), &projection, &capability, 1, ); try std.testing.expect(measurement.total_rows > 8_192); const head = try renderProjectionViewportSource( alloc, &projection, &capability, 1, 32, 0, ); defer alloc.free(head); try std.testing.expect(std.unicode.utf8ValidateSlice(head)); try std.testing.expect(std.mem.indexOf(u8, head, "MIN_WIDTH_HEAD") != null); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 1, 32, measurement.total_rows -| 32, ); defer alloc.free(tail); try std.testing.expect(std.unicode.utf8ValidateSlice(tail)); try std.testing.expect(std.mem.indexOf(u8, tail, "MIN_WIDTH_TAIL") != null); } test "stored result projection preserves line breaks" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "multiline-detail", "read_file", "README.md\n\nFIRST_RESULT_LINE\nSECOND_RESULT_LINE\nTHIRD_RESULT_LINE\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = null, } }); const measurement = try measureProjection(alloc, &projection, &capability, 80); try std.testing.expectEqual(@as(u32, 3), measurement.total_rows); const source = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 3, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "FIRST_RESULT_LINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "SECOND_RESULT_LINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "THIRD_RESULT_LINE") != null); } test "stored tool result repeats its rail on every physical wrap row" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "wrapped-detail", "grep_files", "alpha beta gamma delta epsilon zeta", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = null, .line_prefix = "│ ", } }); const measurement = try measureProjection(alloc, &projection, &capability, 16); try std.testing.expect(measurement.total_rows > 1); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 16, @intCast(measurement.total_rows), 0, ); defer alloc.free(source); try std.testing.expectEqual( @as(usize, measurement.total_rows), std.mem.count(u8, source, "│"), ); } test "projection measurement cache is reused at one width and recomputed after resize" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{} }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "12345678901234567890\nsecond\n"), }); const narrow = try measureProjection(alloc, &projection, null, 10); try std.testing.expectEqual(@as(?u16, 10), projection.measurement_cols); const cached = try measureProjection(alloc, &projection, null, 10); try std.testing.expectEqual(narrow.total_rows, cached.total_rows); try std.testing.expectEqual(@as(?u16, 10), projection.measurement_cols); const wide = try measureProjection(alloc, &projection, null, 20); try std.testing.expect(wide.total_rows < narrow.total_rows); try std.testing.expectEqual(@as(?u16, 20), projection.measurement_cols); } test "measured segment checkpoints preserve viewport bytes from a full walk" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); for ([_][]const u8{ "row-0\nrow-1\nrow-2\n", "\x1b[31mmid", "dle\x1b[0m\nrow-4 wide \xe7\x95\x8c\n", "row-5\nrow-6\n", }) |bytes| { try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, bytes) }); } try projection.measured_segment_checkpoints.ensureTotalCapacity( alloc, projection.segments.items.len, ); for (0..7) |offset| { _ = try measureProjection(alloc, &projection, null, 12); const accelerated = try renderProjectionViewportSource( alloc, &projection, null, 12, 2, @intCast(offset), ); defer alloc.free(accelerated); projection.invalidateMeasurement(); const full_walk = try renderProjectionViewportSource( alloc, &projection, null, 12, 2, @intCast(offset), ); defer alloc.free(full_walk); try std.testing.expectEqualStrings(full_walk, accelerated); } _ = try measureProjection(alloc, &projection, null, 12); try std.testing.expect(projection.windowStart(12, 4).segment_index > 0); } test "viewport selector receives the same-walk measurement and its offset picks the window" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "one\ntwo\n") }); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "three\nfour\n") }); projection.anchor_segment_index = 1; const Recorder = struct { calls: u32 = 0, measurement: ?ProjectionMeasurement = null, visible_rows: ?u16 = null, fn selectOffset(context: *anyopaque, measurement: ProjectionMeasurement, visible_rows: u16) u32 { const self: *@This() = @ptrCast(@alignCast(context)); self.calls += 1; self.measurement = measurement; self.visible_rows = visible_rows; return measurement.anchor_row.?; } }; var recorder = Recorder{}; const selected = try renderProjectionViewportSourceWithSelector(alloc, &projection, null, 80, 2, .{ .context = &recorder, .select_offset = Recorder.selectOffset, }); defer alloc.free(selected); try std.testing.expectEqual(@as(u32, 1), recorder.calls); try std.testing.expectEqual(@as(u32, 4), recorder.measurement.?.total_rows); try std.testing.expectEqual(@as(?u32, 2), recorder.measurement.?.anchor_row); try std.testing.expectEqual(@as(?u16, 2), recorder.visible_rows); const direct = try renderProjectionViewportSource(alloc, &projection, null, 80, 2, 2); defer alloc.free(direct); try std.testing.expectEqualStrings(direct, selected); } test "viewport selector sees the degraded measurement when a stored segment is unavailable" { const alloc = std.testing.allocator; const dim = "\x1b[38;5;245m"; const reset = "\x1b[39m"; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = reset, .dim_style = dim, .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "head\n") }); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = "missing-handle", .preview = "preview-line", .line_prefix = "│ ", } }); const Recorder = struct { calls: u32 = 0, measurement: ?ProjectionMeasurement = null, visible_rows: ?u16 = null, fn selectOffset(context: *anyopaque, measurement: ProjectionMeasurement, visible_rows: u16) u32 { const self: *@This() = @ptrCast(@alignCast(context)); self.calls += 1; self.measurement = measurement; self.visible_rows = visible_rows; return 0; } }; var recorder = Recorder{}; const selected = try renderProjectionViewportSourceWithSelector(alloc, &projection, null, 80, 8, .{ .context = &recorder, .select_offset = Recorder.selectOffset, }); defer alloc.free(selected); // The unreadable segment degrades during the measure walk, so the selector // must be handed the post-degrade totals, not the pre-degrade document. const post_degrade = try measureProjection(alloc, &projection, null, 80); try std.testing.expectEqual(@as(u32, 1), recorder.calls); try std.testing.expectEqual(post_degrade.total_rows, recorder.measurement.?.total_rows); try std.testing.expectEqual(@as(?u16, 8), recorder.visible_rows); try std.testing.expect(std.mem.indexOf(u8, selected, "preview-line") != null); try std.testing.expect(std.mem.indexOf(u8, selected, "Full saved result unavailable.") != null); try std.testing.expect(std.mem.indexOf(u8, selected, dim ++ "│") == null); try std.testing.expect(std.mem.indexOf(u8, selected, reset ++ "│" ++ dim ++ " preview-line" ++ reset) != null); try std.testing.expect(std.mem.indexOf(u8, selected, reset ++ "│" ++ dim ++ " Full saved result unavailable." ++ reset) != null); } test "a window walk degrade re-selects the offset in the same frame" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "degrade-detail", "read_file", "STORED_LINE_ONE\nSTORED_LINE_TWO\nSTORED_LINE_THREE\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "head\n") }); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = "stored-preview", } }); const Saboteur = struct { calls: u32 = 0, last_total_rows: ?u32 = null, visible_rows: ?u16 = null, capability: *session_child_store.SessionChildCapability, handle: []const u8, fn selectOffset(context: *anyopaque, measurement: ProjectionMeasurement, visible_rows: u16) u32 { const self: *@This() = @ptrCast(@alignCast(context)); self.calls += 1; self.last_total_rows = measurement.total_rows; self.visible_rows = visible_rows; if (self.calls == 1) result_store.deleteManaged(self.capability, self.handle) catch {}; return 0; } }; var saboteur = Saboteur{ .capability = &capability, .handle = handle }; const selected = try renderProjectionViewportSourceWithSelector(alloc, &projection, &capability, 80, 8, .{ .context = &saboteur, .select_offset = Saboteur.selectOffset, }); defer alloc.free(selected); // Deleting the stored result between the measure and window walks forces // the window walk to degrade; the pipeline must re-measure and re-select // rather than emit a window at the stale offset. try std.testing.expectEqual(@as(u32, 2), saboteur.calls); try std.testing.expectEqual(@as(?u16, 8), saboteur.visible_rows); const post_degrade = try measureProjection(alloc, &projection, &capability, 80); try std.testing.expectEqual(post_degrade.total_rows, saboteur.last_total_rows.?); try std.testing.expect(std.mem.indexOf(u8, selected, "stored-preview") != null); try std.testing.expect(std.mem.indexOf(u8, selected, "Full saved result unavailable.") != null); } test "full projection prefers a persisted command artifact over the compact tool sidecar" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "commands"); const command_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "commands"); defer alloc.free(command_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, command_dir, .command_artifacts, .writable, ); defer capability.deinit(); const artifact_name = "fx-command-full-transcript.log"; var artifact = try capability.createExclusiveFile( alloc, .command_artifacts, artifact_name, ); defer artifact.deinit(); try artifact.writeAll( "COMMAND_ARTIFACT_HEAD\n" ++ "\n" ++ "LITERAL_ARTIFACT_ENVELOPE\n" ++ "\n" ++ "COMMAND_ARTIFACT_TAIL\n", ); try artifact.sync(); const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2 }}; defer blocks[0].deinit(alloc); const retained_duplicate = try alloc.dupe(u8, "RETAINED_COMMAND_DUPLICATE\n"); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = retained_duplicate }); blocks[0].total_lines = 1; blocks[0].retained_text_bytes = retained_duplicate.len; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe(u8, "bounded sidecar preview"), .result_handle = try alloc.dupe(u8, "missing-compact-sidecar.txt"), .command_artifact_handle = try alloc.dupe(u8, artifact_name), .command_output_entry_id = 2, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 80); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 8, measurement.total_rows -| 8, ); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "COMMAND_ARTIFACT_HEAD") != null); try std.testing.expect(std.mem.indexOf(u8, source, "COMMAND_ARTIFACT_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, source, "") != null); try std.testing.expect(std.mem.indexOf(u8, source, "LITERAL_ARTIFACT_ENVELOPE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "RETAINED_COMMAND_DUPLICATE") == null); try std.testing.expect(std.mem.indexOf(u8, source, "Full saved result unavailable.") == null); const degraded_measurement = try measureProjection(alloc, &projection, null, 80); const degraded = try renderProjectionViewportSource( alloc, &projection, null, 80, 8, degraded_measurement.total_rows -| 8, ); defer alloc.free(degraded); try std.testing.expect(std.mem.indexOf(u8, degraded, "RETAINED_COMMAND_DUPLICATE") != null); try std.testing.expect(std.mem.indexOf(u8, degraded, "Full saved result unavailable.") != null); } test "stored command artifact appends records beyond the callback count once" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "commands"); const command_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "commands"); defer alloc.free(command_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, command_dir, .command_artifacts, .writable, ); defer capability.deinit(); const artifact_name = "fx-command-late-tail.log"; var artifact = try capability.createExclusiveFile( alloc, .command_artifacts, artifact_name, ); defer artifact.deinit(); try artifact.writeAll("CALLBACK_0\nCALLBACK_1\nARTIFACT_LATE_TAIL\n"); try artifact.sync(); const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .subagent_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact callback 0\n"), .class = .command_output, } }, .{ .raw_bytes = .{ .id = 3, .created_at_ms = 0, .bytes = @constCast("│ compact callback 1\n"), .class = .command_output, } }, .{ .raw_bytes = .{ .id = 4, .created_at_ms = 0, .bytes = @constCast("FOLLOWING_STATIC_BLOCK\n"), .class = .tool_status, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .total_lines = 2, }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.appendSlice(alloc, &.{ 2, 3 }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "CALLBACK_0"), .record_ordinal = 0, .entry_id = 2, .terminated = true, }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "CALLBACK_1"), .record_ordinal = 1, .entry_id = 3, .terminated = true, }); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_artifact_handle = try alloc.dupe(u8, artifact_name), .command_output_entry_id = 2, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 80); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 80, @intCast(measurement.total_rows), 0, ); defer alloc.free(source); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, source, "CALLBACK_0")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, source, "CALLBACK_1")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, source, "ARTIFACT_LATE_TAIL")); const callback = std.mem.find(u8, source, "CALLBACK_1") orelse return error.TestExpectedCallbackRecord; const tail = std.mem.find(u8, source, "ARTIFACT_LATE_TAIL") orelse return error.TestExpectedArtifactTail; const following = std.mem.find(u8, source, "FOLLOWING_STATIC_BLOCK") orelse return error.TestExpectedFollowingBlock; try std.testing.expect(callback < tail and tail < following); } test "full projection prefers ordered replay and omits command envelopes and input" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); capture.appendAccepted(capture_alloc, .stdout, "A"); capture.appendAccepted(capture_alloc, .stderr, "B\n"); capture.appendAccepted(capture_alloc, .stdout, "\n"); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran printf replay\n"), .class = .tool_status, } }}; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2 }}; defer blocks[0].deinit(alloc); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "RETAINED_DUPLICATE"), }); blocks[0].total_lines = 1; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .arguments_json = try alloc.dupe(u8, "{\"command\":\"printf replay\"}"), .result = try alloc.dupe(u8, "exit_code=0\n\nWRONG_ENVELOPE\n\n"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .command_process_presentation = .{ .exit_code = 7 }, .outcome = .completed, .command_output_entry_id = 2, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 80); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 80, @intCast(@min(measurement.total_rows, 20)), 0, ); defer alloc.free(source); const a_index = std.mem.indexOf(u8, source, "│ A") orelse return error.TestExpectedStdout; const b_index = std.mem.indexOf(u8, source, "│ B") orelse return error.TestExpectedStderr; try std.testing.expect(a_index < b_index); try std.testing.expect(std.mem.indexOf(u8, source, "RETAINED_DUPLICATE") == null); try std.testing.expect(std.mem.indexOf(u8, source, "WRONG_ENVELOPE") == null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); try std.testing.expect(std.mem.indexOf(u8, source, " input") == null); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, source, "│ exit code 7")); } test "cancelled command detail keeps its semantic heading without raw arguments" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("■ Cancelled ./z.sh\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .arguments_json = try alloc.dupe(u8, "{\"command\":\"./z.sh\"}"), .outcome = .cancelled, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 8, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "Cancelled ./z.sh") != null); try std.testing.expect(std.mem.indexOf(u8, source, " input") == null); try std.testing.expect(std.mem.indexOf(u8, source, "{\"command\":\"./z.sh\"}") == null); } test "head-pruned command replay fills absolute prefix and suffix ranges once" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); capture.appendAccepted( capture_alloc, .stdout, "LOST_HEAD\nSURVIVING_RECORD\nLOST_SUFFIX\n", ); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact survivor\n"), .class = .command_output, } }, .{ .raw_bytes = .{ .id = 3, .created_at_ms = 0, .bytes = @constCast("PRUNED_RANGE_NOTICE\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 4, .created_at_ms = 0, .bytes = @constCast("│ compact lost suffix\n"), .class = .command_output, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .total_lines = 3, .retention_overflow = true, .overflow_line_index = 1, }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.appendSlice(alloc, &.{ 2, 4 }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "SURVIVING_RECORD"), .record_ordinal = 1, .entry_id = 2, .terminated = true, }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "INCOMPLETE_SUFFIX_PREFIX"), .record_ordinal = 2, .entry_id = 4, }); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .command_output_entry_id = 2, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 80); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 80, @intCast(measurement.total_rows), 0, ); defer alloc.free(source); const head = std.mem.indexOf(u8, source, "LOST_HEAD") orelse return error.TestExpectedLostHead; const survivor = std.mem.indexOf(u8, source, "SURVIVING_RECORD") orelse return error.TestExpectedSurvivor; const notice = std.mem.indexOf(u8, source, "PRUNED_RANGE_NOTICE") orelse return error.TestExpectedNotice; const suffix = std.mem.indexOf(u8, source, "LOST_SUFFIX") orelse return error.TestExpectedLostSuffix; try std.testing.expect(head < survivor and survivor < notice and notice < suffix); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, source, "SURVIVING_RECORD")); try std.testing.expect(std.mem.indexOf(u8, source, "INCOMPLETE_SUFFIX_PREFIX") == null); } test "active overflow marker is replaced by the terminal source" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact stable\n"), .class = .command_output, } }, .{ .raw_bytes = .{ .id = 3, .created_at_ms = 0, .bytes = @constCast("ACTIVE_UNRELATED_NOTICE\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 4, .created_at_ms = 0, .bytes = @constCast("│ compact unstable\n"), .class = .command_output, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .retention_overflow = true, .overflow_line_index = 1, }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.appendSlice(alloc, &.{ 2, 4 }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "stable prefix"), .record_ordinal = 0, .entry_id = 2, .terminated = true, }); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "UNSTABLE_TRUNCATED_RECORD"), .record_ordinal = 1, .entry_id = 4, }); blocks[0].total_lines = 2; var active_details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_entry_id = 2, }}; defer active_details[0].deinit(alloc); var active = try buildProjection( alloc, &entries, &active_details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer active.deinit(alloc); const active_measurement = try measureProjection(alloc, &active, null, 80); const active_source = try renderProjectionViewportSource( alloc, &active, null, 80, @intCast(active_measurement.total_rows), 0, ); defer alloc.free(active_source); try std.testing.expect(std.mem.indexOf(u8, active_source, "│ stable prefix") != null); try std.testing.expect(std.mem.indexOf(u8, active_source, "UNSTABLE_TRUNCATED_RECORD") == null); try std.testing.expect(std.mem.indexOf( u8, active_source, "│ … full output available when command finishes", ) != null); const active_stable = std.mem.indexOf(u8, active_source, "│ stable prefix") orelse return error.TestExpectedStablePrefix; const active_notice = std.mem.indexOf(u8, active_source, "ACTIVE_UNRELATED_NOTICE") orelse return error.TestExpectedNotice; const active_marker = std.mem.indexOf( u8, active_source, "available when command finishes", ) orelse return error.TestExpectedActiveMarker; try std.testing.expect(active_stable < active_notice and active_notice < active_marker); active_details[0].outcome = .completed; active_details[0].result = try alloc.dupe( u8, "exit_code=0\n\nstable prefix\nTERMINAL_COMPLETE_TAIL\n\n", ); var terminal = try buildProjection( alloc, &entries, &active_details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer terminal.deinit(alloc); const terminal_measurement = try measureProjection(alloc, &terminal, null, 80); const terminal_source = try renderProjectionViewportSource( alloc, &terminal, null, 80, @intCast(terminal_measurement.total_rows), 0, ); defer alloc.free(terminal_source); try std.testing.expect(std.mem.indexOf(u8, terminal_source, "TERMINAL_COMPLETE_TAIL") != null); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, terminal_source, "│ stable prefix")); const terminal_stable = std.mem.indexOf(u8, terminal_source, "│ stable prefix") orelse return error.TestExpectedStablePrefix; const terminal_notice = std.mem.indexOf(u8, terminal_source, "ACTIVE_UNRELATED_NOTICE") orelse return error.TestExpectedNotice; const terminal_tail = std.mem.indexOf(u8, terminal_source, "TERMINAL_COMPLETE_TAIL") orelse return error.TestExpectedTerminalTail; try std.testing.expect(terminal_stable < terminal_notice and terminal_notice < terminal_tail); try std.testing.expect(std.mem.indexOf( u8, terminal_source, "available when command finishes", ) == null); } test "corrupt required replay keeps a safe fallback and permanent marker" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); const handle = "fx-command-replay-corrupt.bin"; var corrupt = try capability.createExclusiveFile(alloc, .command_artifacts, handle); defer corrupt.deinit(); try corrupt.writeAll("not replay"); try corrupt.sync(); defer capability.delete(.command_artifacts, handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2 }}; defer blocks[0].deinit(alloc); try blocks[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "SAFE_RETAINED_FALLBACK"), }); blocks[0].total_lines = 1; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = .{ .available = .{ .handle = try alloc.dupe(u8, handle), .framed_bytes = "not replay".len, } }, .outcome = .completed, .command_output_entry_id = 2, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 10, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "SAFE_RETAINED_FALLBACK") != null); try std.testing.expect(std.mem.indexOf(u8, source, "│ … full output unavailable") != null); try std.testing.expect(std.mem.indexOf( u8, source, "available when command finishes", ) == null); } test "unavailable replay extracts a grammar-valid inline command fallback" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe( u8, "exit_code=0\n\nINLINE_COMMAND_FALLBACK\n\n", ), .command_output_replay = .unavailable, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 10, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "│ INLINE_COMMAND_FALLBACK") != null); try std.testing.expect(std.mem.indexOf(u8, source, "exit_code=0") == null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); try std.testing.expect(std.mem.indexOf(u8, source, "Full saved result unavailable") == null); try std.testing.expect(std.mem.indexOf(u8, source, "│ … full output unavailable") != null); } test "unavailable replay terminal-safes an ambiguous inline command fallback" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe( u8, "exit_code=0\n\n\x1b[2JAMBIGUOUS_INLINE\n\ntrailing bytes\n", ), .command_output_replay = .unavailable, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 12, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "AMBIGUOUS_INLINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "\x1b[2J") == null); try std.testing.expect(std.mem.indexOf(u8, source, "\\x1b") != null); try std.testing.expect(std.mem.indexOf(u8, source, "Full saved result unavailable") == null); try std.testing.expect(std.mem.indexOf(u8, source, "│ … full output unavailable") != null); } test "stored command detail keeps one normal gap before a following assistant" { const alloc = std.testing.allocator; var entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }, .{ .assistant_turn = .{ .id = 2, .segments = .{} } }, }; try entries[1].assistant_turn.segments.text.appendSlice(alloc, "AFTER_COMMAND"); defer entries[1].deinit(alloc); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe( u8, "exit_code=0\n\nCOMMAND_RESULT\n\n", ), .command_output_replay = .unavailable, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 20, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf( u8, source, "│ … full output unavailable\n\n AFTER_COMMAND", ) != null); try std.testing.expect(std.mem.indexOf( u8, source, "│ … full output unavailable\n\n\n AFTER_COMMAND", ) == null); } test "deferred command replay keeps one normal gap before a following assistant" { const alloc = std.testing.allocator; var entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact placeholder\n"), .class = .command_output, } }, .{ .assistant_turn = .{ .id = 3, .segments = .{} } }, }; try entries[2].assistant_turn.segments.text.appendSlice(alloc, "AFTER_DEFERRED_COMMAND"); defer entries[2].deinit(alloc); var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .total_lines = 1, .retention_overflow = true, }}; defer blocks[0].deinit(alloc); try blocks[0].pruned_ranges.append(alloc, .{ .anchor_entry_id = 2, .start_record = 0, .end_record = 1, }); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe(u8, "exit_code=0\n\nDEFERRED_RESULT\n\n"), .command_output_replay = .unavailable, .command_output_entry_id = 2, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 20, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf( u8, source, "│ … full output unavailable\n\n AFTER_DEFERRED_COMMAND", ) != null); try std.testing.expect(std.mem.indexOf( u8, source, "│ … full output unavailable\n\n\n AFTER_DEFERRED_COMMAND", ) == null); } test "legacy command result without replay does not claim permanent loss" { const alloc = std.testing.allocator; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran legacy command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe(u8, "preflight result \x1b[2JLEGACY_COMMAND_RESULT"), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 10, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "LEGACY_COMMAND_RESULT") != null); try std.testing.expect(std.mem.indexOf(u8, source, "\x1b[2J") == null); try std.testing.expect(std.mem.indexOf(u8, source, "\\x1b") != null); try std.testing.expect(std.mem.indexOf(u8, source, "full output unavailable") == null); } test "bounded command source rejects a truncated absolute record range" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); const handle = "fx-command-artifact-short-range.bin"; var artifact = try capability.createExclusiveFile(alloc, .command_artifacts, handle); defer artifact.deinit(); try artifact.writeAll("ONLY_RECORD\n"); try artifact.sync(); defer capability.delete(.command_artifacts, handle) catch {}; var walker = ProjectionRowWalker.initMeasure(80, null); try std.testing.expectError( error.CommandProjectionRecordMissing, appendCommandStoredResultContent( alloc, &walker, &capability, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, .{ .kind = .command_artifact, .handle = handle, .preview = null, .start_record = 0, .end_record = 2, }, ), ); } test "oversized newline-free replay stays paged through measurement and tail rendering" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); var chunk: [4096]u8 = undefined; @memset(&chunk, 'x'); for (0..270) |_| capture.appendAccepted(capture_alloc, .stdout, &chunk); capture.appendAccepted(capture_alloc, .stdout, "OVERSIZED_REPLAY_TAIL"); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); var bounded_memory: [512 * 1024]u8 = undefined; var bounded_alloc = std.heap.FixedBufferAllocator.init(&bounded_memory); const measurement = try measureProjection( bounded_alloc.allocator(), &projection, &capability, 80, ); try std.testing.expect(measurement.total_rows > 10_000); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 3, measurement.total_rows -| 3, ); defer alloc.free(tail); try std.testing.expect(std.mem.indexOf(u8, tail, "OVERSIZED_REPLAY_TAIL") != null); var lines = std.mem.splitScalar(u8, tail, '\n'); while (lines.next()) |line| { if (line.len == 0) continue; try std.testing.expect(std.mem.startsWith(u8, line, "│ ")); } } test "oversized replay keeps shared orphan wrapping in the paged record" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); var chunk: [4096]u8 = undefined; @memset(&chunk, 'x'); for (0..49) |_| capture.appendAccepted(capture_alloc, .stdout, &chunk); capture.appendAccepted(capture_alloc, .stdout, "xxxxxxxx aaa bbb ccc ddd\n"); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 14, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 14); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 14, 2, measurement.total_rows -| 2, ); defer alloc.free(tail); var logical_record: std.ArrayList(u8) = .empty; defer logical_record.deinit(alloc); try logical_record.appendNTimes(alloc, 'x', 49 * chunk.len + 8); try logical_record.appendSlice(alloc, " aaa bbb ccc ddd"); const expected = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, logical_record.items, 14, ); defer alloc.free(expected); const final_separator = std.mem.findScalarLast(u8, expected[0 .. expected.len - 1], '\n') orelse return error.TestExpectedWrappedRecord; const prior_separator = std.mem.findScalarLast(u8, expected[0..final_separator], '\n') orelse return error.TestExpectedWrappedRecord; try std.testing.expectEqualStrings(expected[prior_separator + 1 ..], tail); } test "oversized zero width replay has bounded measurement and visible output" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); capture.appendAccepted(capture_alloc, .stdout, "a"); var combining_chunk: [4096]u8 = undefined; for (0..combining_chunk.len / 2) |index| { combining_chunk[index * 2] = 0xcc; combining_chunk[index * 2 + 1] = 0x81; } for (0..80) |_| capture.appendAccepted(capture_alloc, .stdout, &combining_chunk); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); var bounded_memory: [128 * 1024]u8 = undefined; var bounded_alloc = std.heap.FixedBufferAllocator.init(&bounded_memory); const measurement = try measureProjection( bounded_alloc.allocator(), &projection, &capability, 80, ); try std.testing.expect(measurement.total_rows > 1000); const selected_row = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 1, measurement.total_rows -| 1, ); defer alloc.free(selected_row); try std.testing.expect(selected_row.len < 512); const full = try renderProjectionViewportSource( alloc, &projection, &capability, 80, @intCast(measurement.total_rows), 0, ); defer alloc.free(full); try std.testing.expectEqual( @as(usize, 80 * (combining_chunk.len / 2)), std.mem.count(u8, full, "\xcc\x81"), ); } test "oversized interleaved replay preserves more than sixty four record ordinals" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); var capture_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer capture_arena.deinit(); const capture_alloc = capture_arena.allocator(); const capture = try command_replay_store.Capture.create(capture_alloc, 8, &capability); capture.appendAccepted(capture_alloc, .stdout, "\xc3"); var stderr_record: std.ArrayList(u8) = .empty; defer stderr_record.deinit(alloc); for (0..100) |index| { stderr_record.clearRetainingCapacity(); var prefix_buffer: [16]u8 = undefined; const prefix = try std.fmt.bufPrint(&prefix_buffer, "E{d:0>3}-", .{index}); try stderr_record.appendSlice(alloc, prefix); try stderr_record.appendNTimes(alloc, 'x', 2048); if (index == 99) try stderr_record.appendSlice(alloc, "-INTERLEAVED_TAIL"); try stderr_record.append(alloc, '\n'); capture.appendAccepted(capture_alloc, .stderr, stderr_record.items); } capture.appendAccepted(capture_alloc, .stdout, "\xa9 progress\rDONE\n"); capture.appendAccepted(capture_alloc, .stdout, "\x1b[31m\x1b[0m"); const replay = capture.retain(capture_alloc) orelse return error.TestExpectedReplay; const descriptor = switch (replay) { .available => |value| value, .unavailable => return error.TestExpectedAvailableReplay, }; defer capability.delete(.command_artifacts, descriptor.handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .command_output_replay = try types.dupeCommandOutputReplay(alloc, replay), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); var bounded_memory: [512 * 1024]u8 = undefined; var bounded_alloc = std.heap.FixedBufferAllocator.init(&bounded_memory); const measurement = try measureProjection( bounded_alloc.allocator(), &projection, &capability, 80, ); const head = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 8, 0); defer alloc.free(head); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 4, measurement.total_rows -| 4, ); defer alloc.free(tail); const done_index = std.mem.indexOf(u8, head, "│ DONE") orelse return error.TestExpectedStdout; const first_stderr_index = std.mem.indexOf(u8, head, "│ E000-") orelse return error.TestExpectedStderr; try std.testing.expect(done_index < first_stderr_index); try std.testing.expect(std.mem.indexOf(u8, head, "progress") == null); try std.testing.expect(std.mem.indexOf(u8, tail, "INTERLEAVED_TAIL") != null); try std.testing.expect(std.mem.indexOf(u8, tail, "\x1b") == null); } test "opaque command sources back a stored artifact without a duplicate static row" { const alloc = std.testing.allocator; const marker = "│ OPAQUE_RETAINED_COMMAND\n"; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast(marker), .class = .command_output, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .total_lines = 1, }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.append(alloc, 2); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result = try alloc.dupe(u8, "bounded preview"), .command_artifact_handle = try alloc.dupe(u8, "missing-command.log"), .command_output_entry_id = 2, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); var stored_segments: usize = 0; for (projection.segments.items) |segment| switch (segment) { .static => |bytes| try std.testing.expect(std.mem.indexOf(u8, bytes, marker) == null), .stored_result => |stored| { stored_segments += 1; const retained = stored.retained_command_fallback orelse return error.TestExpectedRetainedCommandFallback; try std.testing.expectEqualStrings(marker, retained); }, }; try std.testing.expectEqual(@as(usize, 1), stored_segments); const degraded = try renderProjectionViewportSource(alloc, &projection, null, 80, 8, 0); defer alloc.free(degraded); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, degraded, marker)); } test "stored result projection yields a terminal-safe source window for the shared painter" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "shared-source", "read_file", "README.md\n\nFIRST_SOURCE_LINE\nSECOND_SOURCE_LINE\nTHIRD_SOURCE_LINE\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "before\n") }); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = null, } }); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "after\n") }); const source = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 5, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "before") != null); try std.testing.expect(std.mem.indexOf(u8, source, "FIRST_SOURCE_LINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "SECOND_SOURCE_LINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "THIRD_SOURCE_LINE") != null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); try std.testing.expect(std.mem.indexOf(u8, source, "\\x0a") == null); } test "stored tool result keeps every physical rail primary and body secondary" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "styled-source", "read_file", "README.md\n\nalpha beta gamma delta epsilon\nsecond row\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; const reset = "\x1b[39m"; const dim = "\x1b[38;5;245m"; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = reset, .dim_style = dim, .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .kind = .tool_result, .handle = handle, .preview = null, .line_prefix = "│ ", } }); const measurement = try measureProjection(alloc, &projection, &capability, 16); const source = try renderProjectionViewportSource( alloc, &projection, &capability, 16, @intCast(measurement.total_rows), 0, ); defer alloc.free(source); try std.testing.expect(measurement.total_rows >= 3); const styled_rows = std.mem.count(u8, source, reset ++ "│" ++ dim); try std.testing.expectEqual( @as(usize, measurement.total_rows), styled_rows, ); try std.testing.expect(std.mem.indexOf(u8, source, dim ++ "│") == null); try std.testing.expect(std.mem.endsWith( u8, std.mem.trimEnd(u8, source, "\n"), reset, )); } test "missing stored result renders the retained preview and partial notice" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = "missing-result.txt", .preview = "retained preview", } }); const source = try renderProjectionViewportSource(alloc, &projection, null, 80, 3, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "retained preview") != null); try std.testing.expect(std.mem.indexOf(u8, source, "Full saved result unavailable.") != null); } test "missing command artifact uses the retained tool result sidecar" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); const fallback_handle = try result_store.storeLargeResultManaged( alloc, &capability, "command-fallback", "run_command", "exit_code=0\n\nRETAINED_COMMAND_FALLBACK\n\n", ); defer alloc.free(fallback_handle); defer result_store.deleteManaged(&capability, fallback_handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .stored_result = .{ .kind = .command_artifact, .handle = "fx-command-missing.log", .preview = "preview", .fallback_handle = fallback_handle, } }); const source = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 3, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "RETAINED_COMMAND_FALLBACK") != null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); try std.testing.expect(std.mem.indexOf(u8, source, "Full saved result unavailable.") == null); } test "paged command result removes an envelope split across source pages" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); const prefix = "exit_code=0\n\n"; const tail_marker = "PAGED_RESULT_TAIL"; const body_len = result_store.full_read_chunk_bytes - 2 - prefix.len; var result: std.ArrayList(u8) = .empty; defer result.deinit(alloc); try result.appendSlice(alloc, prefix); try result.appendNTimes(alloc, 'x', body_len - tail_marker.len); try result.appendSlice(alloc, tail_marker); try result.appendSlice(alloc, "\n\n"); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "paged-command-result", "run_command", result.items, ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{.{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran command\n"), .class = .tool_status, } }}; var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result_handle = try alloc.dupe(u8, handle), .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &.{}, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const measurement = try measureProjection(alloc, &projection, &capability, 80); const head = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 3, 0); defer alloc.free(head); const tail = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 3, measurement.total_rows -| 3, ); defer alloc.free(tail); try std.testing.expect(std.mem.indexOf(u8, head, "exit_code=0") == null); try std.testing.expect(std.mem.indexOf(u8, head, "") == null); try std.testing.expect(std.mem.indexOf(u8, tail, tail_marker) != null); try std.testing.expect(std.mem.indexOf(u8, tail, "") == null); } test "resumed command detail pages its exact result handle without replay" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDir( io_mod.getIo(), "session", std.Io.File.Permissions.fromMode(0o700), ); var session_dir = try tmp.dir.openDir(io_mod.getIo(), "session", .{ .iterate = true, .follow_symlinks = false, }); defer session_dir.close(io_mod.getIo()); const session_path = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "session"); defer alloc.free(session_path); var capability = try session_child_store.SessionChildCapability.initForTesting( alloc, session_dir, session_path, .writable, .{}, ); defer capability.deinit(); const handle = try result_store.storeLargeResultManaged( alloc, &capability, "resumed-command-result", "run_command", "exit_code=0\n\nRESUMED_EXACT_RESULT\n\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; const entries = [_]transcript_blocks.TranscriptEntry{ .{ .raw_bytes = .{ .id = 1, .created_at_ms = 0, .bytes = @constCast("● Ran resumed command\n"), .class = .tool_status, } }, .{ .raw_bytes = .{ .id = 2, .created_at_ms = 0, .bytes = @constCast("│ compact resumed placeholder\n"), .class = .command_output, } }, }; var blocks = [_]command_output_runtime.CommandOutputBlock{.{ .entry_id = 2, .total_lines = 1, }}; defer blocks[0].deinit(alloc); try blocks[0].source_entry_ids.append(alloc, 2); var details = [_]ToolDetailRecord{.{ .entry_id = 1, .tool_name = try alloc.dupe(u8, "run_command"), .result_handle = try alloc.dupe(u8, handle), .command_output_entry_id = 2, .outcome = .completed, }}; defer details[0].deinit(alloc); var projection = try buildProjection( alloc, &entries, &details, &blocks, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "" }, 80, null, ); defer projection.deinit(alloc); const source = try renderProjectionViewportSource(alloc, &projection, &capability, 80, 10, 0); defer alloc.free(source); try std.testing.expect(std.mem.indexOf(u8, source, "RESUMED_EXACT_RESULT") != null); try std.testing.expect(std.mem.indexOf(u8, source, "compact resumed placeholder") == null); try std.testing.expect(std.mem.indexOf(u8, source, "exit_code=0") == null); try std.testing.expect(std.mem.indexOf(u8, source, "") == null); } test "projection measurement continues across a stored segment boundary" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); try tmp.dir.createDirPath(io_mod.getIo(), "results"); const result_dir = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "results"); defer alloc.free(result_dir); var capability = try session_child_store.SessionChildCapability.initLegacyRoute( alloc, result_dir, .tool_results, .writable, ); defer capability.deinit(); // Envelope trimming leaves the stored segment ending mid-row. const handle = try result_store.storeLargeResultManaged( alloc, &capability, "boundary-detail", "read_file", "x\n\nALPHA\nBRAVO\n", ); defer alloc.free(handle); defer result_store.deleteManaged(&capability, handle) catch {}; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "before\n") }); try projection.segments.append(alloc, .{ .stored_result = .{ .handle = handle, .preview = null, } }); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "\nafter\n") }); // before / ALPHA / BRAVO / after: the newline opening the final static // segment terminates BRAVO's row rather than counting as a row of its own. const measurement = try measureProjection(alloc, &projection, &capability, 80); try std.testing.expectEqual(@as(u32, 4), measurement.total_rows); const last_row = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 1, measurement.total_rows - 1, ); defer alloc.free(last_row); try std.testing.expect(std.mem.indexOf(u8, last_row, "after") != null); const past_end = try renderProjectionViewportSource( alloc, &projection, &capability, 80, 1, measurement.total_rows, ); defer alloc.free(past_end); try std.testing.expectEqualStrings("", past_end); const saturated = try renderProjectionViewportSource( alloc, &projection, null, 10, std.math.maxInt(u16), std.math.maxInt(u32), ); defer alloc.free(saturated); try std.testing.expectEqualStrings("", saturated); } test "projection window applies the carriage return column reset measurement uses" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "AAAAAAAAA\rBB\n") }); const measurement = try measureProjection(alloc, &projection, null, 10); try std.testing.expectEqual(@as(u32, 1), measurement.total_rows); // The overwritten tail must not wrap onto a row past the measured document. const row = try renderProjectionViewportSource(alloc, &projection, null, 10, 1, 0); defer alloc.free(row); try std.testing.expect(std.mem.indexOf(u8, row, "BB") != null); } test "projection window applies positional tab measurement and preserves bytes" { const alloc = std.testing.allocator; const text = "1234567\tXYZ\n"; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, text) }); const measurement = try measureProjection(alloc, &projection, null, 10); try std.testing.expectEqual(@as(u32, 2), measurement.total_rows); const full = try renderProjectionViewportSource(alloc, &projection, null, 10, 2, 0); defer alloc.free(full); try std.testing.expectEqualStrings(text, full); const wrapped_tail = try renderProjectionViewportSource(alloc, &projection, null, 10, 1, 1); defer alloc.free(wrapped_tail); try std.testing.expectEqualStrings("Z\n", wrapped_tail); } test "projection window handles scroll offsets at and past the document tail" { const alloc = std.testing.allocator; var projection = Projection{ .styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", } }; defer projection.deinit(alloc); try projection.segments.append(alloc, .{ .static = try alloc.dupe(u8, "one\ntwo\nthree\n") }); const measurement = try measureProjection(alloc, &projection, null, 10); try std.testing.expectEqual(@as(u32, 3), measurement.total_rows); const tail = try renderProjectionViewportSource(alloc, &projection, null, 10, 5, 2); defer alloc.free(tail); try std.testing.expect(std.mem.indexOf(u8, tail, "three") != null); try std.testing.expect(std.mem.indexOf(u8, tail, "two") == null); const past_end = try renderProjectionViewportSource( alloc, &projection, null, 10, 5, measurement.total_rows + 100, ); defer alloc.free(past_end); try std.testing.expectEqualStrings("", past_end); } pub fn buildProjection( alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, anchor_entry_id: ?u32, ) !Projection { return buildProjectionWithDiffResolverInterruptible( alloc, entries, details, command_blocks, styles, cols, anchor_entry_id, null, null, ) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn buildProjectionWithResolver( alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, anchor_entry_id: ?u32, full_diff_resolver: ?FullDiffResolver, ) !Projection { return buildProjectionWithDiffResolverInterruptible( alloc, entries, details, command_blocks, styles, cols, anchor_entry_id, full_diff_resolver, null, ) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } fn buildProjectionWithDiffResolverInterruptible( alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, anchor_entry_id: ?u32, full_diff_resolver: ?FullDiffResolver, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !Projection { var group_projection = try tool_group_projection.buildExpandedStyledInterruptible( alloc, entries, details, cols, .{ .marker_style = user_message_card.promptMarkerStyle(), .text_style = ui_render.statusline_style, .reset_style = "\x1b[0m", }, styles, checkpoint, ); defer group_projection.deinit(alloc); return buildProjectionWithEntryActionsInterruptible( alloc, entries, details, command_blocks, styles, cols, anchor_entry_id, full_diff_resolver, group_projection.entry_actions.items, checkpoint, ); } pub fn buildProjectionWithEntryActionsInterruptible( alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, anchor_entry_id: ?u32, full_diff_resolver: ?FullDiffResolver, entry_actions: []const transcript_blocks.EntryRenderAction, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !Projection { std.debug.assert(entry_actions.len == entries.len); var builder = ProjectionBuilder.init(alloc, styles, cols); errdefer builder.deinit(); var source_index = try ProjectionSourceIndex.build(alloc, details, command_blocks, checkpoint); defer source_index.deinit(alloc); const emitted_command_blocks = try alloc.alloc(bool, command_blocks.len); defer alloc.free(emitted_command_blocks); @memset(emitted_command_blocks, false); var context = ProjectionComposeContext{ .alloc = alloc, .builder = &builder, .entries = entries, .source_index = &source_index, .entry_actions = entry_actions, .anchor_entry_id = anchor_entry_id, .emitted_command_blocks = emitted_command_blocks, .full_diff_resolver = full_diff_resolver, .cols = cols, .checkpoint = checkpoint, }; const sink = transcript_blocks.FullPresentationSink{ .context = &context, .skip_entry = ProjectionComposeContext.skipEntry, .override_kind = ProjectionComposeContext.overrideKind, .append_override = ProjectionComposeContext.appendOverride, .before_entry = ProjectionComposeContext.beforeEntry, .append_detail = ProjectionComposeContext.appendDetail, }; try transcript_blocks.renderEntriesForFullPresentationInterruptible( alloc, entries, cols, builder.styles(), &sink, builder.staticOut(), checkpoint, ); return builder.finish(); } /// Counts the visual document without materializing stored sidecars. A valid /// handle is scanned in fixed-size raw pages through the terminal-safe encoder. fn measureProjection( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, ) !ProjectionMeasurement { return measureProjectionInterruptible(alloc, projection, capability, cols, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn measureProjectionInterruptible( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, checkpoint: ?*BuildCheckpoint, ) !ProjectionMeasurement { if (projection.measurement_cols == cols) return .{ .total_rows = projection.measured_total_rows, .anchor_row = projection.measured_anchor_row, .item_rows = projection.measured_item_rows.items, }; while (true) { var item_rows: std.ArrayList(transcript_presentation.ItemRow) = .empty; defer item_rows.deinit(alloc); var segment_checkpoints: std.ArrayList(ProjectionCheckpoint) = .empty; defer segment_checkpoints.deinit(alloc); const capture_item_rows = projection.measured_item_rows.capacity >= projection.item_boundaries.items.len; const capture_segment_checkpoints = projection.measured_segment_checkpoints.capacity >= projection.segments.items.len; if (capture_item_rows) { try item_rows.ensureTotalCapacity( alloc, projection.item_boundaries.items.len, ); } if (capture_segment_checkpoints) { try segment_checkpoints.ensureTotalCapacity( alloc, projection.segments.items.len, ); } var walker = ProjectionRowWalker.initMeasure(cols, checkpoint); const anchor_row = walkProjectionSegments( alloc, projection, capability, &walker, 0, 0, if (capture_item_rows) &item_rows else null, if (capture_segment_checkpoints) &segment_checkpoints else null, ) catch |err| switch (err) { error.StoredSegmentDegraded => continue, else => |other| return other, }; projection.measured_item_rows.items.len = 0; projection.measured_item_rows.appendSliceAssumeCapacity(item_rows.items); projection.measured_segment_checkpoints.items.len = 0; projection.measured_segment_checkpoints.appendSliceAssumeCapacity( segment_checkpoints.items, ); projection.measured_total_rows = walker.totalRows(); projection.measured_anchor_row = anchor_row; projection.measurement_cols = cols; return .{ .total_rows = projection.measured_total_rows, .anchor_row = projection.measured_anchor_row, .item_rows = projection.measured_item_rows.items, }; } } fn walkProjectionSegments( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, walker: *ProjectionRowWalker, start_segment_index: usize, start_item_index: usize, item_rows: ?*std.ArrayList(transcript_presentation.ItemRow), segment_checkpoints: ?*std.ArrayList(ProjectionCheckpoint), ) !?u32 { var anchor_row: ?u32 = null; var boundary_index = start_item_index; for (projection.segments.items[start_segment_index..], start_segment_index..) |*segment, index| { if (segment_checkpoints) |captured| { captured.appendAssumeCapacity(walker.checkpoint()); } while (boundary_index < projection.item_boundaries.items.len and projection.item_boundaries.items[boundary_index].segment_index == index) { const boundary = projection.item_boundaries.items[boundary_index]; if (item_rows) |captured| captured.appendAssumeCapacity(.{ .entry_id = boundary.entry_id, .row = walker.totalRows(), }); boundary_index += 1; } if (projection.anchor_segment_index) |anchor_index| { if (anchor_index == index) anchor_row = walker.totalRows(); } const keep_scanning = switch (segment.*) { .static => |bytes| try walker.append(bytes), .stored_result => |*stored| if (stored.unavailable) try appendStoredResultFallback(alloc, walker, projection.styles, stored.*) else appendStoredResultContent(alloc, walker, capability, projection.styles, stored.*) catch |err| { if (err == error.InputPending) return err; // Rows walked so far are stale once the segment degrades. _ = degradeStoredResult(stored, err); projection.invalidateMeasurement(); return error.StoredSegmentDegraded; }, }; if (!keep_scanning) break; } if (item_rows) |captured| while (boundary_index < projection.item_boundaries.items.len) : (boundary_index += 1) { const boundary = projection.item_boundaries.items[boundary_index]; captured.appendAssumeCapacity(.{ .entry_id = boundary.entry_id, .row = walker.totalRows(), }); }; if (projection.anchor_segment_index) |anchor_index| { if (anchor_index == projection.segments.items.len) anchor_row = walker.totalRows(); } return anchor_row; } /// Single row-geometry walk (wrap rules of `visualRowsForLine`) behind both /// measurement and window extraction, so scroll bounds cannot disagree with /// the rows the window yields. A window captures rows [start_row, end_row). const ProjectionRowWalker = struct { cols: u16, row: u32 = 0, col: u16 = 1, row_has_bytes: bool = false, window: ?Window = null, build_checkpoint: ?*BuildCheckpoint = null, max_output_bytes: usize = std.math.maxInt(usize), const Window = struct { writer: std.Io.Writer.Allocating, start_row: u32, end_row: u32, }; fn initMeasure(cols: u16, build_checkpoint_ptr: ?*BuildCheckpoint) ProjectionRowWalker { return .{ .cols = @max(cols, 1), .build_checkpoint = build_checkpoint_ptr }; } fn initWindow( alloc: Allocator, cols: u16, start_row: u32, visible_rows: u16, build_checkpoint_ptr: ?*BuildCheckpoint, ) ProjectionRowWalker { return initWindowAt(alloc, cols, start_row, visible_rows, .{ .row = 0, .col = 1, .row_has_bytes = false, }, build_checkpoint_ptr); } fn initWindowAt( alloc: Allocator, cols: u16, start_row: u32, visible_rows: u32, start_checkpoint: ProjectionCheckpoint, build_checkpoint_ptr: ?*BuildCheckpoint, ) ProjectionRowWalker { return .{ .cols = @max(cols, 1), .row = start_checkpoint.row, .col = start_checkpoint.col, .row_has_bytes = start_checkpoint.row_has_bytes, .build_checkpoint = build_checkpoint_ptr, .window = .{ .writer = .init(alloc), .start_row = start_row, .end_row = start_row +| visible_rows, }, }; } fn checkpoint(self: *const ProjectionRowWalker) ProjectionCheckpoint { return .{ .row = self.row, .col = self.col, .row_has_bytes = self.row_has_bytes, }; } fn deinit(self: *ProjectionRowWalker) void { if (self.window) |*window| window.writer.deinit(); self.* = undefined; } /// Rows the walked content occupies so far; a final partial row counts. fn totalRows(self: *const ProjectionRowWalker) u32 { return self.row +| @intFromBool(self.row_has_bytes); } fn windowFilled(self: *const ProjectionRowWalker) bool { const window = self.window orelse return false; return self.row >= window.end_row; } fn emit(self: *ProjectionRowWalker, bytes: []const u8) !void { if (self.window) |*window| { if (self.row >= window.start_row) { if (bytes.len > self.max_output_bytes -| window.writer.written().len) { return error.PreparedWindowTooLarge; } try window.writer.writer.writeAll(bytes); } } } /// Returns false once the armed window is fully captured. fn append(self: *ProjectionRowWalker, bytes: []const u8) !bool { return self.appendWithSoftWrapPrefix(bytes, ""); } fn appendWithSoftWrapPrefix( self: *ProjectionRowWalker, bytes: []const u8, soft_wrap_prefix: []const u8, ) !bool { var index: usize = 0; while (index < bytes.len) { try build_checkpoint.tick(self.build_checkpoint); if (self.windowFilled()) return false; const ch = bytes[index]; if (ch == 0x1b) { const end = display_width.ansiSequenceEnd(bytes, index); try self.emit(bytes[index..end]); self.row_has_bytes = true; index = end; continue; } if (ch == '\n') { try self.emit(bytes[index .. index + 1]); self.row +|= 1; self.col = 1; self.row_has_bytes = false; index += 1; continue; } if (ch == '\r') { try self.emit(bytes[index .. index + 1]); self.col = 1; self.row_has_bytes = true; index += 1; continue; } if (ch == '\t') { try self.emit(bytes[index .. index + 1]); self.col = display_width.nextTabStopColumn(self.col, self.cols); self.row_has_bytes = true; index += 1; continue; } if (ch < 32) { try self.emit(bytes[index .. index + 1]); self.row_has_bytes = true; index += 1; continue; } const unit = display_width.displayUnitAt(bytes, index); const width = unit.cell_width; if (width > 0 and display_width.shouldWrapAt(self.col, @intCast(width), self.cols)) { self.row +|= 1; self.col = 1; self.row_has_bytes = false; if (self.windowFilled()) return false; const prefix_width = display_width.visibleWidthIgnoringAnsi(soft_wrap_prefix); if (prefix_width > 0 and prefix_width + width <= self.cols) { try self.emit(soft_wrap_prefix); self.col = 1 + @as(u16, @intCast(prefix_width)); self.row_has_bytes = true; } } try self.emit(bytes[index .. index + unit.byte_len]); self.row_has_bytes = true; if (width > 0) self.col +|= @intCast(width); index += unit.byte_len; } return !self.windowFilled(); } fn toOwnedSlice(self: *ProjectionRowWalker) ![]u8 { return self.window.?.writer.toOwnedSlice(); } }; const StoredResultRange = struct { start: usize, end: usize, }; const CommandBodyRange = struct { stream: command_output_content.Stream, start: usize, end: usize, }; const PagedReaderCursor = struct { reader: *StoredResultReader, checkpoint: ?*BuildCheckpoint, page: ?[]u8 = null, page_start: usize = 0, fn deinit(self: *PagedReaderCursor, alloc: Allocator) void { if (self.page) |page| alloc.free(page); self.* = undefined; } fn byteAt(self: *PagedReaderCursor, alloc: Allocator, offset: usize) !u8 { if (offset >= self.reader.size()) return error.UnexpectedEndOfResult; try self.ensurePage(alloc, offset); return self.page.?[offset - self.page_start]; } fn startsWithAt( self: *PagedReaderCursor, alloc: Allocator, offset: usize, expected: []const u8, ) !bool { const end = std.math.add(usize, offset, expected.len) catch return false; if (end > self.reader.size()) return false; for (expected, 0..) |byte, index| { if (try self.byteAt(alloc, offset + index) != byte) return false; } return true; } fn findFrom( self: *PagedReaderCursor, alloc: Allocator, start: usize, needle: []const u8, ) !?usize { if (needle.len == 0) return start; var offset = start; while (offset < self.reader.size()) : (offset += 1) { try build_checkpoint.tick(self.checkpoint); if (try self.startsWithAt(alloc, offset, needle)) return offset; } return null; } fn ensurePage(self: *PagedReaderCursor, alloc: Allocator, offset: usize) !void { if (self.page) |page| { if (offset >= self.page_start and offset < self.page_start + page.len) return; alloc.free(page); self.page = null; } self.page_start = offset; const page = try self.reader.readPage( alloc, offset, @min(result_store.full_read_chunk_bytes, self.reader.size() - offset), ); if (page.len == 0) { alloc.free(page); return error.UnexpectedEndOfResult; } self.page = page; } }; const CommandBodyRanges = struct { items: [2]CommandBodyRange = undefined, len: usize = 0, fn append(self: *CommandBodyRanges, range: CommandBodyRange) void { std.debug.assert(self.len < self.items.len); self.items[self.len] = range; self.len += 1; } }; fn commandResultBodyRanges( alloc: Allocator, reader: *StoredResultReader, checkpoint: ?*BuildCheckpoint, ) !CommandBodyRanges { var cursor = PagedReaderCursor{ .reader = reader, .checkpoint = checkpoint }; defer cursor.deinit(alloc); const status_end = try cursor.findFrom(alloc, 0, "\n") orelse return error.InvalidCommandResultEnvelope; if (!try validForegroundStatusRange(alloc, &cursor, status_end)) { return error.InvalidCommandResultEnvelope; } var offset = status_end + 1; if (try cursor.startsWithAt(alloc, offset, "(no output)\n")) { if (offset + "(no output)\n".len != reader.size()) { return error.InvalidCommandResultEnvelope; } return .{}; } var ranges = CommandBodyRanges{}; for ([_]command_output_content.Stream{ .stdout, .stderr }) |stream| { const label = @tagName(stream); var open_buffer: [16]u8 = undefined; const open = std.fmt.bufPrint(&open_buffer, "<{s}>\n", .{label}) catch unreachable; if (!try cursor.startsWithAt(alloc, offset, open)) continue; const body_start = offset + open.len; var close_buffer: [20]u8 = undefined; const close = std.fmt.bufPrint(&close_buffer, "\n\n", .{label}) catch unreachable; const close_start = try cursor.findFrom(alloc, body_start, close) orelse return error.InvalidCommandResultEnvelope; ranges.append(.{ .stream = stream, .start = body_start, .end = close_start, }); offset = close_start + close.len; } if (ranges.len == 0 or offset != reader.size()) { return error.InvalidCommandResultEnvelope; } return ranges; } fn validForegroundStatusRange( alloc: Allocator, cursor: *PagedReaderCursor, status_end: usize, ) !bool { if (status_end > 64) return false; var status_buffer: [64]u8 = undefined; for (0..status_end) |index| { status_buffer[index] = try cursor.byteAt(alloc, index); } return command_output_content.validForegroundStatus(status_buffer[0..status_end]); } const CommandFrame = struct { stream: command_output_content.Stream, payload: []u8, }; const RangedCommandFrameReader = struct { reader: StoredResultReader, ranges: CommandBodyRanges, range_index: usize = 0, offset: usize = 0, fn deinit(self: *RangedCommandFrameReader) void { self.reader.deinit(); self.* = undefined; } fn next(self: *RangedCommandFrameReader, alloc: Allocator) !?CommandFrame { while (self.range_index < self.ranges.len) { const range = self.ranges.items[self.range_index]; if (self.offset == 0) self.offset = range.start; if (self.offset >= range.end) { self.range_index += 1; self.offset = 0; continue; } const page = try self.reader.readPage( alloc, self.offset, @min(result_store.full_read_chunk_bytes, range.end - self.offset), ); errdefer alloc.free(page); if (page.len == 0) return error.UnexpectedEndOfResult; self.offset += page.len; return .{ .stream = range.stream, .payload = page }; } return null; } }; const CommandFrameReader = union(enum) { replay: command_replay_store.Reader, ranged: RangedCommandFrameReader, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, checkpoint: ?*BuildCheckpoint, ) !CommandFrameReader { var source: CommandFrameReader = undefined; try initInto(&source, alloc, capability, stored, checkpoint); return source; } // noinline keeps the comptime-known error returns behind a call // boundary; inlined into a `!CommandFrameReader` result location they // each materialize a union-sized (~8KB) error-union constant. noinline fn initInto( out: *CommandFrameReader, alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, checkpoint: ?*BuildCheckpoint, ) !void { const managed = capability orelse return error.ResultHandleUnavailable; switch (stored.kind) { .command_replay => out.* = .{ .replay = try command_replay_store.Reader.open( alloc, managed, .{ .handle = stored.handle, .framed_bytes = stored.framed_bytes }, ) }, .command_artifact, .command_result => { var reader = try openStoredResultReader(alloc, capability, stored); errdefer reader.deinit(); var ranges = CommandBodyRanges{}; if (stored.kind == .command_result) { ranges = try commandResultBodyRanges(alloc, &reader, checkpoint); } else { ranges.append(.{ .stream = .stdout, .start = 0, .end = reader.size(), }); } out.* = .{ .ranged = .{ .reader = reader, .ranges = ranges, } }; }, .tool_result => return error.NotCommandStoredResult, } } fn deinit(self: *CommandFrameReader) void { switch (self.*) { .replay => |*reader| reader.deinit(), .ranged => |*reader| reader.deinit(), } self.* = undefined; } fn next(self: *CommandFrameReader, alloc: Allocator) !?CommandFrame { return switch (self.*) { .replay => |*reader| if (try reader.next(alloc)) |frame| .{ .stream = frame.stream, .payload = frame.payload } else null, .ranged => |*reader| reader.next(alloc), }; } }; const command_projection_scratch_bytes: usize = 192 * 1024; const command_record_exact_bytes: usize = 16 * 1024; fn appendCommandStoredResultContent( alloc: Allocator, walker: *ProjectionRowWalker, capability: ?*session_child_store.SessionChildCapability, styles: transcript_blocks.Styles, stored: StoredResult, ) !bool { if (try appendBoundedCommandSource(alloc, walker, capability, styles, stored)) |keep_scanning| { return keep_scanning; } return appendMergedCommandSource(alloc, walker, capability, styles, stored); } /// Returns null when canonical content exceeds the bounded scratch budget. fn appendBoundedCommandSource( alloc: Allocator, walker: *ProjectionRowWalker, capability: ?*session_child_store.SessionChildCapability, styles: transcript_blocks.Styles, stored: StoredResult, ) !?bool { if (stored.kind == .command_replay and stored.framed_bytes > command_projection_scratch_bytes) { return null; } const scratch = alloc.alloc(u8, command_projection_scratch_bytes) catch |err| switch (err) { error.OutOfMemory => return null, }; defer alloc.free(scratch); var scratch_alloc = std.heap.FixedBufferAllocator.init(scratch); var source = try CommandFrameReader.init(alloc, capability, stored, walker.build_checkpoint); defer source.deinit(); var output: command_output_content.CanonicalOutput = .{}; defer output.deinit(scratch_alloc.allocator()); while (try source.next(alloc)) |frame| { defer alloc.free(frame.payload); output.append(scratch_alloc.allocator(), frame.stream, frame.payload) catch |err| switch (err) { error.OutOfMemory => return null, }; } output.finish(scratch_alloc.allocator()) catch |err| switch (err) { error.OutOfMemory => return null, }; const end_record = stored.end_record orelse output.records.items.len; if (stored.start_record > output.records.items.len or end_record > output.records.items.len or stored.start_record > end_record) { return error.CommandProjectionRecordMissing; } for (output.records.items[stored.start_record..end_record]) |record| { const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, record.text.items, walker.cols, ); defer alloc.free(rendered); if (!try walker.append(rendered)) return false; if (!std.mem.endsWith(u8, rendered, "\n")) { if (!try walker.append("\n")) return false; } } return true; } const PagedLiteralCommandRecord = struct { walker: *ProjectionRowWalker, styles: transcript_blocks.Styles, exact: std.ArrayList(u8) = .empty, streaming: bool = false, pending_row: std.ArrayList(u8) = .empty, pending_separator_spaces: usize = 0, pending_valid: bool = false, row: std.ArrayList(u8) = .empty, row_width: u16 = 0, last_space_byte: ?usize = null, zero_width_run_bytes: usize = 0, emitted_any: bool = false, fn deinit(self: *PagedLiteralCommandRecord, alloc: Allocator) void { self.exact.deinit(alloc); self.pending_row.deinit(alloc); self.row.deinit(alloc); self.* = undefined; } fn append(self: *PagedLiteralCommandRecord, alloc: Allocator, text: []const u8) !void { if (!self.streaming) { if (text.len <= command_record_exact_bytes -| self.exact.items.len) { try self.exact.appendSlice(alloc, text); return; } self.streaming = true; try self.appendStreaming(alloc, self.exact.items); self.exact.clearRetainingCapacity(); } try self.appendStreaming(alloc, text); } fn appendStreaming(self: *PagedLiteralCommandRecord, alloc: Allocator, text: []const u8) !void { var offset: usize = 0; while (offset < text.len) { const byte = text[offset]; if (byte == '\t') { const absolute_col = self.gutterWidth() + self.row_width + 1; const next_col = display_width.nextTabStopColumn(absolute_col, self.walker.cols); const spaces = next_col -| absolute_col; self.zero_width_run_bytes = 0; try self.row.appendNTimes(alloc, ' ', spaces); self.row_width += spaces; offset += 1; continue; } const unit = display_width.displayUnitAt(text, offset); const width_usize = unit.cell_width; if (byte == ' ') { try self.appendSpace(alloc); } else if (width_usize == 0) { if (self.zero_width_run_bytes +| unit.byte_len <= assistant_wrap.literal_command_zero_width_row_byte_limit) { try self.row.appendSlice(alloc, text[offset .. offset + unit.byte_len]); self.zero_width_run_bytes += unit.byte_len; } else { try self.emitCurrentRow(alloc, 0); try self.row.appendSlice(alloc, text[offset .. offset + unit.byte_len]); self.zero_width_run_bytes = unit.byte_len; } } else { self.zero_width_run_bytes = 0; const width: u16 = @intCast(width_usize); try self.appendVisibleUnit(alloc, text[offset .. offset + unit.byte_len], width); } offset += unit.byte_len; } } fn finish(self: *PagedLiteralCommandRecord, alloc: Allocator) !void { if (!self.streaming) { const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, self.styles, self.exact.items, self.walker.cols, ); defer alloc.free(rendered); if (!try self.walker.append(rendered)) return error.WindowFilled; return; } var tail: std.ArrayList(u8) = .empty; defer tail.deinit(alloc); if (self.pending_valid) { try tail.appendSlice(alloc, self.pending_row.items); try tail.appendNTimes(alloc, ' ', self.pending_separator_spaces); } try tail.appendSlice(alloc, self.row.items); if (tail.items.len == 0 and self.emitted_any) return; const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, self.styles, tail.items, self.walker.cols, ); defer alloc.free(rendered); if (!try self.walker.append(rendered)) return error.WindowFilled; } fn reset(self: *PagedLiteralCommandRecord) void { self.exact.clearRetainingCapacity(); self.streaming = false; self.pending_row.clearRetainingCapacity(); self.pending_separator_spaces = 0; self.pending_valid = false; self.row.clearRetainingCapacity(); self.row_width = 0; self.last_space_byte = null; self.zero_width_run_bytes = 0; self.emitted_any = false; } fn appendVisibleUnit( self: *PagedLiteralCommandRecord, alloc: Allocator, bytes: []const u8, unit_width: u16, ) !void { const content_cols = self.contentCols(); var display_bytes = bytes; var display_width_cells = unit_width; if (unit_width > content_cols) { display_bytes = "?"; display_width_cells = 1; } while (self.row_width + display_width_cells > content_cols) { if (self.last_space_byte != null) { try self.wrapAtLastSpace(alloc); } else { try self.emitCurrentRow(alloc, 0); } } try self.row.appendSlice(alloc, display_bytes); self.row_width += display_width_cells; } fn appendSpace(self: *PagedLiteralCommandRecord, alloc: Allocator) !void { self.zero_width_run_bytes = 0; if (self.row_width >= self.contentCols()) { try self.emitCurrentRow(alloc, 1); return; } const space_index = self.row.items.len; try self.row.append(alloc, ' '); if (space_index > 0 and self.row.items[space_index - 1] != ' ') { self.last_space_byte = space_index; } self.row_width += 1; } fn wrapAtLastSpace(self: *PagedLiteralCommandRecord, alloc: Allocator) !void { const break_index = self.last_space_byte.?; var suffix_start = break_index; while (suffix_start < self.row.items.len and self.row.items[suffix_start] == ' ') : (suffix_start += 1) {} try self.queueRow( alloc, self.row.items[0..break_index], suffix_start - break_index, ); const suffix_len = self.row.items.len - suffix_start; std.mem.copyForwards(u8, self.row.items[0..suffix_len], self.row.items[suffix_start..]); self.row.items.len = suffix_len; self.remeasureRow(); } fn emitCurrentRow( self: *PagedLiteralCommandRecord, alloc: Allocator, separator_spaces: usize, ) !void { try self.queueRow(alloc, self.row.items, separator_spaces); self.row.clearRetainingCapacity(); self.row_width = 0; self.last_space_byte = null; } fn queueRow( self: *PagedLiteralCommandRecord, alloc: Allocator, content: []const u8, separator_spaces: usize, ) !void { if (self.pending_valid) try self.emitPendingRow(); self.pending_row.clearRetainingCapacity(); try self.pending_row.appendSlice(alloc, content); self.pending_separator_spaces = separator_spaces; self.pending_valid = true; self.emitted_any = true; } fn emitPendingRow(self: *PagedLiteralCommandRecord) !void { if (self.gutterWidth() > 0) { if (!try self.walker.append(self.styles.reset_style)) return error.WindowFilled; if (!try self.walker.append("│")) return error.WindowFilled; if (!try self.walker.append(self.styles.dim_style)) return error.WindowFilled; if (!try self.walker.append(" ")) return error.WindowFilled; } else { if (!try self.walker.append(self.styles.dim_style)) return error.WindowFilled; } if (!try self.walker.append(self.pending_row.items)) return error.WindowFilled; if (!try self.walker.append(self.styles.reset_style)) return error.WindowFilled; if (!try self.walker.append("\n")) return error.WindowFilled; self.pending_row.clearRetainingCapacity(); self.pending_separator_spaces = 0; self.pending_valid = false; } fn remeasureRow(self: *PagedLiteralCommandRecord) void { self.row_width = @intCast(@min( display_width.visibleWidthIgnoringAnsi(self.row.items), std.math.maxInt(u16), )); self.last_space_byte = null; for (self.row.items, 0..) |byte, index| { if (byte == ' ' and index > 0 and self.row.items[index - 1] != ' ') { self.last_space_byte = index; } } } fn gutterWidth(self: *const PagedLiteralCommandRecord) u16 { return if (self.walker.cols >= 3) 2 else 0; } fn contentCols(self: *const PagedLiteralCommandRecord) u16 { return @max(self.walker.cols -| self.gutterWidth(), 1); } }; test "paged command records match shared wrapping geometry" { const alloc = std.testing.allocator; const text = try alloc.alloc(u8, command_record_exact_bytes + 1); defer alloc.free(text); @memset(text, 'x'); @memcpy(text[0..11], "aa\tbbbbbbbb"); const styles = transcript_blocks.Styles{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", }; for ([_]u16{ 1, 2, 5, 10, 16, 80 }) |cols| { const expected = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, text, cols, ); defer alloc.free(expected); var walker = ProjectionRowWalker.initWindow( alloc, cols, 0, std.math.maxInt(u16), null, ); defer walker.deinit(); var projector = PagedLiteralCommandRecord{ .walker = &walker, .styles = styles, }; defer projector.deinit(alloc); try projector.append(alloc, text); try projector.finish(alloc); const actual = try walker.toOwnedSlice(); defer alloc.free(actual); try std.testing.expectEqualStrings(expected, actual); } } const TaggedCommandByte = struct { stream: command_output_content.Stream, byte: u8, }; const CommandByteReader = struct { source: CommandFrameReader, checkpoint: ?*BuildCheckpoint, frame: ?CommandFrame = null, frame_offset: usize = 0, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, checkpoint: ?*BuildCheckpoint, ) !CommandByteReader { return .{ .source = try CommandFrameReader.init(alloc, capability, stored, checkpoint), .checkpoint = checkpoint, }; } fn deinit(self: *CommandByteReader, alloc: Allocator) void { if (self.frame) |frame| alloc.free(frame.payload); self.source.deinit(); self.* = undefined; } fn next(self: *CommandByteReader, alloc: Allocator) !?TaggedCommandByte { try build_checkpoint.tick(self.checkpoint); if (self.source == .replay) { const byte = try self.source.replay.nextByte() orelse return null; return .{ .stream = byte.stream, .byte = byte.value }; } while (true) { if (self.frame) |frame| { if (self.frame_offset < frame.payload.len) { const byte = frame.payload[self.frame_offset]; self.frame_offset += 1; return .{ .stream = frame.stream, .byte = byte }; } alloc.free(frame.payload); self.frame = null; self.frame_offset = 0; } self.frame = try self.source.next(alloc) orelse return null; } } }; const RecordOrderReader = struct { bytes: CommandByteReader, decoders: [2]command_output_content.Decoder = .{ .{}, .{} }, open: [2]bool = .{ false, false }, pending_byte: ?TaggedCommandByte = null, created: ?command_output_content.Stream = null, finished: bool = false, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, checkpoint: ?*BuildCheckpoint, ) !RecordOrderReader { return .{ .bytes = try CommandByteReader.init(alloc, capability, stored, checkpoint) }; } fn deinit(self: *RecordOrderReader, alloc: Allocator) void { self.bytes.deinit(alloc); self.* = undefined; } fn nextRecord(self: *RecordOrderReader, alloc: Allocator) !?command_output_content.Stream { if (self.finished) return null; while (true) { if (self.pending_byte) |tagged| { self.pending_byte = null; try self.consume(tagged); if (self.created) |stream| { self.created = null; return stream; } continue; } const tagged = try self.bytes.next(alloc) orelse { inline for ([_]command_output_content.Stream{ .stdout, .stderr }) |stream| { var sink = RecordOrderSink{ .reader = self, .stream = stream }; try self.decoders[@intFromEnum(stream)].finish(&sink); } self.finished = true; if (self.created) |stream| { self.created = null; return stream; } return null; }; const index = @intFromEnum(tagged.stream); if (!self.open[index]) { self.open[index] = true; self.pending_byte = tagged; return tagged.stream; } try self.consume(tagged); if (self.created) |stream| { self.created = null; return stream; } } } fn consume(self: *RecordOrderReader, tagged: TaggedCommandByte) !void { const one = [_]u8{tagged.byte}; var sink = RecordOrderSink{ .reader = self, .stream = tagged.stream }; try self.decoders[@intFromEnum(tagged.stream)].append(&one, &sink); } }; const RecordOrderSink = struct { reader: *RecordOrderReader, stream: command_output_content.Stream, fn ensureOpen(self: *RecordOrderSink) void { const index = @intFromEnum(self.stream); if (self.reader.open[index]) return; self.reader.open[index] = true; self.reader.created = self.stream; } pub fn appendText(self: *RecordOrderSink, _: []const u8) !void { self.ensureOpen(); } pub fn finishLine(self: *RecordOrderSink) !void { self.ensureOpen(); self.reader.open[@intFromEnum(self.stream)] = false; } pub fn replaceLine(self: *RecordOrderSink) !void { self.ensureOpen(); } }; const RecordGeneration = struct { final_generation: usize, valid: bool, }; const StreamGenerationReader = struct { stream: command_output_content.Stream, bytes: CommandByteReader, decoder: command_output_content.Decoder = .{}, open: bool = false, generation: usize = 0, visible: bool = false, terminated: bool = false, finished: bool = false, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, stream: command_output_content.Stream, checkpoint: ?*BuildCheckpoint, ) !StreamGenerationReader { return .{ .stream = stream, .bytes = try CommandByteReader.init(alloc, capability, stored, checkpoint), }; } fn deinit(self: *StreamGenerationReader, alloc: Allocator) void { self.bytes.deinit(alloc); self.* = undefined; } fn nextRecord(self: *StreamGenerationReader, alloc: Allocator) !?RecordGeneration { if (self.finished) return null; while (try self.bytes.next(alloc)) |tagged| { if (tagged.stream != self.stream) continue; if (!self.open) self.beginRecord(); self.terminated = false; const one = [_]u8{tagged.byte}; var sink = StreamGenerationSink{ .reader = self }; try self.decoder.append(&one, &sink); if (self.terminated) return self.takeCompleted(true); } var sink = StreamGenerationSink{ .reader = self }; try self.decoder.finish(&sink); self.finished = true; if (!self.open) return null; return self.takeCompleted(false); } fn beginRecord(self: *StreamGenerationReader) void { self.open = true; self.generation = 0; self.visible = false; } fn takeCompleted(self: *StreamGenerationReader, terminated: bool) RecordGeneration { const result = RecordGeneration{ .final_generation = self.generation, .valid = terminated or self.visible, }; self.open = false; self.generation = 0; self.visible = false; self.terminated = false; return result; } }; const StreamGenerationSink = struct { reader: *StreamGenerationReader, pub fn appendText(self: *StreamGenerationSink, _: []const u8) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.visible = true; } pub fn finishLine(self: *StreamGenerationSink) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.terminated = true; } pub fn replaceLine(self: *StreamGenerationSink) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.generation += 1; self.reader.visible = false; } }; const StreamProjectionReader = struct { stream: command_output_content.Stream, bytes: CommandByteReader, decoder: command_output_content.Decoder = .{}, projector: PagedLiteralCommandRecord, open: bool = false, generation: usize = 0, visible: bool = false, terminated: bool = false, target_generation: usize = 0, emit: bool = false, finished: bool = false, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, stream: command_output_content.Stream, walker: *ProjectionRowWalker, styles: transcript_blocks.Styles, ) !StreamProjectionReader { return .{ .stream = stream, .bytes = try CommandByteReader.init(alloc, capability, stored, walker.build_checkpoint), .projector = .{ .walker = walker, .styles = styles }, }; } fn deinit(self: *StreamProjectionReader, alloc: Allocator) void { self.projector.deinit(alloc); self.bytes.deinit(alloc); self.* = undefined; } fn projectNext( self: *StreamProjectionReader, alloc: Allocator, expected: RecordGeneration, should_emit: bool, ) !void { if (self.finished) return error.CommandProjectionRecordMissing; self.target_generation = expected.final_generation; self.emit = expected.valid and should_emit; self.projector.reset(); while (try self.bytes.next(alloc)) |tagged| { if (tagged.stream != self.stream) continue; if (!self.open) self.beginRecord(); self.terminated = false; const one = [_]u8{tagged.byte}; var sink = StreamProjectionSink{ .reader = self, .alloc = alloc }; try self.decoder.append(&one, &sink); if (self.terminated) return self.completeRecord(alloc, expected, true); } var sink = StreamProjectionSink{ .reader = self, .alloc = alloc }; try self.decoder.finish(&sink); self.finished = true; if (!self.open) return error.CommandProjectionRecordMissing; return self.completeRecord(alloc, expected, false); } fn beginRecord(self: *StreamProjectionReader) void { self.open = true; self.generation = 0; self.visible = false; } fn completeRecord( self: *StreamProjectionReader, alloc: Allocator, expected: RecordGeneration, terminated: bool, ) !void { const valid = terminated or self.visible; if (self.generation != expected.final_generation or valid != expected.valid) { return error.CommandProjectionGenerationMismatch; } if (self.emit) try self.projector.finish(alloc); self.projector.reset(); self.open = false; self.generation = 0; self.visible = false; self.terminated = false; } }; const StreamProjectionSink = struct { reader: *StreamProjectionReader, alloc: Allocator, pub fn appendText(self: *StreamProjectionSink, bytes: []const u8) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.visible = true; if (self.reader.emit and self.reader.generation == self.reader.target_generation) { try self.reader.projector.append(self.alloc, bytes); } } pub fn finishLine(self: *StreamProjectionSink) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.terminated = true; } pub fn replaceLine(self: *StreamProjectionSink) !void { if (!self.reader.open) self.reader.beginRecord(); self.reader.generation += 1; self.reader.visible = false; self.reader.projector.reset(); } }; fn appendMergedCommandSource( alloc: Allocator, walker: *ProjectionRowWalker, capability: ?*session_child_store.SessionChildCapability, styles: transcript_blocks.Styles, stored: StoredResult, ) !bool { var order = try RecordOrderReader.init(alloc, capability, stored, walker.build_checkpoint); defer order.deinit(alloc); var generations = [2]StreamGenerationReader{ try .init(alloc, capability, stored, .stdout, walker.build_checkpoint), try .init(alloc, capability, stored, .stderr, walker.build_checkpoint), }; defer for (&generations) |*reader| reader.deinit(alloc); var projections = [2]StreamProjectionReader{ try .init(alloc, capability, stored, .stdout, walker, styles), try .init(alloc, capability, stored, .stderr, walker, styles), }; defer for (&projections) |*reader| reader.deinit(alloc); var record_ordinal: usize = 0; while (try order.nextRecord(alloc)) |stream| { const index = @intFromEnum(stream); const generation = try generations[index].nextRecord(alloc) orelse return error.CommandProjectionRecordMissing; const in_range = record_ordinal >= stored.start_record and (stored.end_record == null or record_ordinal < stored.end_record.?); const emit = generation.valid and in_range; projections[index].projectNext(alloc, generation, emit) catch |err| switch (err) { error.WindowFilled => return false, else => |other| return other, }; if (generation.valid) record_ordinal += 1; } if (record_ordinal < stored.start_record) return error.CommandProjectionRecordMissing; if (stored.end_record) |end_record| { if (record_ordinal < end_record) return error.CommandProjectionRecordMissing; } return true; } const StoredResultSourceStream = struct { reader: StoredResultReader, range: StoredResultRange, offset: usize, terminal_safe: TerminalSafeIndentedWriter = .{}, fn init( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, ) !StoredResultSourceStream { var reader = try openStoredResultReader(alloc, capability, stored); errdefer reader.deinit(); const range = try storedResultPresentationRange(alloc, &reader); return .{ .reader = reader, .range = range, .offset = range.start, .terminal_safe = .{ .prefix = stored.line_prefix }, }; } fn deinit(self: *StoredResultSourceStream) void { self.reader.deinit(); self.* = undefined; } fn hasMore(self: StoredResultSourceStream) bool { return self.offset < self.range.end; } fn readNextPage( self: *StoredResultSourceStream, alloc: Allocator, ) ![]u8 { std.debug.assert(self.hasMore()); const page = try self.reader.readPage( alloc, self.offset, @min(result_store.full_read_chunk_bytes, self.range.end - self.offset), ); errdefer alloc.free(page); if (page.len == 0) return error.UnexpectedEndOfResult; self.offset += page.len; return page; } fn appendPage( self: *StoredResultSourceStream, writer: *std.Io.Writer, page: []const u8, ) !void { try self.terminal_safe.append(writer, page); } fn appendTail( self: *StoredResultSourceStream, tail: *std.Io.Writer.Allocating, ) !void { try self.terminal_safe.finish(&tail.writer); } }; fn storedResultPresentationRange( alloc: Allocator, reader: *StoredResultReader, ) !StoredResultRange { switch (reader.*) { .command_artifact => return .{ .start = 0, .end = reader.size() }, .command_replay => return error.InvalidReplayPageRead, .tool_result, .command_result => {}, } const probe_len = @min(reader.size(), result_store.read_default_bytes); const prefix = try reader.readPage(alloc, 0, probe_len); defer alloc.free(prefix); const start = contentEnvelopeStart(prefix) orelse return .{ .start = 0, .end = reader.size() }; const suffix_len = @min(reader.size(), "\n".len); const suffix_start = reader.size() - suffix_len; const suffix = try reader.readPage(alloc, suffix_start, suffix_len); defer alloc.free(suffix); if (!std.mem.endsWith(u8, suffix, "")) return .{ .start = 0, .end = reader.size() }; var suffix_end = suffix.len - "".len; while (suffix_end > 0 and (suffix[suffix_end - 1] == '\n' or suffix[suffix_end - 1] == '\r')) { suffix_end -= 1; } const end = suffix_start + suffix_end; return if (end >= start) .{ .start = start, .end = end } else .{ .start = 0, .end = reader.size() }; } fn contentEnvelopeStart(body: []const u8) ?usize { var start: usize = 0; if (std.mem.startsWith(u8, body, "")) { const path_close = std.mem.find(u8, body, "") orelse return null; start = path_close + "".len; while (start < body.len and (body[start] == '\n' or body[start] == '\r')) : (start += 1) {} } if (!std.mem.startsWith(u8, body[start..], "")) return null; start += "".len; while (start < body.len and (body[start] == '\n' or body[start] == '\r')) : (start += 1) {} return start; } /// Writes terminal-safe tool detail while retaining LF as the line boundary. /// Other controls still go through the shared terminal-safe encoder. const TerminalSafeIndentedWriter = struct { encoder: text_utils.IncrementalTerminalSafeEncoder = .{}, line_start: bool = true, prefix: []const u8 = " ", line_suffix: []const u8 = "", fn append( self: *TerminalSafeIndentedWriter, writer: *std.Io.Writer, raw: []const u8, ) !void { var start: usize = 0; while (start < raw.len) { var separator = start; while (separator < raw.len and raw[separator] != '\n' and raw[separator] != '\t') : (separator += 1) {} if (separator == raw.len) break; try self.writePrefix(writer); try self.encoder.append(writer, raw[start..separator]); try self.encoder.finish(writer); if (raw[separator] == '\n') { try writer.writeAll(self.line_suffix); try writer.writeByte('\n'); self.line_start = true; } else { try writer.writeAll(" "); } start = separator + 1; } if (start < raw.len) { try self.writePrefix(writer); try self.encoder.append(writer, raw[start..]); } } fn finish(self: *TerminalSafeIndentedWriter, writer: *std.Io.Writer) !void { if (!self.line_start) { try self.encoder.finish(writer); try writer.writeAll(self.line_suffix); } } fn writePrefix(self: *TerminalSafeIndentedWriter, writer: *std.Io.Writer) !void { if (!self.line_start) return; try writer.writeAll(self.prefix); self.line_start = false; } }; fn appendStoredResultContent( alloc: Allocator, walker: *ProjectionRowWalker, capability: ?*session_child_store.SessionChildCapability, styles: transcript_blocks.Styles, stored: StoredResult, ) !bool { if (stored.kind != .tool_result) { if (!try appendCommandStoredResultContent( alloc, walker, capability, styles, stored, )) return false; if (stored.required_replay_unavailable) { return appendPermanentCommandUnavailable(walker, styles); } return true; } var source = try StoredResultSourceStream.init(alloc, capability, stored); defer source.deinit(); const styled_prefix = try styledSecondaryLinePrefix(alloc, styles, stored.line_prefix); defer alloc.free(styled_prefix); source.terminal_safe.prefix = styled_prefix; source.terminal_safe.line_suffix = styles.reset_style; while (source.hasMore()) { const page = try source.readNextPage(alloc); defer alloc.free(page); var encoded: std.Io.Writer.Allocating = .init(alloc); defer encoded.deinit(); try source.appendPage(&encoded.writer, page); if (!try walker.appendWithSoftWrapPrefix(encoded.written(), styled_prefix)) return false; } var tail: std.Io.Writer.Allocating = .init(alloc); defer tail.deinit(); try source.appendTail(&tail); return walker.appendWithSoftWrapPrefix(tail.written(), styled_prefix); } fn styledSecondaryLinePrefix( alloc: Allocator, styles: transcript_blocks.Styles, line_prefix: []const u8, ) ![]u8 { var out: std.Io.Writer.Allocating = .init(alloc); errdefer out.deinit(); try writeSecondaryLinePrefix(&out.writer, styles, line_prefix); return out.toOwnedSlice(); } fn writeSecondaryLinePrefix( writer: *std.Io.Writer, styles: transcript_blocks.Styles, line_prefix: []const u8, ) !void { if (std.mem.startsWith(u8, line_prefix, "│")) { try writer.writeAll(styles.reset_style); try writer.writeAll("│"); try writer.writeAll(styles.dim_style); try writer.writeAll(line_prefix["│".len..]); } else { try writer.writeAll(styles.dim_style); try writer.writeAll(line_prefix); } } fn beginSecondaryRailLine( writer: *std.Io.Writer, styles: transcript_blocks.Styles, ) !void { try writer.writeAll(styles.reset_style); try writer.writeAll("│"); try writer.writeAll(styles.dim_style); } fn endSecondaryRailLine( writer: *std.Io.Writer, styles: transcript_blocks.Styles, ) !void { try writer.writeAll(styles.reset_style); try writer.writeByte('\n'); } fn writeSecondaryRailLine( writer: *std.Io.Writer, styles: transcript_blocks.Styles, text: []const u8, ) !void { try beginSecondaryRailLine(writer, styles); try writer.writeAll(text); try endSecondaryRailLine(writer, styles); } fn writeSecondaryPrefixedLine( writer: *std.Io.Writer, styles: transcript_blocks.Styles, prefix: []const u8, text: []const u8, ) !void { try writeSecondaryLinePrefix(writer, styles, prefix); try writer.writeAll(text); try writer.writeAll(styles.reset_style); try writer.writeByte('\n'); } fn appendStoredResultFallback( alloc: Allocator, walker: *ProjectionRowWalker, styles: transcript_blocks.Styles, stored: StoredResult, ) !bool { const styled_prefix = try styledSecondaryLinePrefix(alloc, styles, stored.line_prefix); defer alloc.free(styled_prefix); if (stored.required_replay_unavailable) { if (stored.retained_command_fallback) |retained| { if (!try walker.append(retained)) return false; } else { const fallback = try storedResultFallbackBytes( alloc, styles, stored, styled_prefix, ); defer alloc.free(fallback); if (!try walker.appendWithSoftWrapPrefix(fallback, styled_prefix)) return false; } return appendPermanentCommandUnavailable(walker, styles); } const fallback = try storedResultFallbackBytes( alloc, styles, stored, styled_prefix, ); defer alloc.free(fallback); if (!try walker.appendWithSoftWrapPrefix(fallback, styled_prefix)) return false; if (stored.retained_command_fallback) |retained| return walker.append(retained); return true; } fn appendPermanentCommandUnavailable( walker: *ProjectionRowWalker, styles: transcript_blocks.Styles, ) !bool { if (!try walker.append(styles.reset_style)) return false; if (!try walker.append("│")) return false; if (!try walker.append(styles.dim_style)) return false; if (!try walker.append(" … full output unavailable")) return false; if (!try walker.append(styles.reset_style)) return false; return walker.append("\n"); } fn openStoredResultReader( alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, ) !StoredResultReader { var reader: StoredResultReader = undefined; try openStoredResultReaderInto(&reader, alloc, capability, stored); return reader; } // noinline keeps the comptime-known error returns behind a call boundary; // inlined into a `!StoredResultReader` result location they each materialize // a union-sized (~8KB) error-union constant. noinline fn openStoredResultReaderInto( out: *StoredResultReader, alloc: Allocator, capability: ?*session_child_store.SessionChildCapability, stored: StoredResult, ) !void { const managed = capability orelse return error.ResultHandleUnavailable; switch (stored.kind) { .tool_result => out.* = .{ .tool_result = try result_store.openReaderManaged(alloc, managed, stored.handle) }, .command_result => out.* = .{ .command_result = try result_store.openReaderManaged(alloc, managed, stored.handle) }, .command_artifact => { var file = try managed.openFileReadOnly(alloc, .command_artifacts, stored.handle); errdefer file.deinit(); const stat = try file.stat(); const size = std.math.cast(usize, stat.size) orelse return error.ResultTooLarge; out.* = .{ .command_artifact = .{ .file = file, .size = size } }; }, .command_replay => out.* = .{ .command_replay = try command_replay_store.Reader.open( alloc, managed, .{ .handle = stored.handle, .framed_bytes = stored.framed_bytes }, ) }, } } fn activateStoredResultFallback(stored: *StoredResult, err: anyerror) bool { if (stored.kind == .command_replay) { stored.required_replay_unavailable = true; if (stored.fallback_artifact_handle) |artifact_handle| { debug_trace.logf( "full_transcript", "command_replay_unavailable handle_bytes={d} err={s}; using command artifact fallback", .{ stored.handle.len, @errorName(err) }, ); stored.kind = .command_artifact; stored.handle = artifact_handle; stored.fallback_artifact_handle = null; return true; } if (stored.fallback_handle) |result_handle| { debug_trace.logf( "full_transcript", "command_replay_unavailable handle_bytes={d} err={s}; using stored result fallback", .{ stored.handle.len, @errorName(err) }, ); stored.kind = .command_result; stored.handle = result_handle; stored.fallback_handle = null; return true; } return false; } if (stored.kind != .command_artifact) return false; const fallback_handle = stored.fallback_handle orelse return false; debug_trace.logf( "full_transcript", "command_artifact_unavailable handle_bytes={d} err={s}; using stored result fallback", .{ stored.handle.len, @errorName(err) }, ); stored.kind = .command_result; stored.handle = fallback_handle; stored.fallback_handle = null; return true; } const StoredResultDegradation = enum { retry, unavailable }; /// One-way (command artifact, then retained tool result, then unavailable), /// which bounds the measurement retry and the render restart. fn degradeStoredResult(stored: *StoredResult, err: anyerror) StoredResultDegradation { if (activateStoredResultFallback(stored, err)) return .retry; stored.unavailable = true; logStoredResultUnavailable(stored.handle, err); return .unavailable; } fn storedResultFallbackBytes( alloc: Allocator, styles: transcript_blocks.Styles, stored: StoredResult, styled_prefix: []const u8, ) ![]u8 { var out: std.Io.Writer.Allocating = .init(alloc); errdefer out.deinit(); try out.writer.writeAll(styles.reset_style); var terminal_safe = TerminalSafeIndentedWriter{ .prefix = styled_prefix, .line_suffix = styles.reset_style, }; try terminal_safe.append( &out.writer, tool_result_display.contentForDisplay(stored.preview orelse ""), ); try terminal_safe.finish(&out.writer); if (!terminal_safe.line_start) try out.writer.writeByte('\n'); try writeSecondaryPrefixedLine( &out.writer, styles, stored.line_prefix, "Full saved result unavailable.", ); return out.toOwnedSlice(); } fn logStoredResultUnavailable(handle: []const u8, err: anyerror) void { debug_trace.logf( "full_transcript", "stored_result_unavailable handle_bytes={d} err={s}", .{ handle.len, @errorName(err) }, ); } /// Reads the selected Ctrl-O visual window as normal terminal source bytes. /// The caller sends these bytes through the same prepared-transcript painter /// that renders compact inline output; this helper never constructs a grid. /// The window emits only rows the document reaches, so an offset at or past /// the document end yields an empty window. fn renderProjectionViewportSource( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, scroll_offset: u32, ) ![]u8 { return renderProjectionViewportSourceInterruptible( alloc, projection, capability, cols, visible_rows, scroll_offset, null, ) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn renderProjectionViewportSourceInterruptible( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, scroll_offset: u32, checkpoint: ?*BuildCheckpoint, ) ![]u8 { return renderProjectionViewportSourceWithSelection( alloc, projection, capability, cols, visible_rows, .{ .fixed_offset = scroll_offset }, checkpoint, std.math.maxInt(usize), ); } pub fn renderProjectionViewportSourceBoundedInterruptible( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, scroll_offset: u32, max_bytes: usize, checkpoint: ?*BuildCheckpoint, ) ![]u8 { return renderProjectionViewportSourceWithSelection( alloc, projection, capability, cols, visible_rows, .{ .fixed_offset = scroll_offset }, checkpoint, max_bytes, ); } /// Measures the projection, lets the selector pick the scroll offset against /// that same-walk measurement, and reads the selected window. A stored segment /// degrading during the window walk restarts the whole pipeline, so the /// emitted window always matches the document the offset was selected for. fn renderProjectionViewportSourceWithSelector( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, offset_selector: ViewportOffsetSelector, ) ![]u8 { return renderProjectionViewportSourceWithSelectorInterruptible( alloc, projection, capability, cols, visible_rows, offset_selector, null, ) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn renderProjectionViewportSourceWithSelectorInterruptible( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, offset_selector: ViewportOffsetSelector, checkpoint: ?*BuildCheckpoint, ) ![]u8 { return renderProjectionViewportSourceWithSelection( alloc, projection, capability, cols, visible_rows, .{ .selector = offset_selector }, checkpoint, std.math.maxInt(usize), ); } const ViewportSelection = union(enum) { fixed_offset: u32, selector: ViewportOffsetSelector, }; fn renderProjectionViewportSourceWithSelection( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, selection: ViewportSelection, checkpoint: ?*BuildCheckpoint, max_bytes: usize, ) ![]u8 { if (cols == 0 or visible_rows == 0) return error.InvalidViewport; while (true) { const offset = switch (selection) { .fixed_offset => |fixed_offset| fixed_offset, .selector => |selector| blk: { const measurement = try measureProjectionInterruptible( alloc, projection, capability, cols, checkpoint, ); break :blk selector.select_offset(selector.context, measurement, visible_rows); }, }; return renderProjectionWindow(alloc, projection, capability, cols, visible_rows, offset, checkpoint, max_bytes) catch |err| switch (err) { error.StoredSegmentDegraded => continue, else => |other| return other, }; } } fn renderProjectionWindow( alloc: Allocator, projection: *Projection, capability: ?*session_child_store.SessionChildCapability, cols: u16, visible_rows: u16, scroll_offset: u32, checkpoint: ?*BuildCheckpoint, max_bytes: usize, ) ![]u8 { const start = projection.windowStart(cols, scroll_offset); debug_trace.logf( "full_transcript_cache", "window cols={d} offset={d} visible={d} segments={d} checkpoints={d} start_segment={d} start_row={d}", .{ cols, scroll_offset, visible_rows, projection.segments.items.len, projection.measured_segment_checkpoints.items.len, start.segment_index, start.checkpoint.row, }, ); var walker = ProjectionRowWalker.initWindowAt( alloc, cols, scroll_offset, visible_rows, start.checkpoint, checkpoint, ); defer walker.deinit(); walker.max_output_bytes = max_bytes; _ = try walkProjectionSegments( alloc, projection, capability, &walker, start.segment_index, 0, null, null, ); return walker.toOwnedSlice(); } const LifecycleContext = struct { pub fn hash(_: LifecycleContext, id: types.ToolLifecycleId) u64 { return std.hash.Wyhash.hash(id.turn_id, id.call_id); } pub fn eql(_: LifecycleContext, lhs: types.ToolLifecycleId, rhs: types.ToolLifecycleId) bool { return lhs.turn_id == rhs.turn_id and std.mem.eql(u8, lhs.call_id, rhs.call_id); } }; const CommandLifecycleIndex = std.HashMapUnmanaged( types.ToolLifecycleId, usize, LifecycleContext, std.hash_map.default_max_load_percentage, ); const SourceEntryAssociation = struct { detail_index: ?usize = null, command_block_index: ?usize = null, command_source_owned: bool = false, }; const ProjectionSourceIndex = struct { details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, by_entry: std.AutoHashMapUnmanaged(u32, SourceEntryAssociation) = .empty, command_by_lifecycle: CommandLifecycleIndex = .empty, detail_by_command_block: []?usize, fn build( alloc: Allocator, details: []const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !ProjectionSourceIndex { const detail_by_command_block = try alloc.alloc(?usize, command_blocks.len); @memset(detail_by_command_block, null); var index = ProjectionSourceIndex{ .details = details, .command_blocks = command_blocks, .detail_by_command_block = detail_by_command_block, }; errdefer index.deinit(alloc); for (command_blocks, 0..) |block, block_index| { try build_checkpoint.tick(checkpoint); if (block.lifecycle_id) |lifecycle_id| { const result = try index.command_by_lifecycle.getOrPut(alloc, lifecycle_id); if (!result.found_existing) result.value_ptr.* = block_index; } if (block.entry_id) |entry_id| try index.addCommandEntry(alloc, entry_id, block_index); for (block.pruned_ranges.items) |range| { try build_checkpoint.tick(checkpoint); try index.addCommandEntry(alloc, range.anchor_entry_id, block_index); } for (block.live_entry_ids.items) |entry_id| { try build_checkpoint.tick(checkpoint); try index.addCommandEntry(alloc, entry_id, block_index); } for (block.source_entry_ids.items) |entry_id| { try build_checkpoint.tick(checkpoint); try index.addCommandEntry(alloc, entry_id, block_index); } } for (details, 0..) |*detail, detail_index| { try build_checkpoint.tick(checkpoint); const association = try index.entryAssociation(alloc, detail.entry_id); if (association.detail_index == null) association.detail_index = detail_index; const block_index = index.commandBlockIndexForDetail(detail); if (block_index) |value| { if (index.detail_by_command_block[value] == null) { index.detail_by_command_block[value] = detail_index; } } const has_stored_result = storedResultForDetail(detail) != null; if (detail.command_output_entry_id) |entry_id| { const output_block_index = index.commandBlockIndexForEntry(entry_id); if (output_block_index == null or commandSourceIsOwned(detail, command_blocks[output_block_index.?], has_stored_result)) { try index.markCommandSourceOwned(alloc, entry_id); } } if (block_index) |value| { const block = command_blocks[value]; if (!commandSourceIsOwned(detail, block, has_stored_result)) continue; for (block.source_entry_ids.items) |entry_id| { try build_checkpoint.tick(checkpoint); try index.markCommandSourceOwned(alloc, entry_id); } for (block.live_entry_ids.items) |entry_id| { try build_checkpoint.tick(checkpoint); try index.markCommandSourceOwned(alloc, entry_id); } } } return index; } fn deinit(self: *ProjectionSourceIndex, alloc: Allocator) void { alloc.free(self.detail_by_command_block); self.command_by_lifecycle.deinit(alloc); self.by_entry.deinit(alloc); self.* = undefined; } fn entryAssociation( self: *ProjectionSourceIndex, alloc: Allocator, entry_id: u32, ) !*SourceEntryAssociation { const result = try self.by_entry.getOrPut(alloc, entry_id); if (!result.found_existing) result.value_ptr.* = .{}; return result.value_ptr; } fn addCommandEntry( self: *ProjectionSourceIndex, alloc: Allocator, entry_id: u32, block_index: usize, ) !void { const association = try self.entryAssociation(alloc, entry_id); if (association.command_block_index == null) association.command_block_index = block_index; } fn markCommandSourceOwned( self: *ProjectionSourceIndex, alloc: Allocator, entry_id: u32, ) !void { const association = try self.entryAssociation(alloc, entry_id); association.command_source_owned = true; } fn detailForEntry(self: *const ProjectionSourceIndex, entry_id: u32) ?*const ToolDetailRecord { const detail_index = (self.by_entry.get(entry_id) orelse return null).detail_index orelse return null; return &self.details[detail_index]; } fn commandBlockIndexForEntry(self: *const ProjectionSourceIndex, entry_id: u32) ?usize { return (self.by_entry.get(entry_id) orelse return null).command_block_index; } fn renderableCommandBlockIndexForEntry(self: *const ProjectionSourceIndex, entry_id: u32) ?usize { const block_index = self.commandBlockIndexForEntry(entry_id) orelse return null; const block = self.command_blocks[block_index]; return if (block.canReconstructEntries() or block.retention_overflow) block_index else null; } fn commandBlockIndexForLifecycle( self: *const ProjectionSourceIndex, lifecycle_id: types.ToolLifecycleId, ) ?usize { return self.command_by_lifecycle.get(lifecycle_id); } fn commandBlockIndexForDetail( self: *const ProjectionSourceIndex, detail: *const ToolDetailRecord, ) ?usize { if (detail.command_output_entry_id) |entry_id| { if (self.commandBlockIndexForEntry(entry_id)) |block_index| return block_index; } const lifecycle_id = detail.lifecycle_id orelse return null; return self.commandBlockIndexForLifecycle(lifecycle_id); } fn detailForCommandBlock( self: *const ProjectionSourceIndex, block_index: usize, ) ?*const ToolDetailRecord { const detail_index = self.detail_by_command_block[block_index] orelse return null; return &self.details[detail_index]; } fn commandSourceOwned(self: *const ProjectionSourceIndex, entry_id: u32) bool { return (self.by_entry.get(entry_id) orelse return false).command_source_owned; } }; fn commandSourceIsOwned( detail: *const ToolDetailRecord, block: command_output_runtime.CommandOutputBlock, has_stored_result: bool, ) bool { return block.canReconstructEntries() or has_stored_result or isActivePartialCommand(detail, block); } const ProjectionComposeContext = struct { alloc: Allocator, builder: *ProjectionBuilder, entries: []const transcript_blocks.TranscriptEntry, source_index: *const ProjectionSourceIndex, entry_actions: []const transcript_blocks.EntryRenderAction, anchor_entry_id: ?u32, emitted_command_blocks: []bool, full_diff_resolver: ?FullDiffResolver, cols: u16, entry_index: usize = 0, checkpoint: ?*BuildCheckpoint, fn fromOpaque(context: *anyopaque) *ProjectionComposeContext { return @ptrCast(@alignCast(context)); } fn skipEntry( context: *anyopaque, entry: transcript_blocks.TranscriptEntry, entry_index: usize, ) bool { const self = fromOpaque(context); self.entry_index = entry_index; if (self.entryAction(entry) == .hide) return true; if (self.source_index.renderableCommandBlockIndexForEntry(entry.id()) != null) return false; if (self.source_index.commandSourceOwned(entry.id())) return true; return false; } fn overrideKind(context: *anyopaque, entry: transcript_blocks.TranscriptEntry) ?transcript_blocks.TranscriptBlockKind { const self = fromOpaque(context); if (self.diffForEntry(entry) != null) return .diff_block; if (self.source_index.renderableCommandBlockIndexForEntry(entry.id()) != null) return .command_output; return switch (self.entryAction(entry)) { .override => |value| value.kind, .keep, .hide => null, }; } fn appendOverride( context: *anyopaque, entry: transcript_blocks.TranscriptEntry, out: *std.Io.Writer.Allocating, ) !bool { const self = fromOpaque(context); if (self.diffForEntry(entry)) |diff| { const reflowed = try transcript_blocks.reflowDiffBlock(self.alloc, diff, self.cols); defer self.alloc.free(reflowed); try out.writer.writeAll(reflowed); return std.mem.endsWith(u8, reflowed, "\n"); } if (self.source_index.renderableCommandBlockIndexForEntry(entry.id())) |index| { return appendCommandBlockAtEntry(self, out, index, entry.id()); } return switch (self.entryAction(entry)) { .override => |value| blk: { try out.writer.writeAll(value.bytes); break :blk std.mem.endsWith(u8, value.bytes, "\n"); }, .keep, .hide => false, }; } fn beforeEntry( context: *anyopaque, entry_id: u32, out: *std.Io.Writer.Allocating, ) !void { const self = fromOpaque(context); try self.builder.markEntry(entry_id); const entry = self.entries[self.entry_index]; std.debug.assert(entry.id() == entry_id); if (metadataKind(entry)) |kind| { var header_buf: [80]u8 = undefined; if (full_transcript_metadata.formatHeader( &header_buf, self.metadataCreatedAtMs(entry), kind, )) |header| { try out.writer.writeAll(self.builder.styles().dim_style); try out.writer.writeAll(" "); try out.writer.writeAll(header); try out.writer.writeAll(self.builder.styles().reset_style); try out.writer.writeByte('\n'); } } if (self.anchor_entry_id != null and self.anchor_entry_id.? == entry_id) { try self.builder.markAnchor(); } } fn metadataCreatedAtMs( self: *const ProjectionComposeContext, entry: transcript_blocks.TranscriptEntry, ) i64 { switch (entry) { .raw_bytes => |raw| if (raw.class == .tool_status) { if (self.source_index.detailForEntry(entry.id())) |detail| { if (detail.created_at_ms > 0) return detail.created_at_ms; } }, else => {}, } return entry.createdAtMs(); } fn appendDetail( context: *anyopaque, entry_id: u32, out: *std.Io.Writer.Allocating, ) !transcript_blocks.FullDetailAppend { const self = fromOpaque(context); const detail = self.source_index.detailForEntry(entry_id) orelse return .{}; return appendDetailContent( out, self.builder, self.entries, detail, self.source_index, self.full_diff_resolver, self.checkpoint, ); } fn entryAction(self: *const ProjectionComposeContext, entry: transcript_blocks.TranscriptEntry) transcript_blocks.EntryRenderAction { std.debug.assert(self.entries[self.entry_index].id() == entry.id()); return self.entry_actions[self.entry_index]; } fn diffForEntry( self: *const ProjectionComposeContext, entry: transcript_blocks.TranscriptEntry, ) ?[]const u8 { if (self.fullDiffForEntry(entry)) |full| return full; const raw = switch (entry) { .raw_bytes => |value| value, else => return null, }; if (raw.class != .diff_block) return null; return markedDiffContent(raw.bytes) orelse raw.bytes; } fn fullDiffForEntry( self: *const ProjectionComposeContext, entry: transcript_blocks.TranscriptEntry, ) ?[]const u8 { const resolver = self.full_diff_resolver orelse return null; const raw = switch (entry) { .raw_bytes => |value| value, else => return null, }; if (raw.class != .diff_block) return null; const id = diff_mod.markedDiffBlockId(raw.bytes) orelse return null; return resolver.full_for_marker(resolver.context, id); } }; fn metadataKind( entry: transcript_blocks.TranscriptEntry, ) ?full_transcript_metadata.Kind { return switch (entry) { .user_turn => |user| if (std.mem.startsWith( u8, std.mem.trimStart(u8, user.turn.text, " \t\r\n"), "/issue", )) .issue else .prompt, .assistant_turn => .response, .semantic_notice => |notice| if (notice.tone == .@"error") .error_notice else .notice, .raw_bytes => |raw| switch (raw.class) { .tool_status => .tool, .subagent_status => .task, .turn_summary => .usage, else => null, }, .assistant_table, .assistant_code_block, .assistant_thematic_rule, => null, }; } fn markedDiffContent(bytes: []const u8) ?[]const u8 { _ = diff_mod.markedDiffBlockId(bytes) orelse return null; const start_marker_end = std.mem.indexOfScalarPos( u8, bytes, diff_mod.diff_block_start_prefix.len, 0x07, ) orelse return null; const content_start = start_marker_end + 1; const content_end = std.mem.lastIndexOf(u8, bytes, diff_mod.diff_block_end_prefix) orelse return null; if (content_end < content_start) return null; return bytes[content_start..content_end]; } fn isCapturedCommandDetail(detail: *const ToolDetailRecord) bool { return detail.isCapturedCommand(); } fn isActivePartialCommand( detail: *const ToolDetailRecord, block: command_output_runtime.CommandOutputBlock, ) bool { return isCapturedCommandDetail(detail) and detail.outcome == null and storedResultForDetail(detail) == null and block.retention_overflow; } fn commandLineEntryId( block: command_output_runtime.CommandOutputBlock, line_index: usize, ) ?u32 { const line = block.lines.items[line_index]; if (line.entry_id) |entry_id| return entry_id; if (line_index < block.source_entry_ids.items.len) return block.source_entry_ids.items[line_index]; if (line_index < block.live_entry_ids.items.len) return block.live_entry_ids.items[line_index]; return block.entry_id; } fn commandLineRecordOrdinal( block: command_output_runtime.CommandOutputBlock, line_index: usize, ) usize { const ordinal = block.lines.items[line_index].record_ordinal; // Hand-built legacy/test blocks predate explicit ordinals and leave every // line at the default zero. Runtime-ingested records are strictly ordered. if (line_index > 0 and ordinal == 0) return line_index; return ordinal; } fn commandDeferredAnchorEntryId( block: command_output_runtime.CommandOutputBlock, ) ?u32 { var best_end: usize = 0; var best_entry_id: ?u32 = null; for (block.lines.items, 0..) |_, line_index| { const entry_id = commandLineEntryId(block, line_index) orelse continue; const record_end = commandLineRecordOrdinal(block, line_index) +| 1; if (best_entry_id == null or record_end >= best_end) { best_end = record_end; best_entry_id = entry_id; } } for (block.pruned_ranges.items) |range| { if (best_entry_id == null or range.end_record >= best_end) { best_end = range.end_record; best_entry_id = range.anchor_entry_id; } } if (best_entry_id) |entry_id| return entry_id; if (block.source_entry_ids.items.len > 0) return block.source_entry_ids.items[block.source_entry_ids.items.len - 1]; if (block.live_entry_ids.items.len > 0) return block.live_entry_ids.items[block.live_entry_ids.items.len - 1]; return block.entry_id; } fn stableCommandRecordCount(block: command_output_runtime.CommandOutputBlock) usize { if (!block.retention_overflow) return block.lines.items.len; return @min( block.overflow_line_index orelse block.lines.items.len, block.lines.items.len, ); } fn appendDeferredCommandRange( context: *ProjectionComposeContext, out: *std.Io.Writer.Allocating, detail: *const ToolDetailRecord, start_record: usize, end_record: usize, ) !bool { if (start_record >= end_record) return true; const styles = context.builder.styles(); if (storedResultForDetail(detail)) |stored_value| { var stored = stored_value; stored.start_record = start_record; stored.end_record = end_record; stored.retained_command_fallback = try context.alloc.alloc(u8, 0); try context.builder.appendStoredResult(stored); return true; } if (detail.result) |result| { const parsed = try appendInlineCommandResultRange( &out.writer, context.alloc, styles, result, context.cols, start_record, end_record, ); if (parsed) return true; } try appendPermanentCommandUnavailableToWriter(&out.writer, styles); return true; } fn terminalStoredCommandSource(detail: *const ToolDetailRecord) ?StoredResult { const stored = storedResultForDetail(detail) orelse return null; if (stored.kind == .tool_result or stored.handle.len == 0) return null; return stored; } fn appendOpenEndedStoredCommandTail( context: *ProjectionComposeContext, stored_value: StoredResult, start_record: usize, ) !void { var stored = stored_value; stored.start_record = start_record; stored.end_record = null; stored.retained_command_fallback = try context.alloc.alloc(u8, 0); try context.builder.appendStoredResult(stored); } fn prunedRangeCoveringRecord( block: command_output_runtime.CommandOutputBlock, record_ordinal: usize, ) ?command_output_runtime.CommandOutputPrunedRange { for (block.pruned_ranges.items) |range| { if (record_ordinal >= range.start_record and record_ordinal < range.end_record) return range; } return null; } fn nextPrunedRangeStart( block: command_output_runtime.CommandOutputBlock, start_record: usize, end_record: usize, ) ?usize { var next: ?usize = null; for (block.pruned_ranges.items) |range| { if (range.start_record <= start_record or range.start_record >= end_record) continue; next = if (next) |current| @min(current, range.start_record) else range.start_record; } return next; } fn appendDeferredCommandGap( context: *ProjectionComposeContext, out: *std.Io.Writer.Allocating, detail: *const ToolDetailRecord, block: command_output_runtime.CommandOutputBlock, start_record: usize, end_record: usize, ) !bool { var cursor = start_record; var ends_with_newline = true; while (cursor < end_record) { if (prunedRangeCoveringRecord(block, cursor)) |range| { cursor = @min(range.end_record, end_record); continue; } const next_range = nextPrunedRangeStart(block, cursor, end_record) orelse end_record; ends_with_newline = try appendDeferredCommandRange( context, out, detail, cursor, next_range, ); cursor = next_range; } return ends_with_newline; } fn representedCommandRecordEnd( block: command_output_runtime.CommandOutputBlock, stable_count: usize, ) usize { var end_record: usize = 0; for (block.lines.items[0..stable_count], 0..) |_, line_index| { end_record = @max(end_record, commandLineRecordOrdinal(block, line_index) +| 1); } for (block.pruned_ranges.items) |range| { end_record = @max(end_record, range.end_record); } return end_record; } fn appendCommandBlockAtEntry( context: *ProjectionComposeContext, out: *std.Io.Writer.Allocating, block_index: usize, entry_id: u32, ) !bool { const block = context.source_index.command_blocks[block_index]; const styles = context.builder.styles(); const detail = context.source_index.detailForCommandBlock(block_index); const active_partial = if (detail) |command_detail| isActivePartialCommand(command_detail, block) else false; const terminal_source = if (detail) |command_detail| !active_partial and (storedResultForDetail(command_detail) != null or command_detail.result != null) else false; const stored_terminal_source = if (detail) |command_detail| if (!active_partial) terminalStoredCommandSource(command_detail) else null else null; var ends_with_newline = false; if (terminal_source) { for (block.pruned_ranges.items) |range| { if (range.anchor_entry_id != entry_id) continue; ends_with_newline = try appendDeferredCommandRange( context, out, detail.?, range.start_record, range.end_record, ); } } const stable_count = stableCommandRecordCount(block); for (block.lines.items[0..stable_count], 0..) |line, line_index| { if (!line.visible) continue; if (commandLineEntryId(block, line_index) != entry_id) continue; const prior_ordinal = if (line_index == 0) 0 else commandLineRecordOrdinal(block, line_index - 1) +| 1; const record_ordinal = commandLineRecordOrdinal(block, line_index); if (record_ordinal < prior_ordinal) return error.CommandProjectionOrdinalMismatch; if (terminal_source and record_ordinal > prior_ordinal) { ends_with_newline = try appendDeferredCommandGap( context, out, detail.?, block, prior_ordinal, record_ordinal, ); } const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( context.alloc, styles, line.text, context.cols, ); defer context.alloc.free(rendered); try out.writer.writeAll(rendered); ends_with_newline = std.mem.endsWith(u8, rendered, "\n"); } const anchor_entry_id = commandDeferredAnchorEntryId(block) orelse return ends_with_newline; if (anchor_entry_id != entry_id or context.emitted_command_blocks[block_index]) { return ends_with_newline; } context.emitted_command_blocks[block_index] = true; if (detail) |command_detail| { if (active_partial) { try writeSecondaryRailLine( &out.writer, styles, " … full output available when command finishes", ); ends_with_newline = true; } else { if (block.retention_overflow) { const suffix_start = representedCommandRecordEnd(block, stable_count); if (suffix_start < block.total_lines) { ends_with_newline = try appendDeferredCommandGap( context, out, command_detail, block, suffix_start, block.total_lines, ); } } if (stored_terminal_source) |stored| { try appendOpenEndedStoredCommandTail( context, stored, block.total_lines, ); ends_with_newline = true; } } if (command_detail.command_process_presentation) |presentation| { try appendCommandProcessPresentation( &out.writer, context.alloc, styles, presentation, context.cols, ); ends_with_newline = true; } } return ends_with_newline; } fn appendCommandBlock( writer: *std.Io.Writer, alloc: Allocator, block: command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, ) !bool { var ends_with_newline = false; for (block.lines.items) |line| { if (!line.visible) continue; const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, line.text, cols, ); defer alloc.free(rendered); try writer.writeAll(rendered); ends_with_newline = std.mem.endsWith(u8, rendered, "\n"); } return ends_with_newline; } fn appendStableActiveCommandPrefix( writer: *std.Io.Writer, alloc: Allocator, block: command_output_runtime.CommandOutputBlock, styles: transcript_blocks.Styles, cols: u16, ) !void { const stable_end = @min(block.overflow_line_index orelse block.lines.items.len, block.lines.items.len); for (block.lines.items[0..stable_end]) |line| { if (!line.visible) continue; const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, line.text, cols, ); defer alloc.free(rendered); try writer.writeAll(rendered); } try writeSecondaryRailLine( writer, styles, " … full output available when command finishes", ); } fn appendRetainedCommandEntries( writer: *std.Io.Writer, entries: []const transcript_blocks.TranscriptEntry, block: command_output_runtime.CommandOutputBlock, ) !bool { var ends_with_newline = false; for (entries) |entry| { const raw = switch (entry) { .raw_bytes => |value| value, else => continue, }; if (!command_output_runtime.commandBlockOwnsEntry(block, raw.id)) continue; try writer.writeAll(raw.bytes); ends_with_newline = std.mem.endsWith(u8, raw.bytes, "\n"); } return ends_with_newline; } fn storedResultForDetail(detail: *const ToolDetailRecord) ?StoredResult { if (detail.command_output_replay) |replay| switch (replay) { .available => |descriptor| return .{ .kind = .command_replay, .handle = descriptor.handle, .framed_bytes = descriptor.framed_bytes, .preview = detail.result, .fallback_artifact_handle = detail.command_artifact_handle, .fallback_handle = detail.result_handle, }, .unavailable => { if (detail.command_artifact_handle) |handle| { return .{ .kind = .command_artifact, .handle = handle, .preview = detail.result, .fallback_handle = detail.result_handle, .required_replay_unavailable = true, }; } if (detail.result_handle) |handle| { return .{ .kind = .command_result, .handle = handle, .preview = detail.result, .required_replay_unavailable = true, }; } return .{ .kind = .command_replay, .handle = "", .preview = detail.result, .unavailable = true, .required_replay_unavailable = true, }; }, }; if (detail.command_artifact_handle) |handle| { return .{ .kind = .command_artifact, .handle = handle, .preview = detail.result, .fallback_handle = detail.result_handle, }; } if (detail.result_handle) |handle| { return .{ .kind = if (isCapturedCommandDetail(detail)) .command_result else .tool_result, .handle = handle, .preview = detail.result, }; } return null; } fn transcriptHasEntry( entries: []const transcript_blocks.TranscriptEntry, entry_id: u32, ) bool { for (entries) |entry| { if (entry.id() == entry_id) return true; } return false; } fn appendTerminalSafeToolOutput( writer: *std.Io.Writer, alloc: Allocator, styles: transcript_blocks.Styles, raw: []const u8, cols: u16, ) !void { return appendTerminalSafeToolOutputInterruptible( writer, alloc, styles, raw, cols, null, ) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } fn appendTerminalSafeToolOutputInterruptible( writer: *std.Io.Writer, alloc: Allocator, styles: transcript_blocks.Styles, raw: []const u8, cols: u16, checkpoint: ?*BuildCheckpoint, ) !void { if (raw.len == 0) return; var encoded: std.Io.Writer.Allocating = .init(alloc); defer encoded.deinit(); var encoder = TerminalSafeIndentedWriter{ .prefix = "" }; try encoder.append(&encoded.writer, raw); try encoder.finish(&encoded.writer); const bytes = encoded.written(); const ends_with_newline = std.mem.endsWith(u8, bytes, "\n"); const wrap_source = bytes[0 .. bytes.len - @intFromBool(ends_with_newline)]; const wrapped = try assistant_wrap.wrapLiteralToolOutputInterruptible( alloc, wrap_source, cols, checkpoint, ); defer alloc.free(wrapped); var row_start: usize = 0; while (row_start < wrapped.len) { const newline_offset = std.mem.findScalar(u8, wrapped[row_start..], '\n'); const row_end = if (newline_offset) |offset| row_start + offset else wrapped.len; const row = wrapped[row_start..row_end]; if (std.mem.startsWith(u8, row, "│")) { try writer.writeAll(styles.reset_style); try writer.writeAll("│"); try writer.writeAll(styles.dim_style); try writer.writeAll(row["│".len..]); } else { try writer.writeAll(styles.dim_style); try writer.writeAll(row); } try writer.writeAll(styles.reset_style); if (newline_offset == null) break; try writer.writeByte('\n'); row_start = row_end + 1; } if (wrapped.len > 0 or ends_with_newline) try writer.writeByte('\n'); } /// Heading rows carry SGR styling; compare the argument against their plain /// text. Truncation past the buffer reports not-visible, which keeps the /// argument row (the safe direction). fn containsIgnoringSgr(haystack: []const u8, needle: []const u8) bool { var plain_buf: [4096]u8 = undefined; var n: usize = 0; var i: usize = 0; while (i < haystack.len and n < plain_buf.len) { const next = display_width.ansiSequenceEnd(haystack, i); if (next != i) { i = next; continue; } plain_buf[n] = haystack[i]; n += 1; i += 1; } return std.mem.find(u8, plain_buf[0..n], needle) != null; } fn argumentVisibleInToolHeading( entries: []const transcript_blocks.TranscriptEntry, entry_id: u32, value: []const u8, cols: u16, ) bool { if (value.len == 0) return false; for (entries) |entry| { if (entry.id() != entry_id) continue; const raw = switch (entry) { .raw_bytes => |candidate| candidate, else => return false, }; if (raw.class != .tool_status or !containsIgnoringSgr(raw.bytes, value)) return false; return display_width.visibleWidthIgnoringAnsi(raw.bytes) <= cols; } return false; } fn appendFullSemanticArguments( writer: *std.Io.Writer, alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, detail: *const ToolDetailRecord, styles: transcript_blocks.Styles, cols: u16, checkpoint: ?*BuildCheckpoint, ) !bool { const arguments_json = detail.arguments_json orelse return false; var parsed = std.json.parseFromSlice(std.json.Value, alloc, arguments_json, .{}) catch { var fallback: std.Io.Writer.Allocating = .init(alloc); defer fallback.deinit(); try fallback.writer.writeAll("arguments: "); try fallback.writer.writeAll(arguments_json); try appendTerminalSafeToolOutputInterruptible( writer, alloc, styles, fallback.written(), cols, checkpoint, ); return arguments_json.len > 0; }; defer parsed.deinit(); const object = switch (parsed.value) { .object => |value| value, else => { var fallback: std.Io.Writer.Allocating = .init(alloc); defer fallback.deinit(); try fallback.writer.writeAll("arguments: "); try std.json.Stringify.value(parsed.value, .{}, &fallback.writer); try appendTerminalSafeToolOutputInterruptible( writer, alloc, styles, fallback.written(), cols, checkpoint, ); return true; }, }; var appended = false; var iterator = object.iterator(); while (iterator.next()) |entry| { const value = entry.value_ptr.*; if (isCapturedCommandDetail(detail) and std.mem.eql(u8, entry.key_ptr.*, "action") and value == .string and std.mem.eql(u8, value.string, "exec")) continue; if (value == .string and argumentVisibleInToolHeading( entries, detail.entry_id, value.string, cols, )) continue; var line: std.Io.Writer.Allocating = .init(alloc); defer line.deinit(); try line.writer.print("{s}: ", .{entry.key_ptr.*}); switch (value) { .string => |text| try line.writer.writeAll(text), else => try std.json.Stringify.value(value, .{}, &line.writer), } try appendTerminalSafeToolOutputInterruptible( writer, alloc, styles, line.written(), cols, checkpoint, ); appended = true; } return appended; } fn detailHasAdjacentFullDiff( entries: []const transcript_blocks.TranscriptEntry, entry_id: u32, resolver: FullDiffResolver, ) bool { var found_detail = false; for (entries) |entry| { if (!found_detail) { found_detail = entry.id() == entry_id; continue; } const raw = switch (entry) { .raw_bytes => |candidate| candidate, else => return false, }; if (raw.class != .diff_block) return false; const id = diff_mod.markedDiffBlockId(raw.bytes) orelse return false; return resolver.full_for_marker(resolver.context, id) != null; } return false; } fn appendDetailContent( out: *std.Io.Writer.Allocating, builder: *ProjectionBuilder, entries: []const transcript_blocks.TranscriptEntry, detail: *const ToolDetailRecord, source_index: *const ProjectionSourceIndex, full_diff_resolver: ?FullDiffResolver, checkpoint: ?*BuildCheckpoint, ) !transcript_blocks.FullDetailAppend { const alloc = builder.alloc; const styles = builder.styles(); const command_blocks = source_index.command_blocks; const owned_command_block_index = source_index.commandBlockIndexForDetail(detail); const command_block_index = if (owned_command_block_index) |block_index| if (command_blocks[block_index].canReconstructEntries()) block_index else null else null; const deferred_command_source = if (owned_command_block_index) |block_index| blk: { const block = command_blocks[block_index]; break :blk (block.canReconstructEntries() or block.retention_overflow) and if (commandDeferredAnchorEntryId(block)) |entry_id| transcriptHasEntry(entries, entry_id) else false; } else false; const full_diff_covers_arguments = if (full_diff_resolver) |resolver| (if (detail.lifecycle_id) |lifecycle_id| resolver.has_full_for_lifecycle(resolver.context, lifecycle_id) else false) or detailHasAdjacentFullDiff(entries, detail.entry_id, resolver) else false; var semantic_arguments: std.Io.Writer.Allocating = .init(alloc); defer semantic_arguments.deinit(); const has_semantic_arguments = !full_diff_covers_arguments and try appendFullSemanticArguments( &semantic_arguments.writer, alloc, entries, detail, styles, builder.projection_cols, checkpoint, ); const authoritative_stored_result = storedResultForDetail(detail); const active_partial = if (owned_command_block_index) |block_index| isActivePartialCommand(detail, command_blocks[block_index]) else false; const stored_result = if (deferred_command_source) null else authoritative_stored_result; const has_detail = has_semantic_arguments or stored_result != null or detail.result != null or command_block_index != null or active_partial or deferred_command_source; if (!has_detail) return .{}; try out.writer.writeByte('\n'); var ends_with_newline = has_semantic_arguments; if (has_semantic_arguments) try out.writer.writeAll(semantic_arguments.written()); if (stored_result) |stored_value| { var stored = stored_value; stored.line_prefix = "│ "; if (isCapturedCommandDetail(detail) and stored.kind == .command_replay) { stored.retained_command_fallback = try degradedInlineCommandFallback( alloc, entries, detail, command_blocks, owned_command_block_index, styles, builder.projection_cols, ); } else if (owned_command_block_index) |block_index| { var fallback: std.Io.Writer.Allocating = .init(alloc); errdefer fallback.deinit(); const block = command_blocks[block_index]; _ = if (block.canReconstructEntries()) try appendCommandBlock(&fallback.writer, alloc, block, styles, builder.projection_cols) else try appendRetainedCommandEntries(&fallback.writer, entries, block); stored.retained_command_fallback = try fallback.toOwnedSlice(); } try builder.appendStoredResult(stored); ends_with_newline = stored.kind != .tool_result; } else if (deferred_command_source) { ends_with_newline = true; } else if (active_partial) { try appendStableActiveCommandPrefix( &out.writer, alloc, command_blocks[owned_command_block_index.?], styles, builder.projection_cols, ); ends_with_newline = true; } else if (detail.result) |result| { if (isCapturedCommandDetail(detail)) { var rendered: std.Io.Writer.Allocating = .init(alloc); defer rendered.deinit(); const parsed = try appendInlineCommandResult( &rendered.writer, alloc, styles, result, builder.projection_cols, ); if (!parsed) { if (command_block_index) |block_index| { _ = try appendCommandBlock( &rendered.writer, alloc, command_blocks[block_index], styles, builder.projection_cols, ); } else { try appendTerminalSafeToolOutputInterruptible( &rendered.writer, alloc, styles, tool_result_display.contentForDisplay(result), builder.projection_cols, checkpoint, ); } } try out.writer.writeAll(rendered.written()); } else { const display = tool_result_display.contentForDisplay(result); try appendTerminalSafeToolOutputInterruptible( &out.writer, alloc, styles, display, builder.projection_cols, checkpoint, ); } ends_with_newline = true; } if (!deferred_command_source and stored_result == null and detail.result == null and !active_partial) { if (command_block_index) |block_index| { ends_with_newline = try appendCommandBlock( &out.writer, alloc, command_blocks[block_index], styles, builder.projection_cols, ); } } if (!deferred_command_source) { if (detail.command_process_presentation) |presentation| { try appendCommandProcessPresentation( &out.writer, alloc, styles, presentation, builder.projection_cols, ); ends_with_newline = true; } } return .{ .attached = true, .ends_with_newline = ends_with_newline }; } fn degradedInlineCommandFallback( alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, detail: *const ToolDetailRecord, command_blocks: []const command_output_runtime.CommandOutputBlock, owned_command_block_index: ?usize, styles: transcript_blocks.Styles, cols: u16, ) ![]u8 { var fallback: std.Io.Writer.Allocating = .init(alloc); errdefer fallback.deinit(); if (detail.result) |result| { if (try appendInlineCommandResult( &fallback.writer, alloc, styles, result, cols, )) return fallback.toOwnedSlice(); } if (owned_command_block_index) |block_index| { const block = command_blocks[block_index]; _ = if (block.canReconstructEntries()) try appendCommandBlock(&fallback.writer, alloc, block, styles, cols) else try appendRetainedCommandEntries(&fallback.writer, entries, block); if (fallback.written().len > 0) return fallback.toOwnedSlice(); } if (detail.result) |result| { try appendTerminalSafeIndented( &fallback.writer, alloc, tool_result_display.contentForDisplay(result), ); } return fallback.toOwnedSlice(); } fn appendCommandProcessPresentation( writer: *std.Io.Writer, alloc: Allocator, styles: transcript_blocks.Styles, presentation: types.CommandProcessPresentation, cols: u16, ) !void { const text = switch (presentation) { .exit_code => |code| try std.fmt.allocPrint(alloc, "exit code {d}", .{code}), .signal => |signal| try std.fmt.allocPrint(alloc, "signal {d}", .{signal}), .timed_out => try alloc.dupe(u8, "timed out"), .output_capture_failed => try alloc.dupe(u8, "output capture failed"), }; defer alloc.free(text); const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, text, cols, ); defer alloc.free(rendered); try writer.writeAll(rendered); if (!std.mem.endsWith(u8, rendered, "\n")) try writer.writeByte('\n'); } fn appendInlineCommandResult( writer: *std.Io.Writer, alloc: Allocator, styles: transcript_blocks.Styles, result: []const u8, cols: u16, ) !bool { return appendInlineCommandResultRange( writer, alloc, styles, result, cols, 0, std.math.maxInt(usize), ); } fn appendInlineCommandResultRange( writer: *std.Io.Writer, alloc: Allocator, styles: transcript_blocks.Styles, result: []const u8, cols: u16, start_record: usize, requested_end_record: usize, ) !bool { if (try command_output_content.canonicalizeForegroundResult(alloc, result)) |parsed_value| { var parsed = parsed_value; defer parsed.deinit(alloc); if (requested_end_record != std.math.maxInt(usize) and requested_end_record > parsed.records.items.len) return false; const end_record = @min(requested_end_record, parsed.records.items.len); if (start_record > end_record) return false; for (parsed.records.items[start_record..end_record]) |record| { const rendered = try command_output_runtime.renderCommandOutputRecordWithPrimaryGutter( alloc, styles, record.text.items, cols, ); defer alloc.free(rendered); try writer.writeAll(rendered); if (!std.mem.endsWith(u8, rendered, "\n")) try writer.writeByte('\n'); } return true; } return false; } fn appendPermanentCommandUnavailableToWriter( writer: *std.Io.Writer, styles: transcript_blocks.Styles, ) !void { try writeSecondaryRailLine(writer, styles, " … full output unavailable"); } fn appendTerminalSafeIndented(writer: *std.Io.Writer, alloc: Allocator, raw: []const u8) !void { _ = alloc; var stream = TerminalSafeIndentedWriter{}; try stream.append(writer, raw); try stream.finish(writer); if (!stream.line_start) try writer.writeByte('\n'); } test "containsIgnoringSgr matches arguments inside styled tool headings" { const styled = "● Ran\x1b[0m \x1b[38;5;245mprintf \x1b[38;5;250m'hello world'\x1b[39m\x1b[38;5;245m\x1b[0m"; try std.testing.expect(containsIgnoringSgr(styled, "printf 'hello world'")); try std.testing.expect(containsIgnoringSgr(styled, "Ran")); try std.testing.expect(!containsIgnoringSgr(styled, "missing")); try std.testing.expect(containsIgnoringSgr("plain row", "plain")); try std.testing.expect(containsIgnoringSgr("\x1b[38;5;245m", "x") == false); }