WIP: Large refactor checkpoint

- Refactored daemon client and RPC layer
- Added new client package structure in server
- Removed legacy hooks (use-daemon-request, use-session-rpc, use-websocket)
- Added use-daemon-client hook
- Added e2e test infrastructure with Playwright
- Updated agent providers and session handling
- Removed codex-sdk patches
This commit is contained in:
Mohamed Boudra
2026-01-12 13:30:20 +07:00
parent 7c2e959c19
commit 868f9fb571
64 changed files with 5773 additions and 4741 deletions
+141 -13
View File
@@ -1,4 +1,4 @@
import { useState, useCallback, useEffect, useId, useRef } from "react";
import { useState, useCallback, useEffect, useId, useMemo, useRef, memo } from "react";
import {
View,
Text,
@@ -22,6 +22,12 @@ import {
import { useHorizontalScrollOptional } from "@/contexts/horizontal-scroll-context";
import { useExplorerSidebarAnimation } from "@/contexts/explorer-sidebar-animation-context";
import { Fonts } from "@/constants/theme";
import { getNowMs, isPerfLoggingEnabled, perfLog } from "@/utils/perf";
const DIFF_PANE_LOG_TAG = "[GitDiffPane]";
const DIFF_FILE_LOG_TAG = "[DiffFileSection]";
const DIFF_FILE_LOG_LINE_THRESHOLD = 500;
const DIFF_FILE_LOG_TOKEN_THRESHOLD = 5000;
type HighlightStyle = NonNullable<HighlightToken["style"]>;
@@ -81,7 +87,8 @@ function HighlightedText({ tokens, lineType }: HighlightedTextProps) {
interface DiffFileSectionProps {
file: ParsedDiffFile;
defaultExpanded?: boolean;
isExpanded: boolean;
onToggle: (path: string) => void;
testID?: string;
}
@@ -119,14 +126,41 @@ function DiffLineView({ line }: { line: DiffLine }) {
);
}
function DiffFileSection({ file, defaultExpanded = true, testID }: DiffFileSectionProps) {
const DiffFileSection = memo(function DiffFileSection({
file,
isExpanded,
onToggle,
testID,
}: DiffFileSectionProps) {
const { theme } = useUnistyles();
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
const [scrollViewWidth, setScrollViewWidth] = useState(0);
const [isAtLeftEdge, setIsAtLeftEdge] = useState(true);
const horizontalScroll = useHorizontalScrollOptional();
const scrollId = useId();
const scrollViewRef = useRef<ScrollViewType>(null);
const expandStartRef = useRef<number | null>(null);
const { hunkCount, lineCount, tokenCount } = useMemo(() => {
let totalLines = 0;
let totalTokens = 0;
for (const hunk of file.hunks) {
totalLines += hunk.lines.length;
for (const line of hunk.lines) {
if (line.tokens) {
totalTokens += line.tokens.length;
}
}
}
return {
hunkCount: file.hunks.length,
lineCount: totalLines,
tokenCount: totalTokens,
};
}, [file]);
const shouldLogFileMetrics =
lineCount >= DIFF_FILE_LOG_LINE_THRESHOLD ||
tokenCount >= DIFF_FILE_LOG_TOKEN_THRESHOLD;
// Get the close gesture ref from animation context (may not be available outside sidebar)
let closeGestureRef: React.MutableRefObject<any> | undefined;
@@ -138,8 +172,46 @@ function DiffFileSection({ file, defaultExpanded = true, testID }: DiffFileSecti
}
const toggleExpanded = useCallback(() => {
setIsExpanded((prev) => !prev);
}, []);
if (isPerfLoggingEnabled() && shouldLogFileMetrics) {
expandStartRef.current = getNowMs();
perfLog(DIFF_FILE_LOG_TAG, {
event: "toggle",
path: file.path,
nextExpanded: !isExpanded,
hunkCount,
lineCount,
tokenCount,
});
}
onToggle(file.path);
}, [file.path, onToggle, isExpanded, hunkCount, lineCount, tokenCount, shouldLogFileMetrics]);
useEffect(() => {
if (!isPerfLoggingEnabled() || !shouldLogFileMetrics) {
return;
}
const startMs = expandStartRef.current;
if (startMs === null) {
return;
}
expandStartRef.current = null;
const logCommit = () => {
const durationMs = getNowMs() - startMs;
perfLog(DIFF_FILE_LOG_TAG, {
event: isExpanded ? "expand_commit" : "collapse_commit",
path: file.path,
durationMs: Math.round(durationMs),
hunkCount,
lineCount,
tokenCount,
});
};
if (typeof requestAnimationFrame === "function") {
requestAnimationFrame(() => logCommit());
} else {
logCommit();
}
}, [isExpanded, file.path, hunkCount, lineCount, tokenCount, shouldLogFileMetrics]);
// Register/unregister scroll offset tracking
useEffect(() => {
@@ -227,7 +299,7 @@ function DiffFileSection({ file, defaultExpanded = true, testID }: DiffFileSecti
)}
</View>
);
}
});
interface GitDiffPaneProps {
serverId: string;
@@ -242,12 +314,43 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
});
// Track user-initiated refresh to avoid iOS RefreshControl animation on background fetches
const [isManualRefresh, setIsManualRefresh] = useState(false);
const [expandedByPath, setExpandedByPath] = useState<Record<string, boolean>>({});
const diffMetrics = useMemo(() => {
let hunkCount = 0;
let lineCount = 0;
let tokenCount = 0;
for (const file of files) {
hunkCount += file.hunks.length;
for (const hunk of file.hunks) {
lineCount += hunk.lines.length;
for (const line of hunk.lines) {
if (line.tokens) {
tokenCount += line.tokens.length;
}
}
}
}
return {
fileCount: files.length,
hunkCount,
lineCount,
tokenCount,
};
}, [files]);
const lastMetricsKeyRef = useRef<string | null>(null);
const handleRefresh = useCallback(() => {
setIsManualRefresh(true);
refresh();
}, [refresh]);
const handleToggleExpanded = useCallback((path: string) => {
setExpandedByPath((prev) => ({
...prev,
[path]: !prev[path],
}));
}, []);
// Reset manual refresh flag when fetch completes
useEffect(() => {
if (!isFetching && isManualRefresh) {
@@ -255,21 +358,45 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
}
}, [isFetching, isManualRefresh]);
useEffect(() => {
if (!isPerfLoggingEnabled()) {
return;
}
const metricsKey = `${diffMetrics.fileCount}:${diffMetrics.hunkCount}:${diffMetrics.lineCount}:${diffMetrics.tokenCount}`;
if (lastMetricsKeyRef.current === metricsKey) {
return;
}
lastMetricsKeyRef.current = metricsKey;
perfLog(DIFF_PANE_LOG_TAG, {
event: "files_snapshot",
serverId,
agentId,
fileCount: diffMetrics.fileCount,
hunkCount: diffMetrics.hunkCount,
lineCount: diffMetrics.lineCount,
tokenCount: diffMetrics.tokenCount,
isLoading,
isFetching,
});
}, [agentId, diffMetrics, isFetching, isLoading, serverId]);
const agentExists = useSessionStore((state) =>
state.sessions[serverId]?.agents?.has(agentId) ?? false
);
const renderFileSection: ListRenderItem<ParsedDiffFile> = useCallback(
({ item, index }) => (
<DiffFileSection file={item} testID={`diff-file-${index}`} />
<DiffFileSection
file={item}
isExpanded={expandedByPath[item.path] ?? false}
onToggle={handleToggleExpanded}
testID={`diff-file-${index}`}
/>
),
[]
[expandedByPath, handleToggleExpanded]
);
const keyExtractor = useCallback(
(item: ParsedDiffFile, index: number) => `${item.path}-${index}`,
[]
);
const keyExtractor = useCallback((item: ParsedDiffFile) => item.path, []);
if (!agentExists) {
return (
@@ -312,6 +439,7 @@ export function GitDiffPane({ serverId, agentId }: GitDiffPaneProps) {
data={files}
renderItem={renderFileSection}
keyExtractor={keyExtractor}
extraData={expandedByPath}
style={styles.scrollView}
contentContainerStyle={styles.contentContainer}
testID="git-diff-scroll"