const std = @import("std");const input_action = @import("../input/input_action.zig");const core_input_runtime = @import("../input/runtime.zig");const ui_input = @import("../../ui/input/runtime.zig");const input_visual_layout = @import("../../ui/input/visual_layout.zig");const shell_runtime = @import("../../ui/shell_runtime.zig");const transcript_runtime = @import("../../ui/transcript/runtime.zig");const app_render_runtime = @import("app_render_runtime.zig");const app_terminal_runtime = @import("app_terminal_runtime.zig");const input_selection_runtime = @import("input_selection_runtime.zig");const app_session_runtime = @import("app_session_runtime.zig");const command_specs = @import("../slash_commands/command_specs.zig");const debug_trace = @import("../shared/debug_trace.zig");const skill_runtime = @import("../skills/skill_runtime.zig");const types = @import("../shared/types.zig");const subagent_domain = @import("../subagent/domain.zig");const subagent_input = @import("../subagent/input_action.zig");const catalog_screen_layout = @import("../../ui/catalog_screen_layout.zig");const input_presentation = @import("../../ui/footer/input_presentation.zig");const model_menu_presentation = @import("../../ui/footer/model_menu_presentation.zig");const skills_menu_presentation = @import("../../ui/footer/skills_menu_presentation.zig");const render_input = @import("../../ui/footer/render_input.zig"); pub fn SubagentRuntime(comptime App: type) type { return struct { pub fn routeSubagentEscapeAction( app: *App, action: input_action.Action, shortcut: ?input_action.ShortcutAction, typed_action: ?subagent_input.Action, ) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "handleAction")) return; app.input_runtime.vertical_navigation.reset(); if (comptime @hasField(App, "model_cache") and @hasDecl(@TypeOf(app.subagents), "childRouteId") and @hasDecl(@TypeOf(app.subagents), "childPresentationView")) { if (childSkillsMenuActive(app)) { switch (action) { .escape => { closeChildSkillsMenu(app); try childChangedAndRedraw(app); }, .history_up, .cursor_up => moveChildSkillsMenu(app, -1), .history_down, .cursor_down => moveChildSkillsMenu(app, 1), .cursor_left, .cursor_right, .home, .end, .word_left, .word_right, .delete_next, .delete_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .clear_line, => try editChildSkillsQuery(app, action), else => {}, } return; } if (childModelMenuActive(app)) { switch (action) { .escape => { closeChildModelMenu(app); try childChangedAndRedraw(app); }, .history_up, .cursor_up => moveChildModelMenu(app, -1), .history_down, .cursor_down => moveChildModelMenu(app, 1), .cursor_left, .cursor_right, .home, .end, .word_left, .word_right, .delete_next, .delete_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .clear_line, => try editChildModelQuery(app, action), else => {}, } return; } } if (shortcut) |composer_action| { if (try routeChildComposerShortcut(app, composer_action)) return; } if (typed_action) |resolved| { try handleSubagentAction(app, resolved); return; } if (action == .mouse_pointer) { _ = routeChildComposerPointerAction(app, action.mouse_pointer); } } fn routeChildComposerShortcut( app: *App, shortcut: input_action.ShortcutAction, ) !bool { if (comptime !@hasDecl(@TypeOf(app.subagents), "childComposerFocused")) { return false; } if (!app.subagents.childComposerFocused()) return false; switch (shortcut) { .move => |intent| { const child_shell = app.subagents.childConversationRuntime() orelse return false; if (!app.subagents.moveChildInputCursor( intent, child_shell.layout.cols, input_presentation.inputRowLimit(child_shell.layout.content_bottom), )) return false; }, .select_all => { if (comptime !@hasDecl( @TypeOf(app.subagents), "childComposerEditor", )) return false; const editor = app.subagents.childComposerEditor() orelse return false; _ = editor.selectionState().selectAll(); }, .copy_selection => { if (comptime @hasDecl(App, "clipboard")) { const view = app.subagents.childPresentationView() orelse return false; if (input_selection_runtime.copySelection( &view.editor.edit_state, app.clipboard(), ) == .copy_failed) { debug_trace.logf( "subagent", "child selection copy preserved reason=clipboard_copy_failed", .{}, ); } } }, .cut_selection => { if (comptime @hasDecl(App, "clipboard")) { const editor = app.subagents.childComposerEditor() orelse return false; switch (input_selection_runtime.cutSelection( app.alloc, editor.selectionState(), null, app.clipboard(), )) { .cut => app.subagents.commitChildEditorEdit(app.alloc), .copy_failed => debug_trace.logf( "subagent", "child selection cut preserved reason=clipboard_copy_failed", .{}, ), .delete_failed => debug_trace.logf( "subagent", "child selection cut delete skipped reason=delete_failed", .{}, ), .inactive, .copied => {}, } } }, .delete_forward => try handleSubagentAction(app, .delete_next), .delete_word_left => try handleSubagentAction(app, .delete_word_left), .delete_whitespace_word_left => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.killRingState(null).delete( app.alloc, .whitespace_word_left, )) { app.subagents.commitChildEditorEdit(app.alloc); } }, .delete_word_right => try handleSubagentAction(app, .delete_word_right), .delete_to_line_start => try handleSubagentAction(app, .delete_to_line_start), .delete_to_line_end => try handleSubagentAction(app, .delete_to_line_end), .insert_newline => try handleSubagentAction(app, .insert_newline), .undo => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.undoState().undo(app.alloc)) { app.subagents.commitChildEditorEdit(app.alloc); } }, .redo => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.undoState().redo(app.alloc)) { app.subagents.commitChildEditorEdit(app.alloc); } }, .yank => { const editor = app.subagents.childComposerEditor() orelse return false; switch (try editor.killRingState(null).yank( app.alloc, 1, subagent_domain.max_message_bytes, )) { .inserted => app.subagents.commitChildEditorEdit(app.alloc), .inactive, .limit_exceeded => {}, } }, .delete_backward, .history_previous, .history_next, .redraw, => return false, } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return true; } fn routeChildComposerPointerAction( app: *App, pointer: input_action.MousePointer, ) bool { if (pointer.shift) return false; if (comptime !@hasDecl( @TypeOf(app.subagents), "childComposerEditor", )) return false; const editor = app.subagents.childComposerEditor() orelse return false; const child_shell = app.subagents.childConversationRuntime() orelse return false; if (!child_shell.footer_viewport.has_frame) return false; const prefix_cells: u16 = @intCast(input_visual_layout.inputPrefix(0).cell_width); const position = child_shell.footer_viewport.geometry.inputPointerPosition( pointer.row, pointer.column, prefix_cells, ) orelse { if (pointer.kind == .release and editor.edit_state.selection_anchor != null) { editor.selectionState().finish(); requestChildFooterFrame(app); return true; } return false; }; const point = input_visual_layout.cursorPointAtPosition(.{ .input = editor.edit_state.input.items, .cursor = editor.edit_state.cursor, .terminal_cols = child_shell.layout.cols, .pasted_blocks = editor.entities.pasted_blocks.items, .skill_tokens = editor.entities.skill_tokens.items, }, position.row_index, position.content_column) orelse return false; const changed = switch (pointer.kind) { .press => editor.selectionState().begin(point.raw_offset), .drag => editor.selectionState().extend(point.raw_offset), .release => blk: { if (editor.edit_state.selection_anchor == null) break :blk false; _ = editor.selectionState().extend(point.raw_offset); editor.selectionState().finish(); break :blk true; }, }; if (changed) requestChildFooterFrame(app); return changed; } fn requestChildFooterFrame(app: *App) void { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .footer, ); } pub fn handleSubagentRawInput( app: *App, raw: input_action.RawTerminalInput, ) !void { const byte = raw.byte; if (comptime @hasField(App, "model_cache") and @hasDecl(@TypeOf(app.subagents), "childRouteId") and @hasDecl(@TypeOf(app.subagents), "childPresentationView")) { if (childSkillsMenuActive(app) and try handleChildSkillsMenuByte(app, byte)) { return; } if (childModelMenuActive(app) and try handleChildModelMenuByte(app, byte)) { return; } } if (raw.composer_shortcut) |shortcut| { if (try routeChildComposerShortcut(app, shortcut)) return; } if (raw.subagent_action) |action| { try handleSubagentAction(app, action); return; } if (raw.composer_shortcut != null) return; const failure_before = if (comptime @hasDecl( @TypeOf(app.subagents), "childPresentationView", )) if (app.subagents.childPresentationView()) |view| view.input_failure else null else null; const result = if (comptime @hasDecl(@TypeOf(app.subagents), "handleKeyWithMainApproval")) try app.subagents.handleKeyWithMainApproval(app.alloc, byte, mainApprovalId(app)) else try app.subagents.handleKey(app.alloc, byte); if (comptime @hasDecl( @TypeOf(app.subagents), "invalidateChildConversationProjection", )) { const failure_after = if (app.subagents.childPresentationView()) |view| view.input_failure else null; if (!std.meta.eql(failure_before, failure_after)) { app.subagents.invalidateChildConversationProjection(app.alloc); } } switch (result) { .acknowledge => try acknowledgeAndRedraw(app), .none => {}, .exit_app => exitApp(app), .close_manager => try closeSubagentManager(app), .page_changed => try refreshPageAndRedraw(app), .child_changed => try childChangedAndRedraw(app), .load_older_history => try loadOlderHistoryAndRedraw(app), .refresh_newest_history => try refreshNewestHistoryAndRedraw(app), .submit_child_message => try submitChildMessageAndRedraw(app), .load_attach_candidates => try loadAttachCandidatesAndRedraw(app, false), .load_more_attach_candidates => try loadAttachCandidatesAndRedraw(app, true), .submit_manager_mutation => try submitManagerMutationAndRedraw(app), .resolve_child_approval => try resolveChildApprovalAndRedraw(app), .open_terminal => try openSelectedTerminal(app), .redraw => try redraw(app), } } fn handleSubagentAction(app: *App, action: subagent_input.Action) !void { const result = if (comptime @hasDecl(@TypeOf(app.subagents), "handleActionWithMainApproval")) try app.subagents.handleActionWithMainApproval(app.alloc, action, mainApprovalId(app)) else try app.subagents.handleAction(app.alloc, action); switch (result) { .acknowledge => try acknowledgeAndRedraw(app), .none => {}, .exit_app => exitApp(app), .close_manager => try closeSubagentManager(app), .page_changed => try refreshPageAndRedraw(app), .child_changed => try childChangedAndRedraw(app), .load_older_history => try loadOlderHistoryAndRedraw(app), .refresh_newest_history => try refreshNewestHistoryAndRedraw(app), .submit_child_message => try submitChildMessageAndRedraw(app), .load_attach_candidates => try loadAttachCandidatesAndRedraw(app, false), .load_more_attach_candidates => try loadAttachCandidatesAndRedraw(app, true), .submit_manager_mutation => try submitManagerMutationAndRedraw(app), .resolve_child_approval => try resolveChildApprovalAndRedraw(app), .open_terminal => try openSelectedTerminal(app), .redraw => try redraw(app), } } fn openSelectedTerminal(app: *App) !void { requestSelectedTerminalOpen(app); try redraw(app); } fn requestSelectedTerminalOpen(app: *App) void { if (comptime @hasDecl(@TypeOf(app.subagents), "selectedTerminalId") and @hasDecl(App, "requestTerminalOpen")) { const session_id = app.subagents.selectedTerminalId() orelse return; switch (app.requestTerminalOpen(session_id)) { .accepted, .occupied, .rejected => {}, } } } fn exitApp(app: *App) void { app_session_runtime.Runtime(App).requestResumeHandoff(app); app.should_exit = true; } fn redraw(app: *App) !void { if (app.subagents.isViewActive()) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .footer, ); } else { try shell_runtime.requestRedraw(&app.shell, &app.metrics, .replay_viewport); } } fn refreshPageAndRedraw(app: *App) !void { if (comptime @hasDecl(@TypeOf(app.subagents), "pageCursor")) { try app_render_runtime.Runtime(App).refreshSubagentManager(app, true); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn acknowledgeAndRedraw(app: *App) !void { if (comptime @hasDecl(App, "acknowledgeSubagentManagerSelection")) { try app.acknowledgeSubagentManagerSelection(); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn childChangedAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "childRouteId")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } if (app.subagents.childRouteId() != null) { try app_render_runtime.Runtime(App).refreshChildChat( app, null, false, true, ); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn loadOlderHistoryAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "olderHistoryCursor")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } const cursor = app.subagents.olderHistoryCursor() orelse return; try app_render_runtime.Runtime(App).refreshChildChat( app, cursor, true, false, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn refreshNewestHistoryAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "childRouteId")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } try app_render_runtime.Runtime(App).refreshChildChat( app, null, false, true, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn submitChildMessageAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "prepareSubmission")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } if (comptime @hasDecl(@TypeOf(app.subagents), "childPresentationView") and @hasDecl(App, "slashRegistry")) {Lines 1–500 of 1052. Load more
const std = @import("std"); const input_action = @import("../input/input_action.zig"); const core_input_runtime = @import("../input/runtime.zig"); const ui_input = @import("../../ui/input/runtime.zig"); const input_visual_layout = @import("../../ui/input/visual_layout.zig"); const shell_runtime = @import("../../ui/shell_runtime.zig"); const transcript_runtime = @import("../../ui/transcript/runtime.zig"); const app_render_runtime = @import("app_render_runtime.zig"); const app_terminal_runtime = @import("app_terminal_runtime.zig"); const input_selection_runtime = @import("input_selection_runtime.zig"); const app_session_runtime = @import("app_session_runtime.zig"); const command_specs = @import("../slash_commands/command_specs.zig"); const debug_trace = @import("../shared/debug_trace.zig"); const skill_runtime = @import("../skills/skill_runtime.zig"); const types = @import("../shared/types.zig"); const subagent_domain = @import("../subagent/domain.zig"); const subagent_input = @import("../subagent/input_action.zig"); const catalog_screen_layout = @import("../../ui/catalog_screen_layout.zig"); const input_presentation = @import("../../ui/footer/input_presentation.zig"); const model_menu_presentation = @import("../../ui/footer/model_menu_presentation.zig"); const skills_menu_presentation = @import("../../ui/footer/skills_menu_presentation.zig"); const render_input = @import("../../ui/footer/render_input.zig"); pub fn SubagentRuntime(comptime App: type) type { return struct { pub fn routeSubagentEscapeAction( app: *App, action: input_action.Action, shortcut: ?input_action.ShortcutAction, typed_action: ?subagent_input.Action, ) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "handleAction")) return; app.input_runtime.vertical_navigation.reset(); if (comptime @hasField(App, "model_cache") and @hasDecl(@TypeOf(app.subagents), "childRouteId") and @hasDecl(@TypeOf(app.subagents), "childPresentationView")) { if (childSkillsMenuActive(app)) { switch (action) { .escape => { closeChildSkillsMenu(app); try childChangedAndRedraw(app); }, .history_up, .cursor_up => moveChildSkillsMenu(app, -1), .history_down, .cursor_down => moveChildSkillsMenu(app, 1), .cursor_left, .cursor_right, .home, .end, .word_left, .word_right, .delete_next, .delete_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .clear_line, => try editChildSkillsQuery(app, action), else => {}, } return; } if (childModelMenuActive(app)) { switch (action) { .escape => { closeChildModelMenu(app); try childChangedAndRedraw(app); }, .history_up, .cursor_up => moveChildModelMenu(app, -1), .history_down, .cursor_down => moveChildModelMenu(app, 1), .cursor_left, .cursor_right, .home, .end, .word_left, .word_right, .delete_next, .delete_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .clear_line, => try editChildModelQuery(app, action), else => {}, } return; } } if (shortcut) |composer_action| { if (try routeChildComposerShortcut(app, composer_action)) return; } if (typed_action) |resolved| { try handleSubagentAction(app, resolved); return; } if (action == .mouse_pointer) { _ = routeChildComposerPointerAction(app, action.mouse_pointer); } } fn routeChildComposerShortcut( app: *App, shortcut: input_action.ShortcutAction, ) !bool { if (comptime !@hasDecl(@TypeOf(app.subagents), "childComposerFocused")) { return false; } if (!app.subagents.childComposerFocused()) return false; switch (shortcut) { .move => |intent| { const child_shell = app.subagents.childConversationRuntime() orelse return false; if (!app.subagents.moveChildInputCursor( intent, child_shell.layout.cols, input_presentation.inputRowLimit(child_shell.layout.content_bottom), )) return false; }, .select_all => { if (comptime !@hasDecl( @TypeOf(app.subagents), "childComposerEditor", )) return false; const editor = app.subagents.childComposerEditor() orelse return false; _ = editor.selectionState().selectAll(); }, .copy_selection => { if (comptime @hasDecl(App, "clipboard")) { const view = app.subagents.childPresentationView() orelse return false; if (input_selection_runtime.copySelection( &view.editor.edit_state, app.clipboard(), ) == .copy_failed) { debug_trace.logf( "subagent", "child selection copy preserved reason=clipboard_copy_failed", .{}, ); } } }, .cut_selection => { if (comptime @hasDecl(App, "clipboard")) { const editor = app.subagents.childComposerEditor() orelse return false; switch (input_selection_runtime.cutSelection( app.alloc, editor.selectionState(), null, app.clipboard(), )) { .cut => app.subagents.commitChildEditorEdit(app.alloc), .copy_failed => debug_trace.logf( "subagent", "child selection cut preserved reason=clipboard_copy_failed", .{}, ), .delete_failed => debug_trace.logf( "subagent", "child selection cut delete skipped reason=delete_failed", .{}, ), .inactive, .copied => {}, } } }, .delete_forward => try handleSubagentAction(app, .delete_next), .delete_word_left => try handleSubagentAction(app, .delete_word_left), .delete_whitespace_word_left => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.killRingState(null).delete( app.alloc, .whitespace_word_left, )) { app.subagents.commitChildEditorEdit(app.alloc); } }, .delete_word_right => try handleSubagentAction(app, .delete_word_right), .delete_to_line_start => try handleSubagentAction(app, .delete_to_line_start), .delete_to_line_end => try handleSubagentAction(app, .delete_to_line_end), .insert_newline => try handleSubagentAction(app, .insert_newline), .undo => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.undoState().undo(app.alloc)) { app.subagents.commitChildEditorEdit(app.alloc); } }, .redo => { const editor = app.subagents.childComposerEditor() orelse return false; if (try editor.undoState().redo(app.alloc)) { app.subagents.commitChildEditorEdit(app.alloc); } }, .yank => { const editor = app.subagents.childComposerEditor() orelse return false; switch (try editor.killRingState(null).yank( app.alloc, 1, subagent_domain.max_message_bytes, )) { .inserted => app.subagents.commitChildEditorEdit(app.alloc), .inactive, .limit_exceeded => {}, } }, .delete_backward, .history_previous, .history_next, .redraw, => return false, } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return true; } fn routeChildComposerPointerAction( app: *App, pointer: input_action.MousePointer, ) bool { if (pointer.shift) return false; if (comptime !@hasDecl( @TypeOf(app.subagents), "childComposerEditor", )) return false; const editor = app.subagents.childComposerEditor() orelse return false; const child_shell = app.subagents.childConversationRuntime() orelse return false; if (!child_shell.footer_viewport.has_frame) return false; const prefix_cells: u16 = @intCast(input_visual_layout.inputPrefix(0).cell_width); const position = child_shell.footer_viewport.geometry.inputPointerPosition( pointer.row, pointer.column, prefix_cells, ) orelse { if (pointer.kind == .release and editor.edit_state.selection_anchor != null) { editor.selectionState().finish(); requestChildFooterFrame(app); return true; } return false; }; const point = input_visual_layout.cursorPointAtPosition(.{ .input = editor.edit_state.input.items, .cursor = editor.edit_state.cursor, .terminal_cols = child_shell.layout.cols, .pasted_blocks = editor.entities.pasted_blocks.items, .skill_tokens = editor.entities.skill_tokens.items, }, position.row_index, position.content_column) orelse return false; const changed = switch (pointer.kind) { .press => editor.selectionState().begin(point.raw_offset), .drag => editor.selectionState().extend(point.raw_offset), .release => blk: { if (editor.edit_state.selection_anchor == null) break :blk false; _ = editor.selectionState().extend(point.raw_offset); editor.selectionState().finish(); break :blk true; }, }; if (changed) requestChildFooterFrame(app); return changed; } fn requestChildFooterFrame(app: *App) void { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .footer, ); } pub fn handleSubagentRawInput( app: *App, raw: input_action.RawTerminalInput, ) !void { const byte = raw.byte; if (comptime @hasField(App, "model_cache") and @hasDecl(@TypeOf(app.subagents), "childRouteId") and @hasDecl(@TypeOf(app.subagents), "childPresentationView")) { if (childSkillsMenuActive(app) and try handleChildSkillsMenuByte(app, byte)) { return; } if (childModelMenuActive(app) and try handleChildModelMenuByte(app, byte)) { return; } } if (raw.composer_shortcut) |shortcut| { if (try routeChildComposerShortcut(app, shortcut)) return; } if (raw.subagent_action) |action| { try handleSubagentAction(app, action); return; } if (raw.composer_shortcut != null) return; const failure_before = if (comptime @hasDecl( @TypeOf(app.subagents), "childPresentationView", )) if (app.subagents.childPresentationView()) |view| view.input_failure else null else null; const result = if (comptime @hasDecl(@TypeOf(app.subagents), "handleKeyWithMainApproval")) try app.subagents.handleKeyWithMainApproval(app.alloc, byte, mainApprovalId(app)) else try app.subagents.handleKey(app.alloc, byte); if (comptime @hasDecl( @TypeOf(app.subagents), "invalidateChildConversationProjection", )) { const failure_after = if (app.subagents.childPresentationView()) |view| view.input_failure else null; if (!std.meta.eql(failure_before, failure_after)) { app.subagents.invalidateChildConversationProjection(app.alloc); } } switch (result) { .acknowledge => try acknowledgeAndRedraw(app), .none => {}, .exit_app => exitApp(app), .close_manager => try closeSubagentManager(app), .page_changed => try refreshPageAndRedraw(app), .child_changed => try childChangedAndRedraw(app), .load_older_history => try loadOlderHistoryAndRedraw(app), .refresh_newest_history => try refreshNewestHistoryAndRedraw(app), .submit_child_message => try submitChildMessageAndRedraw(app), .load_attach_candidates => try loadAttachCandidatesAndRedraw(app, false), .load_more_attach_candidates => try loadAttachCandidatesAndRedraw(app, true), .submit_manager_mutation => try submitManagerMutationAndRedraw(app), .resolve_child_approval => try resolveChildApprovalAndRedraw(app), .open_terminal => try openSelectedTerminal(app), .redraw => try redraw(app), } } fn handleSubagentAction(app: *App, action: subagent_input.Action) !void { const result = if (comptime @hasDecl(@TypeOf(app.subagents), "handleActionWithMainApproval")) try app.subagents.handleActionWithMainApproval(app.alloc, action, mainApprovalId(app)) else try app.subagents.handleAction(app.alloc, action); switch (result) { .acknowledge => try acknowledgeAndRedraw(app), .none => {}, .exit_app => exitApp(app), .close_manager => try closeSubagentManager(app), .page_changed => try refreshPageAndRedraw(app), .child_changed => try childChangedAndRedraw(app), .load_older_history => try loadOlderHistoryAndRedraw(app), .refresh_newest_history => try refreshNewestHistoryAndRedraw(app), .submit_child_message => try submitChildMessageAndRedraw(app), .load_attach_candidates => try loadAttachCandidatesAndRedraw(app, false), .load_more_attach_candidates => try loadAttachCandidatesAndRedraw(app, true), .submit_manager_mutation => try submitManagerMutationAndRedraw(app), .resolve_child_approval => try resolveChildApprovalAndRedraw(app), .open_terminal => try openSelectedTerminal(app), .redraw => try redraw(app), } } fn openSelectedTerminal(app: *App) !void { requestSelectedTerminalOpen(app); try redraw(app); } fn requestSelectedTerminalOpen(app: *App) void { if (comptime @hasDecl(@TypeOf(app.subagents), "selectedTerminalId") and @hasDecl(App, "requestTerminalOpen")) { const session_id = app.subagents.selectedTerminalId() orelse return; switch (app.requestTerminalOpen(session_id)) { .accepted, .occupied, .rejected => {}, } } } fn exitApp(app: *App) void { app_session_runtime.Runtime(App).requestResumeHandoff(app); app.should_exit = true; } fn redraw(app: *App) !void { if (app.subagents.isViewActive()) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .footer, ); } else { try shell_runtime.requestRedraw(&app.shell, &app.metrics, .replay_viewport); } } fn refreshPageAndRedraw(app: *App) !void { if (comptime @hasDecl(@TypeOf(app.subagents), "pageCursor")) { try app_render_runtime.Runtime(App).refreshSubagentManager(app, true); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn acknowledgeAndRedraw(app: *App) !void { if (comptime @hasDecl(App, "acknowledgeSubagentManagerSelection")) { try app.acknowledgeSubagentManagerSelection(); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn childChangedAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "childRouteId")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } if (app.subagents.childRouteId() != null) { try app_render_runtime.Runtime(App).refreshChildChat( app, null, false, true, ); } app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn loadOlderHistoryAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "olderHistoryCursor")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } const cursor = app.subagents.olderHistoryCursor() orelse return; try app_render_runtime.Runtime(App).refreshChildChat( app, cursor, true, false, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn refreshNewestHistoryAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "childRouteId")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } try app_render_runtime.Runtime(App).refreshChildChat( app, null, false, true, ); app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); } fn submitChildMessageAndRedraw(app: *App) !void { if (comptime !@hasDecl(@TypeOf(app.subagents), "prepareSubmission")) { app_render_runtime.Runtime(App).requestSubagentSurfaceFrame( app, .subagent_panel, ); return; } if (comptime @hasDecl(@TypeOf(app.subagents), "childPresentationView") and @hasDecl(App, "slashRegistry")) {