diff --git a/packages/app/src/components/git-diff-pane.tsx b/packages/app/src/components/git-diff-pane.tsx
index 4c3fad20e..b9f9b5beb 100644
--- a/packages/app/src/components/git-diff-pane.tsx
+++ b/packages/app/src/components/git-diff-pane.tsx
@@ -14,7 +14,7 @@ import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gest
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as Linking from "expo-linking";
-import { ChevronDown, ChevronRight, GitBranch, MoreVertical, RotateCcw } from "lucide-react-native";
+import { ChevronDown, ChevronRight, GitBranch, MoreVertical } from "lucide-react-native";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useSessionStore } from "@/stores/session-store";
import {
@@ -32,7 +32,6 @@ import { getNowMs, isPerfLoggingEnabled, perfLog } from "@/utils/perf";
import {
DropdownMenu,
DropdownMenuContent,
- DropdownMenuHint,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
@@ -121,6 +120,7 @@ function HighlightedText({ tokens, lineType }: HighlightedTextProps) {
);
}
+
interface DiffFileSectionProps {
file: ParsedDiffFile;
isExpanded: boolean;
@@ -824,67 +824,12 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
{branchLabel}
- {isStatusFetching && (
-
- )}
+ {isStatusFetching && (
+
+ )}
{isGit ? (
-
-
-
- {diffMode === "uncommitted" ? "Working" : "Base"}
-
-
-
-
- setDiffMode("uncommitted")}
- >
- Working
-
- setDiffMode("base")}
- >
- Base
-
-
-
- ) : null}
-
-
- {isGit ? (
-
-
- {canShowCommit ? (
- commitMutation.mutate()}
- disabled={commitDisabled}
- >
- {commitMutation.isPending ? (
-
- ) : (
- Commit…
- )}
-
- ) : (
-
- )}
-
-
+
{canShowShip ? (
) : (
- <>
-
- {resolvedShipPrimary === "merge" ? "Merge" : prActionLabel}
-
-
- into {baseRefLabel}
-
- >
+
+ {resolvedShipPrimary === "merge" ? "Merge branch" : prActionLabel}
+
)}
@@ -940,19 +880,15 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
{
void persistShipDefault("merge");
mergeMutation.mutate();
}}
>
- Merge into {baseRefLabel}
+ Merge branch
- {mergeDisabled && hasUncommittedChanges ? (
- Requires a clean working tree.
- ) : null}
-
-
- {hasPullRequest ? "Open PR" : `Create PR into ${baseRefLabel}`}
+ {hasPullRequest ? "Open PR" : "Create PR"}
@@ -982,35 +918,56 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
- }
- onSelect={handleRefresh}
- >
- Refresh
-
-
+ {canShowShip ? (
+ <>
+ {resolvedShipPrimary === "merge" ? (
+ {
+ void persistShipDefault("pr");
+ if (hasPullRequest && prStatus?.url) {
+ void Linking.openURL(prStatus.url);
+ return;
+ }
+ prMutation.mutate();
+ }}
+ >
+ {hasPullRequest ? "Open PR" : "Create PR"}
+
+ ) : (
+ {
+ void persistShipDefault("merge");
+ mergeMutation.mutate();
+ }}
+ >
+ Merge branch
+
+ )}
+
+ >
+ ) : null}
mergeFromBaseMutation.mutate()}
>
Merge from {baseRefLabel}
- {mergeFromBaseDisabled && hasUncommittedChanges ? (
- Requires a clean working tree.
- ) : null}
-
+
pushMutation.mutate()}
>
Push branch
- {pushDisabled && !(gitStatus?.hasRemote ?? false) ? (
- Remote 'origin' is not configured.
- ) : null}
+ ) : null}
+
+
+ {isGit ? (
+
+
+ {canShowCommit ? (
+ commitMutation.mutate()}
+ disabled={commitDisabled}
+ >
+ {commitMutation.isPending ? (
+
+ ) : (
+ Commit
+ )}
+
+ ) : (
+
+ )}
+
+
+
+
+
+ {diffMode === "uncommitted" ? "Working" : "Base"}
+
+
+
+
+ setDiffMode("uncommitted")}
+ >
+ Working
+
+ setDiffMode("base")}
+ >
+ Base
+
+
+
+
) : null}
@@ -1076,6 +1090,12 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
minWidth: 0,
},
+ headerRight: {
+ flexDirection: "row",
+ alignItems: "center",
+ gap: theme.spacing[1],
+ flexShrink: 0,
+ },
branchLabel: {
fontSize: theme.fontSize.sm,
color: theme.colors.foreground,
@@ -1104,7 +1124,9 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
paddingTop: theme.spacing[2],
- paddingBottom: theme.spacing[1],
+ paddingBottom: theme.spacing[3],
+ borderBottomWidth: 1,
+ borderBottomColor: theme.colors.border,
},
toolbarLeft: {
flex: 1,
@@ -1136,6 +1158,9 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foreground,
fontWeight: theme.fontWeight.medium,
},
+ buttonSpinner: {
+ height: theme.fontSize.xs * 1.4,
+ },
shipSplitButton: {
flexDirection: "row",
alignItems: "stretch",
@@ -1148,7 +1173,7 @@ const styles = StyleSheet.create((theme) => ({
shipPrimaryButton: {
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
- minWidth: 140,
+ justifyContent: "center",
},
shipPrimaryButtonDisabled: {
opacity: 0.6,
@@ -1158,11 +1183,6 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foreground,
fontWeight: theme.fontWeight.medium,
},
- shipSecondaryText: {
- marginTop: 2,
- fontSize: theme.fontSize.xs,
- color: theme.colors.foregroundMuted,
- },
shipCaretButton: {
width: 36,
alignItems: "center",
@@ -1373,16 +1393,14 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.palette.red[500],
},
additions: {
- fontSize: theme.fontSize.sm,
+ fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.normal,
color: theme.colors.palette.green[400],
- fontFamily: Fonts.mono,
},
deletions: {
- fontSize: theme.fontSize.sm,
+ fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.normal,
color: theme.colors.palette.red[500],
- fontFamily: Fonts.mono,
},
diffContent: {
borderTopWidth: theme.borderWidth[1],
diff --git a/packages/server/src/utils/checkout-git.ts b/packages/server/src/utils/checkout-git.ts
index cd9984bac..db867d76c 100644
--- a/packages/server/src/utils/checkout-git.ts
+++ b/packages/server/src/utils/checkout-git.ts
@@ -485,11 +485,13 @@ export async function getCheckoutDiff(
throw new Error(`Base ref mismatch: expected ${baseRef}, got ${compare.baseRef}`);
} else {
const normalizedBaseRef = normalizeLocalBranchRefName(baseRef);
- const { stdout } = await execAsync(`git diff ${normalizedBaseRef}...HEAD`, {
+ // Diff base ref against working tree (includes uncommitted changes)
+ const { stdout: trackedDiff } = await execAsync(`git diff ${normalizedBaseRef}`, {
cwd,
env: READ_ONLY_GIT_ENV,
});
- diff = stdout;
+ const untrackedDiff = await getUntrackedDiff(cwd);
+ diff = trackedDiff + untrackedDiff;
}
}
diff --git a/scripts/dev.sh b/scripts/dev.sh
index 630f3e618..b72ab5c2b 100755
--- a/scripts/dev.sh
+++ b/scripts/dev.sh
@@ -10,8 +10,8 @@ DAEMON_PORT=$(get-port 6767 6768 6769 6770 6771 6772 6773)
METRO_PORT=$(get-port 8081 8082 8083 8084 8085 8086 8087)
# Use a temporary PASEO_HOME to avoid conflicts between dev instances
-export PASEO_HOME=$(mktemp -d "${TMPDIR:-/tmp}/paseo-dev.XXXXXX")
-trap "rm -rf '$PASEO_HOME'" EXIT
+# export PASEO_HOME=$(mktemp -d "${TMPDIR:-/tmp}/paseo-dev.XXXXXX")
+# trap "rm -rf '$PASEO_HOME'" EXIT
# Build CORS origins for this Expo instance
CORS_ORIGINS="http://localhost:${METRO_PORT},http://127.0.0.1:${METRO_PORT}"
@@ -24,7 +24,7 @@ echo " Paseo Dev"
echo "══════════════════════════════════════════════════════"
echo " Daemon: http://localhost:${DAEMON_PORT}"
echo " Metro: http://localhost:${METRO_PORT}"
-echo " Home: ${PASEO_HOME}"
+# echo " Home: ${PASEO_HOME}"
echo "══════════════════════════════════════════════════════"
# Export for child processes (overrides .env values)