diff --git a/packages/coding-agent/.changes/agents-view-always-show-inactive.md b/packages/coding-agent/.changes/agents-view-always-show-inactive.md new file mode 100644 index 0000000000..f087c8b3f4 --- /dev/null +++ b/packages/coding-agent/.changes/agents-view-always-show-inactive.md @@ -0,0 +1 @@ +- Removed the inactive-session collapse (Alt+I): inactive sessions always render in the agents view, and search remains the filter. diff --git a/packages/coding-agent/src/core/keybindings.ts b/packages/coding-agent/src/core/keybindings.ts index 471cb56003..1efbaaca00 100644 --- a/packages/coding-agent/src/core/keybindings.ts +++ b/packages/coding-agent/src/core/keybindings.ts @@ -48,7 +48,6 @@ export interface AppKeybindings { "app.agents.delete": true; "app.agents.program": true; "app.agents.rename": true; - "app.agents.inactiveCollapse": true; "app.agents.expand": true; "app.tree.foldOrUp": true; "app.tree.unfoldOrDown": true; @@ -161,7 +160,6 @@ export const KEYBINDINGS = { "app.agents.delete": { defaultKeys: "ctrl+x", description: "Stop or delete selected agent" }, "app.agents.program": { defaultKeys: "ctrl+o", description: "Show the program that spawned subagents" }, "app.agents.rename": { defaultKeys: "ctrl+r", description: "Rename selected agent session" }, - "app.agents.inactiveCollapse": { defaultKeys: "alt+i", description: "Show or hide inactive sessions" }, "app.agents.expand": { defaultKeys: "alt+right", description: "Expand or collapse selected agent subagents" }, "app.tree.foldOrUp": { defaultKeys: ["ctrl+left", "alt+left"], diff --git a/packages/coding-agent/src/modes/agents-view/agents-view-mode.ts b/packages/coding-agent/src/modes/agents-view/agents-view-mode.ts index b867baaf06..77baf78057 100644 --- a/packages/coding-agent/src/modes/agents-view/agents-view-mode.ts +++ b/packages/coding-agent/src/modes/agents-view/agents-view-mode.ts @@ -160,7 +160,6 @@ export type AgentsViewPersistentState = { pendingExpandedAncestorSessionIds?: string[]; expandedSubagentParents?: Set; programShownParents?: Set; - inactiveExpanded?: boolean; statusMessage?: string; // Gathered once and reused across agents-view instances so the notices survive // re-entry and render the moment they resolve, even if the first view was left early. @@ -979,13 +978,6 @@ export class AgentsViewMode implements Component, Focusable { this.ui.requestRender(); return; } - if (this.keybindings.matches(data, "app.agents.inactiveCollapse")) { - this.persistentState.inactiveExpanded = !this.persistentState.inactiveExpanded; - this.rebuildRows(); - this.syncSelectedRowState(); - this.ui.requestRender(); - return; - } if (this.keybindings.matches(data, "app.agents.expand")) { const row = this.rows[this.selectedIndex]; if (row && row.descendantCount > 0) this.toggleSubagentList(row); @@ -1328,12 +1320,7 @@ export class AgentsViewMode implements Component, Focusable { computeRecursiveRollups(this.unifiedRecords, this.unifiedIndex), this.anchorSessionId, ); - this.rows = compactSessionRows( - this.allRows, - this.persistentState.inactiveExpanded === true || - ((this.replyTarget || this.renameTarget ? this.actionModeSearchQuery : this.editor.getText()) ?? "").trim() - .length > 0, - ); + this.rows = compactSessionRows(this.allRows); const index = selectedIdentity === undefined ? -1 : this.rows.findIndex((row) => row.identity === selectedIdentity); if (index >= 0) { @@ -2200,12 +2187,7 @@ export class AgentsViewMode implements Component, Focusable { computeRecursiveRollups(this.unifiedRecords, this.unifiedIndex), this.anchorSessionId, ); - this.rows = compactSessionRows( - this.allRows, - this.persistentState.inactiveExpanded === true || - ((this.replyTarget || this.renameTarget ? this.actionModeSearchQuery : this.editor.getText()) ?? "").trim() - .length > 0, - ); + this.rows = compactSessionRows(this.allRows); this.applyPendingAncestorExpansion(); this.restoreSelection(); this.ui.requestRender(); @@ -2552,13 +2534,7 @@ export class AgentsViewMode implements Component, Focusable { ); } if (item.type === "heading") { - const collapsed = - item.section === "inactive" && !this.rows.some((row) => row.depth === 0 && row.section === "inactive"); - const prefix = item.section === "inactive" ? `${collapsed ? "▸" : "▾"} ` : ""; - const hint = item.section === "inactive" ? ` · ${keyText("app.agents.inactiveCollapse")}` : ""; - return theme.bold( - truncateToWidth(`${prefix}${sectionTitle(item.section)} (${counts[item.section]})${hint}`, width), - ); + return theme.bold(truncateToWidth(`${sectionTitle(item.section)} (${counts[item.section]})`, width)); } return this.renderRow(item.row, width, layout); }); @@ -2612,8 +2588,8 @@ export class AgentsViewMode implements Component, Focusable { const actions = [ `${keyText("tui.select.confirm")} open ${keyText("app.agents.open")} open ${keyText("app.agents.new")} new`, `${keyText("app.agents.expand")} expand/collapse subagents ${keyText("app.agents.program")} program`, - `${keyText("app.agents.inactiveCollapse")} show/hide inactive ${keyText("app.shortcuts")} close actions`, `${keyText("app.agents.reply")} reply/resume ${keyText("app.agents.rename")} rename ${keyText("app.agents.delete")} stop/delete`, + `${keyText("app.shortcuts")} close actions`, ]; if (row) { const model = row.summary.model; @@ -2784,12 +2760,9 @@ type DisplayItem = | { type: "running-subagents"; row: AgentsViewRow } | { type: "row"; row: AgentsViewRow }; -function compactSessionRows(rows: readonly AgentsViewRow[], showInactive: boolean): AgentsViewRow[] { - let visible = true; - return rows.filter((row) => { - if (row.depth === 0) visible = showInactive || row.section !== "inactive"; - return visible && row.kind !== "subagent-summary"; - }); +// Summary rows fold into the running-subagents display items. +function compactSessionRows(rows: readonly AgentsViewRow[]): AgentsViewRow[] { + return rows.filter((row) => row.kind !== "subagent-summary"); } // Nested rows (subagent summaries and expanded subagents) always render in diff --git a/packages/coding-agent/test/agents-view-mode.test.ts b/packages/coding-agent/test/agents-view-mode.test.ts index 0bc0bca9fc..243dfbd125 100644 --- a/packages/coding-agent/test/agents-view-mode.test.ts +++ b/packages/coding-agent/test/agents-view-mode.test.ts @@ -863,7 +863,7 @@ describe("AgentsViewMode", () => { } }); - it("keeps collapsed inactive sessions out of navigation and reveals them for search", () => { + it("always renders inactive sessions; search is the only filter", () => { const live = summary({ sessionName: "live" }); const saved = summary({ id: "saved", @@ -874,8 +874,11 @@ describe("AgentsViewMode", () => { rosterStatus: "inactive", lifecycle: "archived", }); - const view = new AgentsViewMode({ config: {}, uiServices: createUiServices() }, { savedCatalogLoaded: true }); + // The stale pre-removal collapse flag must be ignored. + const persistentState = { savedCatalogLoaded: true, inactiveExpanded: false } as AgentsViewPersistentState; + const view = new AgentsViewMode({ config: {}, uiServices: createUiServices() }, persistentState); const rows = () => Reflect.get(view, "rows") as AgentsViewRow[]; + const showsSaved = () => rows().some((row) => row.summary.sessionId === saved.sessionId); try { Reflect.set(view, "lastListedSummaries", [live]); Reflect.set(view, "savedSessions", [ @@ -892,17 +895,12 @@ describe("AgentsViewMode", () => { }, ]); invoke("reconcileCatalogs", view); - expect(rows().map((row) => row.summary.sessionId)).toEqual([live.sessionId]); - invoke("moveSelection", view, 1); - expect(rows()[Reflect.get(view, "selectedIndex") as number]?.summary.sessionId).toBe(live.sessionId); - view.handleInput("\x1bi"); - expect(rows().some((row) => row.summary.sessionId === saved.sessionId)).toBe(true); + expect(showsSaved()).toBe(true); + // The removed Alt+I chord must not hide anything. view.handleInput("\x1bi"); - expect(rows().some((row) => row.summary.sessionId === saved.sessionId)).toBe(false); - invoke("setSearchQuery", view, "archive-match"); - expect(rows().some((row) => row.summary.sessionId === saved.sessionId)).toBe(true); - invoke("setSearchQuery", view, ""); - expect(rows().some((row) => row.summary.sessionId === saved.sessionId)).toBe(false); + expect(showsSaved()).toBe(true); + invoke("setSearchQuery", view, "no-such-session"); + expect(showsSaved()).toBe(false); } finally { stopThemeWatcher(); }