mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-11 16:52:16 +03:00
fix(app): show the main checkout's branch for Local in new sessions (#62061)
This commit is contained in:
committed by
GitHub
Unverified
parent
893e8dc43f
commit
fa2843f270
@@ -92,6 +92,35 @@ test("the location shortcuts choose worktrees from every state and keep cycling"
|
||||
await expect(view.editor).toBeFocused()
|
||||
})
|
||||
|
||||
test("Local shows and targets the main checkout when the draft opened in a worktree", async ({ page }) => {
|
||||
const root = "C:/OpenCode/LocalFromWorktree"
|
||||
|
||||
const worktree = `${root}/.worktrees/quiet-river`
|
||||
|
||||
const created: unknown[] = []
|
||||
|
||||
const view = await openDraft(page, {
|
||||
name: "LocalFromWorktree",
|
||||
project: { sandboxes: [worktree] },
|
||||
worktrees: () => [{ directory: root }, { directory: worktree, strategy: "git" }],
|
||||
vcs: (directory) =>
|
||||
directory === worktree
|
||||
? { current: "worktree-branch", default: "dev" }
|
||||
: { current: "checkout-branch", default: "dev" },
|
||||
onSessionCreate: (body) => void created.push(body.location),
|
||||
seed: { tabs: [{ draft: "draft_localfromworktree", directory: worktree }] },
|
||||
})
|
||||
|
||||
const screen = page.locator('[data-component="new-session"]')
|
||||
|
||||
await expect(newSessionWorktree(page)).toHaveText("Local")
|
||||
await expect(screen.getByText("checkout-branch", { exact: true })).toBeVisible()
|
||||
await expect(screen.getByText("worktree-branch", { exact: true })).toHaveCount(0)
|
||||
await view.editor.fill("Run in the main checkout")
|
||||
await submit(page).click()
|
||||
await expect.poll(() => created).toEqual([{ directory: root }])
|
||||
})
|
||||
|
||||
for (const binding of ["custom", "none"]) {
|
||||
test(`the picker tooltips reflect ${binding} shortcuts`, async ({ page }) => {
|
||||
const view = await openDraft(page, {
|
||||
|
||||
@@ -11,7 +11,6 @@ import { useLocal } from "@/providers/models/selection"
|
||||
import { useData, useServer } from "@/runtime/server/current"
|
||||
import { useServerSDK } from "@/runtime/server/client"
|
||||
import { useTabs } from "@/shell/tabs/tabs"
|
||||
import { useWorkspaceLocation } from "@/workspaces/location"
|
||||
import { createWorktree } from "@/workspaces/create"
|
||||
import { showToast } from "@/shell/notifications/toast"
|
||||
import type { DraftMcpControls } from "./mcp"
|
||||
@@ -72,6 +71,7 @@ type Started = Awaited<ReturnType<NewSessionComposerAdapter["start"]>>
|
||||
export function createNewSessionComposerAdapter(props: {
|
||||
draftID: string
|
||||
worktree: () => string
|
||||
root: () => string
|
||||
branch: () => string | undefined
|
||||
submitted: () => void
|
||||
mcp: DraftMcpControls
|
||||
@@ -84,7 +84,6 @@ export function createNewSessionComposerAdapter(props: {
|
||||
const server = useServer()
|
||||
const serverSDK = useServerSDK()
|
||||
const tabs = useTabs()
|
||||
const location = useWorkspaceLocation()
|
||||
const language = useLanguage()
|
||||
const model = createComposerModelSelection({ agent: () => local.agent.current() })
|
||||
const controls = createComposerControls({ model })
|
||||
@@ -97,11 +96,7 @@ export function createNewSessionComposerAdapter(props: {
|
||||
working: () => false,
|
||||
submitted: props.submitted,
|
||||
start(selection, submission, message) {
|
||||
const currentDirectory = location().directory
|
||||
|
||||
const projectDirectory =
|
||||
data.location.info({ directory: currentDirectory })?.project.canonical ?? currentDirectory
|
||||
|
||||
const projectDirectory = props.root()
|
||||
const worktree = props.worktree()
|
||||
const directory = worktree === "main" ? projectDirectory : worktree
|
||||
const sessionID = Session.ID.create()
|
||||
|
||||
@@ -44,6 +44,7 @@ export default function NewSessionPage(props: { draftId: string }) {
|
||||
const composer = createNewSessionComposerAdapter({
|
||||
draftID: props.draftId,
|
||||
worktree: workspace.selection.value,
|
||||
root: workspace.project.root,
|
||||
branch: workspace.bar.branch,
|
||||
submitted: workspace.selection.remember,
|
||||
mcp,
|
||||
|
||||
@@ -38,19 +38,24 @@ describe("new session workspace selection", () => {
|
||||
expect(resolveNewSessionWorktree(input)).toBe(expected)
|
||||
})
|
||||
|
||||
const branch = (worktree: string) => (worktree === "/project/feature" ? "feature" : undefined)
|
||||
const branches = new Map([
|
||||
["/project", "dev"],
|
||||
["/project/feature", "feature"],
|
||||
])
|
||||
|
||||
const branch = (worktree: string) => branches.get(worktree)
|
||||
|
||||
test.each([
|
||||
{ worktree: "main", directory: "/project/feature", createBranch: undefined, expected: "feature" },
|
||||
{ worktree: "create", directory: "/project/feature", createBranch: undefined, expected: "feature" },
|
||||
{ worktree: "/project/feature", directory: "/project", createBranch: undefined, expected: "feature" },
|
||||
{ worktree: "/missing", directory: "/project/feature", createBranch: undefined, expected: undefined },
|
||||
{ worktree: "create", directory: "/project/feature", createBranch: "release", expected: "release" },
|
||||
])("resolves the branch for $worktree in $directory (new branch: $createBranch)", (row) => {
|
||||
{ worktree: "main", root: "/project", createBranch: undefined, expected: "dev" },
|
||||
{ worktree: "create", root: "/project", createBranch: undefined, expected: "dev" },
|
||||
{ worktree: "/project/feature", root: "/project", createBranch: undefined, expected: "feature" },
|
||||
{ worktree: "/missing", root: "/project", createBranch: undefined, expected: undefined },
|
||||
{ worktree: "create", root: "/project", createBranch: "release", expected: "release" },
|
||||
])("resolves the branch for $worktree from $root (new branch: $createBranch)", (row) => {
|
||||
expect(
|
||||
resolveNewSessionBranch({
|
||||
worktree: row.worktree,
|
||||
directory: row.directory,
|
||||
root: row.root,
|
||||
createBranch: row.createBranch,
|
||||
worktreeBranch: branch,
|
||||
}),
|
||||
|
||||
@@ -26,12 +26,12 @@ export function resolveNewSessionWorktree(input: { enabled: boolean; selected?:
|
||||
|
||||
export function resolveNewSessionBranch(input: {
|
||||
worktree: string
|
||||
directory: string
|
||||
root: string
|
||||
createBranch?: string
|
||||
worktreeBranch: (worktree: string) => string | undefined
|
||||
}) {
|
||||
if (input.worktree === "create" && input.createBranch) return input.createBranch
|
||||
const directory = input.worktree === "main" || input.worktree === "create" ? input.directory : input.worktree
|
||||
const directory = input.worktree === "main" || input.worktree === "create" ? input.root : input.worktree
|
||||
|
||||
return input.worktreeBranch(directory)
|
||||
}
|
||||
@@ -167,8 +167,13 @@ export function createNewSessionWorkspaceController(input: {
|
||||
}),
|
||||
)
|
||||
|
||||
const projectRoot = createMemo(() => currentProject()?.worktree ?? sdk().directory)
|
||||
const branchDirectory = () => (value() === "create" ? projectRoot() : sdk().directory)
|
||||
// A draft opened from a worktree session keeps that worktree as its directory; Local still runs in the main checkout.
|
||||
const projectRoot = createMemo(
|
||||
() =>
|
||||
data.location.info({ directory: sdk().directory })?.project.canonical ??
|
||||
currentProject()?.worktree ??
|
||||
sdk().directory,
|
||||
)
|
||||
|
||||
createEffect(() => {
|
||||
void Promise.all([
|
||||
@@ -178,7 +183,7 @@ export function createNewSessionWorkspaceController(input: {
|
||||
]).catch(() => undefined)
|
||||
})
|
||||
createEffect(() => {
|
||||
if (value() !== "create" || sameDirectory(projectRoot(), sdk().directory)) return
|
||||
if ((value() !== "main" && value() !== "create") || sameDirectory(projectRoot(), sdk().directory)) return
|
||||
void data.location.vcs.sync({ directory: projectRoot() }).catch(() => undefined)
|
||||
})
|
||||
// Only the selected worktree feeds the branch label. Syncing every worktree in the inventory boots
|
||||
@@ -197,7 +202,7 @@ export function createNewSessionWorkspaceController(input: {
|
||||
const branch = createMemo(() =>
|
||||
resolveNewSessionBranch({
|
||||
worktree: value(),
|
||||
directory: branchDirectory(),
|
||||
root: projectRoot(),
|
||||
createBranch: input.selectedBranch(),
|
||||
worktreeBranch: (worktree) => data.location.vcs.info({ directory: worktree })?.branch.current,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user