fix(tui): scoped stable-focus keystroke renders

Scoped ordinary input frames to the focused component while retaining a full compose when input moves focus. Explicitly repainted the coding-agent pending-message sibling and covered stable focus, wrapped growth, focus movement, and queue clearing.

Fixes #5928
This commit is contained in:
roboomp
2026-07-18 00:12:08 +00:00
parent 48241afcc4
commit ea29f72dc0
6 changed files with 157 additions and 8 deletions
@@ -651,11 +651,12 @@ function createStubInteractiveModeContextForUiHelpers(session: AgentSession) {
};
const pendingMessagesContainer = new Container();
const requestRender = vi.fn();
const requestComponentRender = vi.fn();
const updatePendingMessagesDisplay = vi.fn();
const ctx = {
editor,
ui: { requestRender },
ui: { requestRender, requestComponentRender },
pendingMessagesContainer,
session,
viewSession: session,
@@ -667,7 +668,7 @@ function createStubInteractiveModeContextForUiHelpers(session: AgentSession) {
locallySubmittedUserSignatures: new Set<string>(),
} as unknown as InteractiveModeContext;
return { ctx, editor, pendingMessagesContainer };
return { ctx, editor, pendingMessagesContainer, requestComponentRender };
}
describe("UiHelpers / InputController against derived queued custom display", () => {
@@ -704,6 +705,26 @@ describe("UiHelpers / InputController against derived queued custom display", ()
expect(rendered).not.toContain("Steer:");
});
it("requests the pending-container repaint after rebuilding and clearing it", async () => {
fixture = await createRealSession();
const { session } = fixture;
queueCustomSteer(session, "/skill:test-skill arg1 arg2");
const { ctx, pendingMessagesContainer, requestComponentRender } =
createStubInteractiveModeContextForUiHelpers(session);
const uiHelpers = new UiHelpers(ctx);
uiHelpers.updatePendingMessagesDisplay();
expect(pendingMessagesContainer.children.length).toBeGreaterThan(0);
expect(requestComponentRender).toHaveBeenNthCalledWith(1, pendingMessagesContainer);
session.clearQueue();
uiHelpers.updatePendingMessagesDisplay();
expect(pendingMessagesContainer.children).toHaveLength(0);
expect(requestComponentRender).toHaveBeenNthCalledWith(2, pendingMessagesContainer);
});
it("groups yield follow-ups under one heading", async () => {
fixture = await createRealSession();
const { session } = fixture;