mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Update files
This commit is contained in:
@@ -14,12 +14,12 @@ import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { formatTimeAgo } from "@/utils/time";
|
||||
import { shortenPath } from "@/utils/shorten-path";
|
||||
import { deriveBranchLabel, deriveProjectPath } from "@/utils/agent-display-info";
|
||||
import { type AggregatedAgent } from "@/hooks/use-aggregated-agents";
|
||||
import { useSessionStore } from "@/stores/session-store";
|
||||
import {
|
||||
CHECKOUT_STATUS_STALE_TIME,
|
||||
checkoutStatusQueryKey,
|
||||
type CheckoutStatusPayload,
|
||||
useCheckoutStatusCacheOnly,
|
||||
} from "@/hooks/use-checkout-status-query";
|
||||
import {
|
||||
@@ -105,35 +105,6 @@ export function AgentList({
|
||||
setActionAgent(null);
|
||||
}, [actionAgent, deleteAgent]);
|
||||
|
||||
const deriveBranchLabel = useCallback((checkout: CheckoutStatusPayload | null): string | null => {
|
||||
if (!checkout || !checkout.isGit) {
|
||||
return null;
|
||||
}
|
||||
const currentBranch: string | null = checkout.currentBranch ?? null;
|
||||
const baseRef: string | null = checkout.baseRef ?? null;
|
||||
if (!currentBranch) {
|
||||
return null;
|
||||
}
|
||||
if (baseRef && currentBranch === baseRef) {
|
||||
return null;
|
||||
}
|
||||
return currentBranch;
|
||||
}, []);
|
||||
|
||||
const deriveProjectPath = useCallback(
|
||||
(agent: AggregatedAgent, checkout: CheckoutStatusPayload | null): string => {
|
||||
const basePath = checkout?.isGit ? (checkout.repoRoot ?? agent.cwd) : agent.cwd;
|
||||
const worktreeMarker = ".paseo/worktrees/";
|
||||
const idx = basePath.indexOf(worktreeMarker);
|
||||
if (idx !== -1) {
|
||||
const afterMarker = basePath.slice(idx + worktreeMarker.length);
|
||||
return afterMarker;
|
||||
}
|
||||
return basePath;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const viewabilityConfig = useMemo(
|
||||
() => ({ itemVisiblePercentThreshold: 30 }),
|
||||
[]
|
||||
@@ -190,7 +161,7 @@ export function AgentList({
|
||||
agentId: agent.id,
|
||||
});
|
||||
const checkout = checkoutQuery.data ?? null;
|
||||
const projectPath = deriveProjectPath(agent, checkout);
|
||||
const projectPath = deriveProjectPath(agent.cwd, checkout);
|
||||
const branchLabel = deriveBranchLabel(checkout);
|
||||
|
||||
return (
|
||||
@@ -233,8 +204,6 @@ export function AgentList({
|
||||
);
|
||||
},
|
||||
[
|
||||
deriveBranchLabel,
|
||||
deriveProjectPath,
|
||||
handleAgentLongPress,
|
||||
handleAgentPress,
|
||||
selectedAgentId,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { Pressable, Text } from "react-native";
|
||||
import { Pressable, Text, View } from "react-native";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { Menu, PanelLeft } from "lucide-react-native";
|
||||
import { ScreenHeader } from "./screen-header";
|
||||
@@ -7,10 +7,11 @@ import { usePanelStore } from "@/stores/panel-store";
|
||||
|
||||
interface MenuHeaderProps {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
rightContent?: ReactNode;
|
||||
}
|
||||
|
||||
export function MenuHeader({ title, rightContent }: MenuHeaderProps) {
|
||||
export function MenuHeader({ title, subtitle, rightContent }: MenuHeaderProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const isMobile =
|
||||
UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||
@@ -32,9 +33,16 @@ export function MenuHeader({ title, rightContent }: MenuHeaderProps) {
|
||||
<MenuIcon size={16} color={menuIconColor} />
|
||||
</Pressable>
|
||||
{title && (
|
||||
<Text style={styles.title} numberOfLines={1}>
|
||||
{title}
|
||||
</Text>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text style={styles.title} numberOfLines={1}>
|
||||
{title}
|
||||
</Text>
|
||||
{subtitle && (
|
||||
<Text style={styles.subtitle} numberOfLines={1}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
@@ -55,13 +63,21 @@ const styles = StyleSheet.create((theme) => ({
|
||||
},
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
},
|
||||
title: {
|
||||
titleContainer: {
|
||||
flex: 1,
|
||||
fontSize: theme.fontSize.lg,
|
||||
gap: theme.spacing[0],
|
||||
},
|
||||
title: {
|
||||
fontSize: theme.fontSize.base,
|
||||
fontWeight: {
|
||||
xs: theme.fontWeight.semibold,
|
||||
md: "400",
|
||||
xs: "400",
|
||||
md: "300",
|
||||
},
|
||||
color: theme.colors.foreground,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontWeight: "300",
|
||||
color: theme.colors.foregroundMuted,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -57,6 +57,8 @@ import {
|
||||
import { extractAgentModel } from "@/utils/extract-agent-model";
|
||||
import { startPerfMonitor } from "@/utils/perf-monitor";
|
||||
import { shortenPath } from "@/utils/shorten-path";
|
||||
import { deriveBranchLabel, deriveProjectPath } from "@/utils/agent-display-info";
|
||||
import { useCheckoutStatusQuery } from "@/hooks/use-checkout-status-query";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -406,6 +408,13 @@ function AgentScreenContent({
|
||||
? branchError ?? "Unavailable"
|
||||
: branchLabel ?? "Unknown";
|
||||
|
||||
// Checkout status for header subtitle
|
||||
const checkoutStatusQuery = useCheckoutStatusQuery({
|
||||
serverId,
|
||||
agentId: resolvedAgentId ?? "",
|
||||
});
|
||||
const checkout = checkoutStatusQuery.status;
|
||||
|
||||
useEffect(() => {
|
||||
if (!resolvedAgentId) {
|
||||
setFocusedAgentId(null);
|
||||
@@ -490,6 +499,20 @@ function AgentScreenContent({
|
||||
|
||||
const effectiveAgent = agent ?? placeholderAgent;
|
||||
|
||||
// Header subtitle: project path + branch (matching agent list row format)
|
||||
const headerProjectPath = effectiveAgent
|
||||
? deriveProjectPath(effectiveAgent.cwd, checkout)
|
||||
: null;
|
||||
const headerBranchLabel = deriveBranchLabel(checkout);
|
||||
const headerSubtitle = useMemo(() => {
|
||||
if (!headerProjectPath) return undefined;
|
||||
const path = shortenPath(headerProjectPath);
|
||||
if (headerBranchLabel) {
|
||||
return `${path} · ${headerBranchLabel}`;
|
||||
}
|
||||
return path;
|
||||
}, [headerProjectPath, headerBranchLabel]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPendingCreateForRoute || !pendingCreate) {
|
||||
return;
|
||||
@@ -596,6 +619,7 @@ function AgentScreenContent({
|
||||
{/* Header */}
|
||||
<MenuHeader
|
||||
title={effectiveAgent.title || "Agent"}
|
||||
subtitle={headerSubtitle}
|
||||
rightContent={
|
||||
<View style={styles.headerRightContent}>
|
||||
<Pressable onPress={toggleFileExplorer} style={styles.menuButton}>
|
||||
|
||||
41
packages/app/src/utils/agent-display-info.ts
Normal file
41
packages/app/src/utils/agent-display-info.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { CheckoutStatusPayload } from "@/hooks/use-checkout-status-query";
|
||||
|
||||
/**
|
||||
* Derives the branch label to display for an agent.
|
||||
* Returns null if there's no branch to show (not a git repo, or on the base branch).
|
||||
*/
|
||||
export function deriveBranchLabel(
|
||||
checkout: CheckoutStatusPayload | null
|
||||
): string | null {
|
||||
if (!checkout || !checkout.isGit) {
|
||||
return null;
|
||||
}
|
||||
const currentBranch: string | null = checkout.currentBranch ?? null;
|
||||
const baseRef: string | null = checkout.baseRef ?? null;
|
||||
if (!currentBranch) {
|
||||
return null;
|
||||
}
|
||||
if (baseRef && currentBranch === baseRef) {
|
||||
return null;
|
||||
}
|
||||
return currentBranch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives the project path to display for an agent.
|
||||
* If inside a Paseo worktree, shows just the worktree-relative path.
|
||||
* Otherwise uses the repo root or cwd.
|
||||
*/
|
||||
export function deriveProjectPath(
|
||||
cwd: string,
|
||||
checkout: CheckoutStatusPayload | null
|
||||
): string {
|
||||
const basePath = checkout?.isGit ? (checkout.repoRoot ?? cwd) : cwd;
|
||||
const worktreeMarker = ".paseo/worktrees/";
|
||||
const idx = basePath.indexOf(worktreeMarker);
|
||||
if (idx !== -1) {
|
||||
const afterMarker = basePath.slice(idx + worktreeMarker.length);
|
||||
return afterMarker;
|
||||
}
|
||||
return basePath;
|
||||
}
|
||||
@@ -9,9 +9,9 @@ export PATH="$SCRIPT_DIR/../node_modules/.bin:$PATH"
|
||||
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
|
||||
# # 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
|
||||
|
||||
# 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)
|
||||
|
||||
Reference in New Issue
Block a user