Merge pull request #12845 from Kilo-Org/agent-manager-12806-navigation

fix(vscode): add project-local navigation hints
This commit is contained in:
Marius
2026-08-04 11:48:27 +02:00
committed by GitHub
5 changed files with 67 additions and 0 deletions
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Show previous and next navigation hints using each project's own Agent Manager sidebar order.
@@ -0,0 +1,25 @@
import { describe, expect, it } from "bun:test"
import { projectAdjacentHint } from "../../webview-ui/agent-manager/project-local-navigation"
describe("projectAdjacentHint", () => {
it("does not leak a hint to another project with the same raw ID", () => {
expect(projectAdjacentHint("project-a", "project-a", "shared", "local", ["local", "shared"], "prev", "next")).toBe(
"next",
)
expect(projectAdjacentHint("project-b", "project-a", "shared", "local", ["local", "shared"], "prev", "next")).toBe(
"",
)
})
it("uses the active project's local sidebar order", () => {
expect(projectAdjacentHint("project-a", "project-a", "shared", "local", ["local", "shared"], "prev", "next")).toBe(
"next",
)
expect(projectAdjacentHint("project-a", "project-a", "local", "shared", ["local", "shared"], "prev", "next")).toBe(
"prev",
)
expect(
projectAdjacentHint("project-b", "project-b", "shared", "local", ["local", "other", "shared"], "prev", "next"),
).toBe("")
})
})
@@ -218,6 +218,7 @@ export const ProjectList: Component<Props> = (props) => {
sessions={props.sessions[project.id]}
selectedProject={props.selectedProject}
selection={props.selection}
currentSessionID={props.currentSessionID}
bindings={props.bindings}
t={props.t}
onSelectLocal={(projectId) => select({ projectId, kind: "local" })}
@@ -20,6 +20,7 @@ import type {
} from "../src/types/messages"
import type { LanguageContextValue } from "../src/context/language"
import { useVSCode } from "../src/context/vscode"
import { projectAdjacentHint, projectSidebarOrder } from "./project-local-navigation"
import SectionHeader from "./SectionHeader"
import { WorktreeItem } from "./WorktreeItem"
import { UnassignedSessionsSection } from "./UnassignedSessionsSection"
@@ -44,6 +45,7 @@ interface Props {
sessions?: ProjectSessionInfo[]
selectedProject?: string
selection?: string
currentSessionID?: () => string | undefined
bindings: Record<string, string>
t: LanguageContextValue["t"]
onSelectLocal: (projectId: string) => void
@@ -100,9 +102,23 @@ export const ProjectSidebarBody: Component<Props> = (props) => {
const members = (sectionId: string) => sorted().filter((wt) => wt.sectionId === sectionId)
const ungrouped = createMemo(() => sorted().filter((wt) => !wt.sectionId))
const top = createMemo(() => buildTopLevelItems(sections(), ungrouped(), sorted(), order()))
const sidebarOrder = createMemo(() =>
projectSidebarOrder(top(), sorted(), sections(), members, state()?.sessionsCollapsed ? [] : localSessions()),
)
const post = (message: Record<string, unknown>) =>
vscode.postMessage({ ...message, projectId: props.project.id } as never)
const navHint = (id: string) =>
projectAdjacentHint(
props.project.id,
props.selectedProject,
id,
props.selection ?? props.currentSessionID?.(),
sidebarOrder(),
props.bindings.previousSession ?? "",
props.bindings.nextSession ?? "",
)
const scope = (kind: "section" | "worktree", id: string) => `${props.project.id}:${kind}:${id}`
const parse = (kind: "section" | "worktree", value: unknown) => {
if (typeof value !== "string") return
@@ -226,6 +242,7 @@ export const ProjectSidebarBody: Component<Props> = (props) => {
working={runs()[worktree.id]?.state === "running"}
stale={state()?.staleWorktreeIds?.includes(worktree.id) === true}
stats={props.stats?.[worktree.id]}
navHint={navHint(worktree.id)}
sessions={sessions(worktree.id).length}
grouped={isGrouped(worktree)}
groupStart={isGroupStart(worktree, idx(), list)}
@@ -0,0 +1,19 @@
import { adjacentHint } from "./navigate"
import { buildSidebarOrder } from "./section-helpers"
export function projectSidebarOrder(...args: Parameters<typeof buildSidebarOrder>): string[] {
return buildSidebarOrder(...args).map((item) => item.id)
}
export function projectAdjacentHint(
projectId: string,
activeProjectId: string | undefined,
itemId: string,
activeId: string | undefined,
flatIds: string[],
prev: string,
next: string,
): string {
if (projectId !== activeProjectId) return ""
return adjacentHint(itemId, activeId, flatIds, prev, next)
}