From ec19f7319575e1db7c1300091ea4b0a5451e8234 Mon Sep 17 00:00:00 2001 From: Brendan Allan Date: Sun, 28 Jun 2026 02:58:28 +0800 Subject: [PATCH] fix(app): resolve sandbox project edits --- packages/app/src/context/global-sync/utils.test.ts | 10 +++++++++- packages/app/src/context/global-sync/utils.ts | 9 +++++++++ packages/app/src/context/global.tsx | 9 +++++---- packages/app/src/context/layout.tsx | 9 +++++---- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/packages/app/src/context/global-sync/utils.test.ts b/packages/app/src/context/global-sync/utils.test.ts index 406c0f124e..a7209f56c3 100644 --- a/packages/app/src/context/global-sync/utils.test.ts +++ b/packages/app/src/context/global-sync/utils.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import type { Agent } from "@opencode-ai/sdk/v2/client" -import { directoryKey, normalizeAgentList } from "./utils" +import { directoryKey, findProjectMetadata, normalizeAgentList } from "./utils" const agent = (name = "build") => ({ @@ -50,3 +50,11 @@ describe("directoryKey", () => { expect(String(directoryKey("/"))).toBe("/") }) }) + +describe("findProjectMetadata", () => { + test("matches sandbox directories to their root project", () => { + const project = { id: "project", worktree: "/repo", sandboxes: ["/repo-worktree"] } + + expect(findProjectMetadata([project], { worktree: "/repo-worktree" })).toBe(project) + }) +}) diff --git a/packages/app/src/context/global-sync/utils.ts b/packages/app/src/context/global-sync/utils.ts index e54bc88d4d..1420d591c9 100644 --- a/packages/app/src/context/global-sync/utils.ts +++ b/packages/app/src/context/global-sync/utils.ts @@ -49,3 +49,12 @@ export function sanitizeProject(project: Project) { }, } } + +export function findProjectMetadata( + projects: T[], + input: { projectID?: string; worktree: string }, +) { + const byID = input.projectID ? projects.find((project) => project.id === input.projectID) : undefined + if (byID) return byID + return projects.find((project) => project.worktree === input.worktree || project.sandboxes?.includes(input.worktree)) +} diff --git a/packages/app/src/context/global.tsx b/packages/app/src/context/global.tsx index 138b17c4fc..9c99fb7b4a 100644 --- a/packages/app/src/context/global.tsx +++ b/packages/app/src/context/global.tsx @@ -5,6 +5,7 @@ import { createServerProjects, ServerConnection, useServer } from "./server" import { useServerHealth } from "@/utils/server-health" import { createServerSdkContext } from "./server-sdk" import { createServerSyncContext } from "./server-sync" +import { findProjectMetadata } from "./global-sync/utils" import { getOwner } from "solid-js/web" import { QueryClient } from "@tanstack/solid-query" import type { ServerScope } from "@/utils/server-scope" @@ -111,10 +112,10 @@ function createServerCtx( function enrich(project: { worktree: string; expanded: boolean }) { const [childStore] = sync.child(project.worktree, { bootstrap: false }) - const projectID = childStore.project - const metadata = projectID - ? sync.data.project.find((x) => x.id === projectID) - : sync.data.project.find((x) => x.worktree === project.worktree) + const metadata = findProjectMetadata(sync.data.project, { + projectID: childStore.project, + worktree: project.worktree, + }) // Preserve local icon override from per-workspace localStorage cache (childStore.icon). // Without this, different subdirectories of the same git repo would share the same diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index eb97b400c8..c708129a4e 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -18,6 +18,7 @@ import { migrateLegacySessionStateKeys, ServerScope, SessionStateKey } from "@/u import { createSessionKeyReader, ensureSessionKey, pruneSessionKeys } from "./layout-helpers" import { requireServerKey } from "@/utils/session-route" import { type DraftTab, useTabs } from "./tabs" +import { findProjectMetadata } from "./global-sync/utils" export { createSessionKeyReader, ensureSessionKey, pruneSessionKeys } @@ -430,10 +431,10 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( function enrich(project: { worktree: string; expanded: boolean }) { const [childStore] = serverSync().child(project.worktree, { bootstrap: false }) - const projectID = childStore.project - const metadata = projectID - ? serverSync().data.project.find((x) => x.id === projectID) - : serverSync().data.project.find((x) => x.worktree === project.worktree) + const metadata = findProjectMetadata(serverSync().data.project, { + projectID: childStore.project, + worktree: project.worktree, + }) // Preserve local icon override from per-workspace localStorage cache (childStore.icon). // Without this, different subdirectories of the same git repo would share the same