From 667722897ea99a79108389dfbdb0c4a99947819f Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:38:08 +0800 Subject: [PATCH] fix(app): identify session worktrees from project inventory (#45153) Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com> --- .../src/session/timeline/message-timeline.tsx | 11 +++++----- packages/app/src/shell/layout/helpers.test.ts | 22 +++++++++++++++++++ packages/app/src/shell/layout/helpers.ts | 7 ++---- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/app/src/session/timeline/message-timeline.tsx b/packages/app/src/session/timeline/message-timeline.tsx index 375cfb321a2..a73b758460a 100644 --- a/packages/app/src/session/timeline/message-timeline.tsx +++ b/packages/app/src/session/timeline/message-timeline.tsx @@ -342,12 +342,11 @@ function MessageTimelineView( const projection = props.data.projection const sessionDirectory = createMemo(() => props.session.data.info()?.location.directory ?? sdk().directory) const project = createMemo(() => { - const projectID = props.session.data.info()?.projectID - const value = projectID - ? data.project.get(projectID) - : data.project.list().find((item) => containsDirectory(item.canonical, sessionDirectory())) - if (!value) return undefined - return { ...value, worktree: value.canonical, worktrees: [] } + const session = props.session.data.info() + const projects = server.ctx.sync.data.project + return session + ? projectForSession(session, projects) + : projects.find((item) => containsDirectory(item.worktree, sessionDirectory())) }) const workspaceSession = createMemo(() => isWorkspaceDirectory(project(), sessionDirectory())) const showProjectIcon = () => diff --git a/packages/app/src/shell/layout/helpers.test.ts b/packages/app/src/shell/layout/helpers.test.ts index 36e425ba809..b000c4bc890 100644 --- a/packages/app/src/shell/layout/helpers.test.ts +++ b/packages/app/src/shell/layout/helpers.test.ts @@ -12,6 +12,7 @@ import { homeProjectDirectories, homeSessionServerStatus, latestRootSession, + projectForSession, sortedRootSessions, toggleHomeProjectSelection, } from "./helpers" @@ -167,6 +168,27 @@ describe("layout workspace helpers", () => { expect(childSessionOnPath(list, "root", "other")).toBeUndefined() }) + test("keeps the enriched workspace inventory when matching a session by project id", () => { + const project = { + id: "project", + worktree: "/repo", + sandboxes: ["/workspaces/feature"], + worktrees: [{ directory: "/repo" }, { directory: "/workspaces/feature", strategy: "git" }], + } + + expect(projectForSession(session({ id: "feature", directory: "/workspaces/feature/packages/app" }), [project])).toBe( + project, + ) + }) + + test("finds the enriched project for a nested workspace when its session project id is stale", () => { + const project = { id: "updated", worktree: "/repo", sandboxes: ["/workspaces/feature"] } + + expect(projectForSession(session({ id: "feature", directory: "/workspaces/feature/packages/app" }), [project])).toBe( + project, + ) + }) + test("formats fallback project display name", () => { expect(displayName({ worktree: "/tmp/app" })).toBe("app") expect(displayName({ worktree: "/tmp/app", name: "My App" })).toBe("My App") diff --git a/packages/app/src/shell/layout/helpers.ts b/packages/app/src/shell/layout/helpers.ts index 0fd0054c292..b83424d806e 100644 --- a/packages/app/src/shell/layout/helpers.ts +++ b/packages/app/src/shell/layout/helpers.ts @@ -1,6 +1,7 @@ import { getFilename } from "@opencode-ai/util/path" import type { SessionInfo } from "@opencode-ai/client/promise" import { pathKey } from "@/workspaces/path-key" +import { isProjectDirectory } from "@/workspaces/paths" import type { ServerConnection } from "@/runtime/server/registry" import type { HomeProjectSelection } from "@/shell/state/layout" @@ -100,11 +101,7 @@ export function projectForSession - pathKey(project.worktree) === directory || project.sandboxes?.some((sandbox) => pathKey(sandbox) === directory), - ) + return projects.find((project) => isProjectDirectory(project, session.location.directory)) } export const errorMessage = (err: unknown, fallback: string) => {