Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Removed the inactive-session collapse (Alt+I): inactive sessions always render in the agents view, and search remains the filter.
2 changes: 0 additions & 2 deletions packages/coding-agent/src/core/keybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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"],
Expand Down
41 changes: 7 additions & 34 deletions packages/coding-agent/src/modes/agents-view/agents-view-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ export type AgentsViewPersistentState = {
pendingExpandedAncestorSessionIds?: string[];
expandedSubagentParents?: Set<string>;
programShownParents?: Set<string>;
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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
});
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
22 changes: 10 additions & 12 deletions packages/coding-agent/test/agents-view-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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", [
Expand All @@ -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();
}
Expand Down
Loading