diff --git a/.changeset/rapid-recents-hide.md b/.changeset/rapid-recents-hide.md new file mode 100644 index 00000000000..cc87184178f --- /dev/null +++ b/.changeset/rapid-recents-hide.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Hide sub-agent sessions from recent session shortcuts in the extension. diff --git a/packages/kilo-vscode/tests/unit/session-utils.test.ts b/packages/kilo-vscode/tests/unit/session-utils.test.ts index e308a576e3d..d90cf8572d3 100644 --- a/packages/kilo-vscode/tests/unit/session-utils.test.ts +++ b/packages/kilo-vscode/tests/unit/session-utils.test.ts @@ -9,6 +9,7 @@ import { buildCostBreakdown, collapseCostBreakdown, childID, + recentSessions, } from "../../webview-ui/src/context/session-utils" import type { Part } from "../../webview-ui/src/types/messages" @@ -84,6 +85,36 @@ describe("computeStatus", () => { }) }) +describe("recentSessions", () => { + const at = (day: number) => `2026-01-${String(day).padStart(2, "0")}T00:00:00.000Z` + const info = (id: string, day: number, parentID?: string | null) => ({ + id, + updatedAt: at(day), + ...(parentID === undefined ? {} : { parentID }), + }) + + it("keeps the newest root sessions after removing sub-agents", () => { + const result = recentSessions([ + info("old-root", 1), + info("child", 6, "old-root"), + info("new-root", 5), + info("blank-parent", 4, ""), + info("mid-root", 3, null), + info("fourth-root", 2), + ]) + + expect(result.map((session) => session.id)).toEqual(["new-root", "mid-root", "fourth-root"]) + }) + + it("does not mutate the session list while sorting recents", () => { + const sessions = [info("old", 1), info("new", 3), info("mid", 2)] + + recentSessions(sessions) + + expect(sessions.map((session) => session.id)).toEqual(["old", "new", "mid"]) + }) +}) + describe("calcTotalCost", () => { it("returns 0 for empty messages", () => { expect(calcTotalCost([])).toBe(0) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/navigate.ts b/packages/kilo-vscode/webview-ui/agent-manager/navigate.ts index 3ab7375bec3..8be2f3bf481 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/navigate.ts +++ b/packages/kilo-vscode/webview-ui/agent-manager/navigate.ts @@ -7,6 +7,8 @@ * Returns the action to take: select a session by ID, go to local, or do nothing. */ +import { isRootSession } from "../src/context/session-utils" + /** Sentinel value for the local repo selection. */ export const LOCAL = "local" as const @@ -20,7 +22,7 @@ export function filterUnassignedSessions( local: Set, ): T[] { return [...sessions] - .filter((s) => (s.parentID === undefined || s.parentID === null) && !worktree.has(s.id) && !local.has(s.id)) + .filter((s) => isRootSession(s) && !worktree.has(s.id) && !local.has(s.id)) .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) } diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx index c660b5b32aa..9bd1da67bfe 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx @@ -17,6 +17,7 @@ import { createAutoScroll } from "@kilocode/kilo-ui/hooks" import { useSession } from "../../context/session" import { useServer } from "../../context/server" import { useLanguage } from "../../context/language" +import { recentSessions } from "../../context/session-utils" import { formatRelativeDate } from "../../utils/date" import { FeedbackDialog } from "./FeedbackDialog" import { VscodeSessionTurn } from "./VscodeSessionTurn" @@ -93,11 +94,7 @@ export const MessageList: Component = (props) => { ) const isEmpty = () => turns().length === 0 && !session.loading() && !boundary() - const recent = createMemo(() => - [...session.sessions()] - .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) - .slice(0, 3), - ) + const recent = createMemo(() => recentSessions(session.sessions())) const activeUserID = createMemo(() => getActiveUserMessageID(session.messages(), session.statusInfo())) const queuedIDs = createMemo(() => new Set(queuedUserMessageIDs(session.messages(), session.statusInfo()))) diff --git a/packages/kilo-vscode/webview-ui/src/context/session-utils.ts b/packages/kilo-vscode/webview-ui/src/context/session-utils.ts index 2544246964a..4915e93222d 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session-utils.ts +++ b/packages/kilo-vscode/webview-ui/src/context/session-utils.ts @@ -14,6 +14,21 @@ export function snapshotProgress(part: SnapshotPart | undefined): boolean { return (part.text ?? "").includes("Initializing snapshot") } +type ParentSession = { parentID?: string | null } + +type RecentSession = ParentSession & { updatedAt: string } + +export function isRootSession(session: ParentSession): boolean { + return session.parentID === undefined || session.parentID === null +} + +export function recentSessions(sessions: T[]): T[] { + return [...sessions] + .filter(isRootSession) + .sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) + .slice(0, 3) +} + /** Minimal message shape for cost breakdown helpers. */ export type CostMessage = { id: string; role: string; cost?: number }