Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions apps/web/src/components/ChatView.logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import {
shouldWriteThreadErrorToCurrentServerThread,
waitForRevertedMessage,
prepareRevertedMessageAttachments,
resolveProjectGitCwd,
} from "./ChatView.logic";

describe("agent browser close confirmation", () => {
Expand Down Expand Up @@ -2432,3 +2433,20 @@ describe("worktree setup visibility", () => {
});
});
});

describe("resolveProjectGitCwd", () => {
it("uses the repo of a workspace file that lists one repo", () => {
expect(resolveProjectGitCwd({ workspaceRoot: "/ws", repoRoots: ["/ws/api"] })).toBe("/ws/api");
});

it("keeps the workspace root of an ordinary project", () => {
expect(resolveProjectGitCwd({ workspaceRoot: "/repo", repoRoots: ["/repo"] })).toBe("/repo");
expect(resolveProjectGitCwd({ workspaceRoot: "/repo" })).toBe("/repo");
});

it("leaves multi-repo projects on the workspace root, since their git surfaces fan out", () => {
expect(resolveProjectGitCwd({ workspaceRoot: "/ws", repoRoots: ["/ws/api", "/ws/web"] })).toBe(
"/ws",
);
});
});
17 changes: 17 additions & 0 deletions apps/web/src/components/ChatView.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
squashAtomCommandFailure,
type AtomCommandResult,
} from "@t3tools/client-runtime/state/runtime";
import { resolveAnchorRepoRoot } from "@t3tools/shared/git";
import { videoMimeType } from "@t3tools/shared/video";
import {
appendCodexArtifactTemplateUsePrompt,
Expand Down Expand Up @@ -1385,3 +1386,19 @@ export function restorePlanFollowUpComposer(input: {
detectTrigger: true,
});
}

/**
* The checkout the chat view's single-repo git surfaces run in: status, the
* header's git actions, checkout switching and PR checkout. A `.code-workspace`
* project's `workspaceRoot` is only the folder holding the file, so a
* workspace with one repo uses that repo. Multi-repo projects keep
* `workspaceRoot` here because their git surfaces fan out per repo instead.
*/
export function resolveProjectGitCwd(project: {
readonly workspaceRoot: string;
readonly repoRoots?: ReadonlyArray<string> | undefined;
}): string {
return (project.repoRoots?.length ?? 0) > 1
? project.workspaceRoot
: resolveAnchorRepoRoot(project);
}
14 changes: 8 additions & 6 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ import {
codexArtifactTemplatePromptToAppend,
waitForStartedServerThread,
shouldRefocusComposerOnWindowFocus,
resolveProjectGitCwd,
} from "./ChatView.logic";
import type { ThreadSyncPhase } from "../threadSync";
import { useLocalStorage } from "~/hooks/useLocalStorage";
Expand Down Expand Up @@ -3653,7 +3654,8 @@ export default function ChatView(props: ChatViewProps) {
// repo root, swapping in the thread's worktree for roots an isolated run
// covers. A single-repo project uses the worktree-aware status cwd.
const isMultiRepo = (activeProject?.repoRoots?.length ?? 0) > 1;
const gitStatusCwd = activeThread?.worktreePath ?? gitCwd;
const projectGitCwd = activeProject ? resolveProjectGitCwd(activeProject) : null;
const gitStatusCwd = activeThread?.worktreePath ?? projectGitCwd;
const threadWorktrees = activeThread?.worktrees;
const multiRepoStatusRoots = useMemo(() => {
if (!isMultiRepo || !activeProject?.repoRoots) return null;
Expand Down Expand Up @@ -6300,7 +6302,7 @@ export default function ChatView(props: ChatViewProps) {
}, [activeBranchMismatchKey, showBranchMismatchBanner]);
const handleSwitchCheckoutToThread = useCallback(async () => {
if (
!activeProjectCwd ||
!projectGitCwd ||
!activeThread ||
!localCheckoutBranchMismatch ||
isRestoringThreadBranch
Expand All @@ -6311,7 +6313,7 @@ export default function ChatView(props: ChatViewProps) {
const checkoutResult = await switchGitRef({
environmentId,
input: {
cwd: activeProjectCwd,
cwd: projectGitCwd,
refName: localCheckoutBranchMismatch.threadBranch,
},
});
Expand Down Expand Up @@ -6354,7 +6356,7 @@ export default function ChatView(props: ChatViewProps) {
setIsRestoringThreadBranch(false);
scheduleComposerFocus();
}, [
activeProjectCwd,
projectGitCwd,
activeThread,
environmentId,
gitStatusQuery,
Expand Down Expand Up @@ -9906,7 +9908,7 @@ export default function ChatView(props: ChatViewProps) {
keybindings={keybindings}
availableEditors={availableEditors}
rightPanelOpen={rightPanelOpen}
gitCwd={gitCwd}
gitCwd={gitStatusCwd}
onNewThreadInProject={handleNewThreadInActiveProject}
{...(activeDraftLogicalProjectKey
? { onOpenProjectSettings: handleOpenDraftProjectSettings }
Expand Down Expand Up @@ -10364,7 +10366,7 @@ export default function ChatView(props: ChatViewProps) {
open
environmentId={activeThread.environmentId}
threadId={activeThread.id}
cwd={activeProject?.workspaceRoot ?? null}
cwd={projectGitCwd}
initialReference={pullRequestDialogState.initialReference}
onOpenChange={(open) => {
if (!open) {
Expand Down
Loading