fix(app): identify session worktrees from project inventory (#45153)

Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
This commit is contained in:
opencode-agent[bot]
2026-08-26 14:38:08 +08:00
committed by GitHub
Unverified
parent d12dbd12a9
commit 667722897e
3 changed files with 29 additions and 11 deletions
@@ -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 = () =>
@@ -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")
+2 -5
View File
@@ -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<T extends { id?: string; worktree: string; san
) {
const direct = byID.get(session.projectID)
if (direct) return direct
const directory = pathKey(session.location.directory)
return projects.find(
(project) =>
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) => {