Merge branch 'main' into dev
# Conflicts: # packages/server/src/server/session.ts
This commit is contained in:
@@ -1225,6 +1225,8 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
},
|
},
|
||||||
prefsButton: {
|
prefsButton: {
|
||||||
height: 28,
|
height: 28,
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: theme.spacing[1],
|
gap: theme.spacing[1],
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||||||
import { ChevronDown, GitBranch } from "lucide-react-native";
|
import { ChevronDown, GitBranch } from "lucide-react-native";
|
||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { Combobox, ComboboxItem, type ComboboxOption } from "@/components/ui/combobox";
|
import { Combobox, ComboboxItem, type ComboboxOption } from "@/components/ui/combobox";
|
||||||
|
import { useIsCompactFormFactor } from "@/constants/layout";
|
||||||
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
|
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
|
||||||
import { useToast } from "@/contexts/toast-context";
|
import { useToast } from "@/contexts/toast-context";
|
||||||
import { useBranchSwitcher } from "@/hooks/use-branch-switcher";
|
import { useBranchSwitcher } from "@/hooks/use-branch-switcher";
|
||||||
@@ -24,6 +25,7 @@ export function BranchSwitcher({
|
|||||||
isGitCheckout,
|
isGitCheckout,
|
||||||
}: BranchSwitcherProps) {
|
}: BranchSwitcherProps) {
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
|
const isCompact = useIsCompactFormFactor();
|
||||||
const anchorRef = useRef<View>(null);
|
const anchorRef = useRef<View>(null);
|
||||||
const client = useHostRuntimeClient(serverId);
|
const client = useHostRuntimeClient(serverId);
|
||||||
const isConnected = useHostRuntimeIsConnected(serverId);
|
const isConnected = useHostRuntimeIsConnected(serverId);
|
||||||
@@ -65,7 +67,7 @@ export function BranchSwitcher({
|
|||||||
<Text testID="workspace-header-title" style={styles.headerTitle} numberOfLines={1}>
|
<Text testID="workspace-header-title" style={styles.headerTitle} numberOfLines={1}>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
<ChevronDown size={12} color={theme.colors.foregroundMuted} />
|
{!isCompact ? <ChevronDown size={12} color={theme.colors.foregroundMuted} /> : null}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Combobox
|
<Combobox
|
||||||
options={branchOptions}
|
options={branchOptions}
|
||||||
@@ -111,6 +113,10 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: theme.spacing[1],
|
gap: theme.spacing[1],
|
||||||
|
marginLeft: {
|
||||||
|
xs: -theme.spacing[2],
|
||||||
|
md: 0,
|
||||||
|
},
|
||||||
paddingVertical: theme.spacing[1],
|
paddingVertical: theme.spacing[1],
|
||||||
paddingHorizontal: theme.spacing[2],
|
paddingHorizontal: theme.spacing[2],
|
||||||
borderRadius: theme.borderRadius.md,
|
borderRadius: theme.borderRadius.md,
|
||||||
|
|||||||
@@ -644,7 +644,9 @@ export function CombinedModelSelector({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ProviderIcon size={theme.iconSize.md} color={theme.colors.foregroundMuted} />
|
<ProviderIcon size={theme.iconSize.md} color={theme.colors.foregroundMuted} />
|
||||||
<Text style={styles.triggerText}>{triggerLabel}</Text>
|
<Text style={styles.triggerText} numberOfLines={1} ellipsizeMode="tail">
|
||||||
|
{triggerLabel}
|
||||||
|
</Text>
|
||||||
<ChevronDown size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
<ChevronDown size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -714,6 +716,8 @@ export function CombinedModelSelector({
|
|||||||
const styles = StyleSheet.create((theme) => ({
|
const styles = StyleSheet.create((theme) => ({
|
||||||
trigger: {
|
trigger: {
|
||||||
height: 28,
|
height: 28,
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
@@ -731,6 +735,8 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
opacity: 0.5,
|
opacity: 0.5,
|
||||||
},
|
},
|
||||||
triggerText: {
|
triggerText: {
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
color: theme.colors.foregroundMuted,
|
color: theme.colors.foregroundMuted,
|
||||||
fontSize: theme.fontSize.sm,
|
fontSize: theme.fontSize.sm,
|
||||||
fontWeight: theme.fontWeight.normal,
|
fontWeight: theme.fontWeight.normal,
|
||||||
|
|||||||
@@ -1333,11 +1333,15 @@ const styles = StyleSheet.create(((theme: any) => ({
|
|||||||
marginHorizontal: -6,
|
marginHorizontal: -6,
|
||||||
},
|
},
|
||||||
leftButtonGroup: {
|
leftButtonGroup: {
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
|
flexGrow: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "flex-end",
|
alignItems: "flex-end",
|
||||||
gap: theme.spacing[1],
|
gap: theme.spacing[1],
|
||||||
},
|
},
|
||||||
rightButtonGroup: {
|
rightButtonGroup: {
|
||||||
|
flexShrink: 0,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: isWeb ? theme.spacing[2] : theme.spacing[1],
|
gap: isWeb ? theme.spacing[2] : theme.spacing[1],
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ function WorkspaceStatusIndicator({
|
|||||||
if (shouldShowSyncedLoader) {
|
if (shouldShowSyncedLoader) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.workspaceStatusDot}>
|
<View style={styles.workspaceStatusDot}>
|
||||||
<SyncedLoader size={11} color={theme.colors.palette.amber[500]} />
|
<SyncedLoader size={11} color={theme.colorScheme === "light" ? theme.colors.palette.amber[700] : theme.colors.palette.amber[500]} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -406,7 +406,7 @@ function ProjectLeadingVisual({
|
|||||||
if (shouldShowSyncedLoader) {
|
if (shouldShowSyncedLoader) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.projectLeadingVisualSlot}>
|
<View style={styles.projectLeadingVisualSlot}>
|
||||||
<SyncedLoader size={11} color={theme.colors.palette.amber[500]} />
|
<SyncedLoader size={11} color={theme.colorScheme === "light" ? theme.colors.palette.amber[700] : theme.colors.palette.amber[500]} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const DOT_COUNT = DOT_SEQUENCE.length;
|
|||||||
const GRID_ROWS = 3;
|
const GRID_ROWS = 3;
|
||||||
const GRID_COLUMNS = 2;
|
const GRID_COLUMNS = 2;
|
||||||
const SNAKE_SEGMENT_OFFSETS = [0, -1, -2, -3, -4] as const;
|
const SNAKE_SEGMENT_OFFSETS = [0, -1, -2, -3, -4] as const;
|
||||||
const SNAKE_OPACITIES = [1, 0.72, 0.46, 0.22, 0] as const;
|
const SNAKE_OPACITIES = [1, 0.78, 0.56, 0.34, 0] as const;
|
||||||
const sharedStepProgress = makeMutable(0);
|
const sharedStepProgress = makeMutable(0);
|
||||||
let sharedLoopStarted = false;
|
let sharedLoopStarted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,18 @@ function decodeSegment(value: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function areHeaderLabelsEquivalent(
|
||||||
|
a: string | null | undefined,
|
||||||
|
b: string | null | undefined,
|
||||||
|
): boolean {
|
||||||
|
const normalizedA = trimNonEmpty(a)?.toLocaleLowerCase();
|
||||||
|
const normalizedB = trimNonEmpty(b)?.toLocaleLowerCase();
|
||||||
|
if (!normalizedA || !normalizedB) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return normalizedA === normalizedB;
|
||||||
|
}
|
||||||
|
|
||||||
function getFallbackTabOptionLabel(tab: WorkspaceTabDescriptor): string {
|
function getFallbackTabOptionLabel(tab: WorkspaceTabDescriptor): string {
|
||||||
if (tab.target.kind === "draft") {
|
if (tab.target.kind === "draft") {
|
||||||
return "New Agent";
|
return "New Agent";
|
||||||
@@ -773,6 +785,12 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
? resolveWorkspaceHeader({ workspace: workspaceDescriptor })
|
? resolveWorkspaceHeader({ workspace: workspaceDescriptor })
|
||||||
: null;
|
: null;
|
||||||
const isWorkspaceHeaderLoading = workspaceHeader === null;
|
const isWorkspaceHeaderLoading = workspaceHeader === null;
|
||||||
|
const workspaceHeaderTitle = workspaceHeader?.title ?? "";
|
||||||
|
const workspaceHeaderSubtitle = workspaceHeader?.subtitle ?? "";
|
||||||
|
const shouldShowWorkspaceHeaderSubtitle = !areHeaderLabelsEquivalent(
|
||||||
|
workspaceHeaderTitle,
|
||||||
|
workspaceHeaderSubtitle,
|
||||||
|
);
|
||||||
|
|
||||||
const isGitCheckout = checkoutQuery.data?.isGit ?? false;
|
const isGitCheckout = checkoutQuery.data?.isGit ?? false;
|
||||||
const currentBranchName =
|
const currentBranchName =
|
||||||
@@ -2053,27 +2071,29 @@ function WorkspaceScreenContent({ serverId, workspaceId }: WorkspaceScreenProps)
|
|||||||
<SidebarMenuToggle />
|
<SidebarMenuToggle />
|
||||||
<View style={styles.headerTitleContainer}>
|
<View style={styles.headerTitleContainer}>
|
||||||
{isWorkspaceHeaderLoading ? (
|
{isWorkspaceHeaderLoading ? (
|
||||||
<>
|
<View style={styles.headerTitleTextGroup}>
|
||||||
<View style={styles.headerTitleSkeleton} />
|
<View style={styles.headerTitleSkeleton} />
|
||||||
<View style={styles.headerProjectTitleSkeleton} />
|
<View style={styles.headerProjectTitleSkeleton} />
|
||||||
</>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<View style={styles.headerTitleTextGroup}>
|
||||||
<BranchSwitcher
|
<BranchSwitcher
|
||||||
currentBranchName={currentBranchName}
|
currentBranchName={currentBranchName}
|
||||||
title={workspaceHeader.title}
|
title={workspaceHeaderTitle}
|
||||||
serverId={normalizedServerId}
|
serverId={normalizedServerId}
|
||||||
workspaceId={normalizedWorkspaceId}
|
workspaceId={normalizedWorkspaceId}
|
||||||
isGitCheckout={isGitCheckout}
|
isGitCheckout={isGitCheckout}
|
||||||
/>
|
/>
|
||||||
<Text
|
{shouldShowWorkspaceHeaderSubtitle ? (
|
||||||
testID="workspace-header-subtitle"
|
<Text
|
||||||
style={styles.headerProjectTitle}
|
testID="workspace-header-subtitle"
|
||||||
numberOfLines={1}
|
style={styles.headerProjectTitle}
|
||||||
>
|
numberOfLines={1}
|
||||||
{workspaceHeader.subtitle}
|
>
|
||||||
</Text>
|
{workspaceHeaderSubtitle}
|
||||||
</>
|
</Text>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
@@ -2409,15 +2429,40 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
headerTitleContainer: {
|
headerTitleContainer: {
|
||||||
|
flex: 1,
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
},
|
},
|
||||||
|
headerTitleTextGroup: {
|
||||||
|
minWidth: 0,
|
||||||
|
flexShrink: 1,
|
||||||
|
flexGrow: {
|
||||||
|
xs: 1,
|
||||||
|
md: 0,
|
||||||
|
},
|
||||||
|
flexDirection: {
|
||||||
|
xs: "column",
|
||||||
|
md: "row",
|
||||||
|
},
|
||||||
|
alignItems: {
|
||||||
|
xs: "flex-start",
|
||||||
|
md: "center",
|
||||||
|
},
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
gap: {
|
||||||
|
xs: 0,
|
||||||
|
md: theme.spacing[2],
|
||||||
|
},
|
||||||
|
},
|
||||||
headerProjectTitle: {
|
headerProjectTitle: {
|
||||||
color: theme.colors.foregroundMuted,
|
color: theme.colors.foregroundMuted,
|
||||||
fontSize: theme.fontSize.base,
|
fontSize: {
|
||||||
|
xs: theme.fontSize.sm,
|
||||||
|
md: theme.fontSize.base,
|
||||||
|
},
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
headerTitleSkeleton: {
|
headerTitleSkeleton: {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export function WorkspaceTabIcon({
|
|||||||
if (shouldShowLoader) {
|
if (shouldShowLoader) {
|
||||||
return (
|
return (
|
||||||
<View style={[styles.agentIconWrapper, { width: size, height: size }]}>
|
<View style={[styles.agentIconWrapper, { width: size, height: size }]}>
|
||||||
<SyncedLoader size={size - 1} color={theme.colors.palette.amber[500]} />
|
<SyncedLoader size={size - 1} color={theme.colorScheme === "light" ? theme.colors.palette.amber[700] : theme.colors.palette.amber[500]} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ export const baseColors = {
|
|||||||
// Amber scale
|
// Amber scale
|
||||||
amber: {
|
amber: {
|
||||||
500: "#f59e0b",
|
500: "#f59e0b",
|
||||||
|
700: "#b45309",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Yellow scale
|
// Yellow scale
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ import type { StoredAgentRecord } from "./agent/agent-storage.js";
|
|||||||
import type { AgentStorage } from "./agent/agent-storage.js";
|
import type { AgentStorage } from "./agent/agent-storage.js";
|
||||||
import { AGENT_PROVIDER_IDS } from "./agent/provider-manifest.js";
|
import { AGENT_PROVIDER_IDS } from "./agent/provider-manifest.js";
|
||||||
import {
|
import {
|
||||||
|
checkoutLiteFromGitSnapshot,
|
||||||
normalizeWorkspaceId as normalizePersistedWorkspaceId,
|
normalizeWorkspaceId as normalizePersistedWorkspaceId,
|
||||||
deriveWorkspaceId,
|
deriveWorkspaceId,
|
||||||
deriveProjectRootPath,
|
deriveProjectRootPath,
|
||||||
@@ -5716,8 +5717,14 @@ export class Session {
|
|||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkout = checkoutLiteFromGitSnapshot(workspace.cwd, snapshot.git);
|
||||||
|
const displayName = deriveWorkspaceDisplayName({ cwd: workspace.cwd, checkout });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
|
name: displayName,
|
||||||
|
diffStat: snapshot.git.diffStat ?? null,
|
||||||
gitRuntime: this.buildWorkspaceGitRuntimePayload(snapshot) ?? undefined,
|
gitRuntime: this.buildWorkspaceGitRuntimePayload(snapshot) ?? undefined,
|
||||||
githubRuntime: this.buildWorkspaceGitHubRuntimePayload(snapshot),
|
githubRuntime: this.buildWorkspaceGitHubRuntimePayload(snapshot),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1890,9 +1890,7 @@ describe("workspace aggregation", () => {
|
|||||||
});
|
});
|
||||||
const workspaceGitService = createNoopWorkspaceGitService();
|
const workspaceGitService = createNoopWorkspaceGitService();
|
||||||
workspaceGitService.peekSnapshot = vi.fn(() => runtimeSnapshot);
|
workspaceGitService.peekSnapshot = vi.fn(() => runtimeSnapshot);
|
||||||
workspaceGitService.getSnapshot = vi.fn(async () => {
|
workspaceGitService.getSnapshot = vi.fn(async () => runtimeSnapshot);
|
||||||
throw new Error("fetch_workspaces should not trigger per-workspace refreshes");
|
|
||||||
});
|
|
||||||
workspaceGitService.subscribe = vi.fn(async () => ({
|
workspaceGitService.subscribe = vi.fn(async () => ({
|
||||||
initial: runtimeSnapshot,
|
initial: runtimeSnapshot,
|
||||||
unsubscribe: () => {},
|
unsubscribe: () => {},
|
||||||
@@ -1946,8 +1944,7 @@ describe("workspace aggregation", () => {
|
|||||||
| { type: "fetch_workspaces_response"; payload: any }
|
| { type: "fetch_workspaces_response"; payload: any }
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
expect(workspaceGitService.peekSnapshot).toHaveBeenCalledWith("/tmp/repo");
|
expect(workspaceGitService.getSnapshot).toHaveBeenCalledWith("/tmp/repo");
|
||||||
expect(workspaceGitService.getSnapshot).not.toHaveBeenCalled();
|
|
||||||
expect(response?.payload.entries).toEqual([
|
expect(response?.payload.entries).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "/tmp/repo",
|
id: "/tmp/repo",
|
||||||
@@ -1998,9 +1995,7 @@ describe("workspace aggregation", () => {
|
|||||||
});
|
});
|
||||||
const workspaceGitService = createNoopWorkspaceGitService();
|
const workspaceGitService = createNoopWorkspaceGitService();
|
||||||
workspaceGitService.peekSnapshot = vi.fn(() => runtimeSnapshot);
|
workspaceGitService.peekSnapshot = vi.fn(() => runtimeSnapshot);
|
||||||
workspaceGitService.getSnapshot = vi.fn(async () => {
|
workspaceGitService.getSnapshot = vi.fn(async () => runtimeSnapshot);
|
||||||
throw new Error("workspace updates should use passive workspace git snapshots");
|
|
||||||
});
|
|
||||||
|
|
||||||
const session = createSessionForWorkspaceTests({
|
const session = createSessionForWorkspaceTests({
|
||||||
workspaceGitService,
|
workspaceGitService,
|
||||||
@@ -2053,8 +2048,7 @@ describe("workspace aggregation", () => {
|
|||||||
skipReconcile: true,
|
skipReconcile: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(workspaceGitService.peekSnapshot).toHaveBeenCalledWith("/tmp/repo");
|
expect(workspaceGitService.getSnapshot).toHaveBeenCalledWith("/tmp/repo");
|
||||||
expect(workspaceGitService.getSnapshot).not.toHaveBeenCalled();
|
|
||||||
expect(emitted).toContainEqual({
|
expect(emitted).toContainEqual({
|
||||||
type: "workspace_update",
|
type: "workspace_update",
|
||||||
payload: {
|
payload: {
|
||||||
|
|||||||
@@ -137,6 +137,50 @@ export function deriveWorkspaceKind(checkout: ProjectCheckoutLitePayload): Persi
|
|||||||
return checkout.isPaseoOwnedWorktree ? "worktree" : "local_checkout";
|
return checkout.isPaseoOwnedWorktree ? "worktree" : "local_checkout";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function checkoutLiteFromGitSnapshot(
|
||||||
|
cwd: string,
|
||||||
|
git: {
|
||||||
|
isGit: boolean;
|
||||||
|
currentBranch: string | null;
|
||||||
|
remoteUrl: string | null;
|
||||||
|
repoRoot: string | null;
|
||||||
|
isPaseoOwnedWorktree: boolean;
|
||||||
|
mainRepoRoot: string | null;
|
||||||
|
},
|
||||||
|
): ProjectCheckoutLitePayload {
|
||||||
|
if (!git.isGit) {
|
||||||
|
return {
|
||||||
|
cwd,
|
||||||
|
isGit: false,
|
||||||
|
currentBranch: null,
|
||||||
|
remoteUrl: null,
|
||||||
|
worktreeRoot: null,
|
||||||
|
isPaseoOwnedWorktree: false,
|
||||||
|
mainRepoRoot: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (git.isPaseoOwnedWorktree && git.mainRepoRoot) {
|
||||||
|
return {
|
||||||
|
cwd,
|
||||||
|
isGit: true,
|
||||||
|
currentBranch: git.currentBranch,
|
||||||
|
remoteUrl: git.remoteUrl,
|
||||||
|
worktreeRoot: git.repoRoot ?? cwd,
|
||||||
|
isPaseoOwnedWorktree: true,
|
||||||
|
mainRepoRoot: git.mainRepoRoot,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
cwd,
|
||||||
|
isGit: true,
|
||||||
|
currentBranch: git.currentBranch,
|
||||||
|
remoteUrl: git.remoteUrl,
|
||||||
|
worktreeRoot: git.repoRoot ?? cwd,
|
||||||
|
isPaseoOwnedWorktree: false,
|
||||||
|
mainRepoRoot: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function detectStaleWorkspaces(
|
export async function detectStaleWorkspaces(
|
||||||
input: DetectStaleWorkspacesInput,
|
input: DetectStaleWorkspacesInput,
|
||||||
): Promise<Set<string>> {
|
): Promise<Set<string>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user