Skip to content

Commit d90e168

Browse files
committed
feat(git): add per-file agent edits mode and thread diff support
1 parent 21b8dce commit d90e168

20 files changed

Lines changed: 1310 additions & 191 deletions

src/App.tsx

Lines changed: 166 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ function MainApp() {
339339
});
340340

341341
const { errorToasts, dismissErrorToast } = useErrorToasts();
342+
const queueGitStatusRefreshRef = useRef<() => void>(() => {});
343+
const handleThreadMessageActivity = useCallback(() => {
344+
queueGitStatusRefreshRef.current();
345+
}, []);
342346

343347
// Access mode is thread-scoped (best-effort persisted) and falls back to the app default.
344348

@@ -364,69 +368,6 @@ function MainApp() {
364368
resetGitHubPanelState,
365369
} = useGitHubPanelController();
366370

367-
const {
368-
centerMode,
369-
setCenterMode,
370-
selectedDiffPath,
371-
setSelectedDiffPath,
372-
diffScrollRequestId,
373-
gitPanelMode,
374-
setGitPanelMode,
375-
gitDiffViewStyle,
376-
setGitDiffViewStyle,
377-
filePanelMode,
378-
setFilePanelMode,
379-
selectedPullRequest,
380-
setSelectedPullRequest,
381-
selectedCommitSha,
382-
setSelectedCommitSha,
383-
diffSource,
384-
setDiffSource,
385-
gitStatus,
386-
refreshGitStatus,
387-
queueGitStatusRefresh,
388-
refreshGitDiffs,
389-
gitLogEntries,
390-
gitLogTotal,
391-
gitLogAhead,
392-
gitLogBehind,
393-
gitLogAheadEntries,
394-
gitLogBehindEntries,
395-
gitLogUpstream,
396-
gitLogLoading,
397-
gitLogError,
398-
refreshGitLog,
399-
gitCommitDiffs,
400-
shouldLoadDiffs,
401-
activeDiffs,
402-
activeDiffLoading,
403-
activeDiffError,
404-
handleSelectDiff,
405-
handleSelectCommit,
406-
handleActiveDiffPath,
407-
handleGitPanelModeChange,
408-
activeWorkspaceIdRef,
409-
activeWorkspaceRef,
410-
} = useGitPanelController({
411-
activeWorkspace,
412-
gitDiffPreloadEnabled: appSettings.preloadGitDiffs,
413-
gitDiffIgnoreWhitespaceChanges: appSettings.gitDiffIgnoreWhitespaceChanges,
414-
splitChatDiffView: appSettings.splitChatDiffView,
415-
isCompact,
416-
isTablet,
417-
activeTab,
418-
tabletTab,
419-
setActiveTab,
420-
prDiffs: gitPullRequestDiffs,
421-
prDiffsLoading: gitPullRequestDiffsLoading,
422-
prDiffsError: gitPullRequestDiffsError,
423-
});
424-
425-
const shouldLoadGitHubPanelData =
426-
gitPanelMode === "issues" ||
427-
gitPanelMode === "prs" ||
428-
(shouldLoadDiffs && diffSource === "pr");
429-
430371
useEffect(() => {
431372
resetGitHubPanelState();
432373
}, [activeWorkspaceId, resetGitHubPanelState]);
@@ -544,6 +485,165 @@ function MainApp() {
544485
getWorkspacePromptsDir,
545486
getGlobalPromptsDir,
546487
} = useCustomPrompts({ activeWorkspace, onDebug: addDebugEntry });
488+
const resolvedModel = selectedModel?.model ?? null;
489+
const resolvedEffort = reasoningSupported ? selectedEffort : null;
490+
491+
const { collaborationModePayload } = useCollaborationModeSelection({
492+
selectedCollaborationMode,
493+
selectedCollaborationModeId,
494+
selectedEffort: resolvedEffort,
495+
resolvedModel,
496+
});
497+
498+
const {
499+
setActiveThreadId,
500+
activeThreadId,
501+
activeItems,
502+
approvals,
503+
userInputRequests,
504+
threadsByWorkspace,
505+
threadParentById,
506+
threadStatusById,
507+
threadResumeLoadingById,
508+
threadListLoadingByWorkspace,
509+
threadListPagingByWorkspace,
510+
threadListCursorByWorkspace,
511+
activeTurnIdByThread,
512+
tokenUsageByThread,
513+
rateLimitsByWorkspace,
514+
accountByWorkspace,
515+
planByThread,
516+
lastAgentMessageByThread,
517+
interruptTurn,
518+
removeThread,
519+
pinThread,
520+
unpinThread,
521+
isThreadPinned,
522+
getPinTimestamp,
523+
renameThread,
524+
startThreadForWorkspace,
525+
listThreadsForWorkspace,
526+
loadOlderThreadsForWorkspace,
527+
resetWorkspaceThreads,
528+
refreshThread,
529+
sendUserMessage,
530+
sendUserMessageToThread,
531+
startFork,
532+
startReview,
533+
startResume,
534+
startCompact,
535+
startApps,
536+
startMcp,
537+
startStatus,
538+
reviewPrompt,
539+
closeReviewPrompt,
540+
showPresetStep,
541+
choosePreset,
542+
highlightedPresetIndex,
543+
setHighlightedPresetIndex,
544+
highlightedBranchIndex,
545+
setHighlightedBranchIndex,
546+
highlightedCommitIndex,
547+
setHighlightedCommitIndex,
548+
handleReviewPromptKeyDown,
549+
confirmBranch,
550+
selectBranch,
551+
selectBranchAtIndex,
552+
selectCommit,
553+
selectCommitAtIndex,
554+
confirmCommit,
555+
updateCustomInstructions,
556+
confirmCustom,
557+
handleApprovalDecision,
558+
handleApprovalRemember,
559+
handleUserInputSubmit,
560+
refreshAccountInfo,
561+
refreshAccountRateLimits,
562+
} = useThreads({
563+
activeWorkspace,
564+
onWorkspaceConnected: markWorkspaceConnected,
565+
onDebug: addDebugEntry,
566+
model: resolvedModel,
567+
effort: resolvedEffort,
568+
collaborationMode: collaborationModePayload,
569+
accessMode,
570+
reviewDeliveryMode: appSettings.reviewDeliveryMode,
571+
steerEnabled: appSettings.steerEnabled,
572+
threadTitleAutogenerationEnabled: appSettings.threadTitleAutogenerationEnabled,
573+
customPrompts: prompts,
574+
onMessageActivity: handleThreadMessageActivity,
575+
threadSortKey: threadListSortKey,
576+
});
577+
const {
578+
centerMode,
579+
setCenterMode,
580+
selectedDiffPath,
581+
setSelectedDiffPath,
582+
diffScrollRequestId,
583+
gitPanelMode,
584+
setGitPanelMode,
585+
gitDiffViewStyle,
586+
setGitDiffViewStyle,
587+
filePanelMode,
588+
setFilePanelMode,
589+
selectedPullRequest,
590+
setSelectedPullRequest,
591+
selectedCommitSha,
592+
setSelectedCommitSha,
593+
diffSource,
594+
setDiffSource,
595+
gitStatus,
596+
refreshGitStatus,
597+
queueGitStatusRefresh,
598+
refreshGitDiffs,
599+
gitLogEntries,
600+
gitLogTotal,
601+
gitLogAhead,
602+
gitLogBehind,
603+
gitLogAheadEntries,
604+
gitLogBehindEntries,
605+
gitLogUpstream,
606+
gitLogLoading,
607+
gitLogError,
608+
refreshGitLog,
609+
gitCommitDiffs,
610+
shouldLoadDiffs,
611+
activeDiffs,
612+
activeDiffLoading,
613+
activeDiffError,
614+
perFileDiffGroups,
615+
handleSelectDiff,
616+
handleSelectPerFileDiff,
617+
handleSelectCommit,
618+
handleActiveDiffPath,
619+
handleGitPanelModeChange,
620+
activeWorkspaceIdRef,
621+
activeWorkspaceRef,
622+
} = useGitPanelController({
623+
activeWorkspace,
624+
activeItems,
625+
gitDiffPreloadEnabled: appSettings.preloadGitDiffs,
626+
gitDiffIgnoreWhitespaceChanges: appSettings.gitDiffIgnoreWhitespaceChanges,
627+
splitChatDiffView: appSettings.splitChatDiffView,
628+
isCompact,
629+
isTablet,
630+
activeTab,
631+
tabletTab,
632+
setActiveTab,
633+
prDiffs: gitPullRequestDiffs,
634+
prDiffsLoading: gitPullRequestDiffsLoading,
635+
prDiffsError: gitPullRequestDiffsError,
636+
});
637+
queueGitStatusRefreshRef.current = queueGitStatusRefresh;
638+
639+
const shouldLoadGitHubPanelData =
640+
gitPanelMode === "issues" ||
641+
gitPanelMode === "prs" ||
642+
(shouldLoadDiffs && diffSource === "pr");
643+
644+
const alertError = useCallback((error: unknown) => {
645+
alert(error instanceof Error ? error.message : String(error));
646+
}, []);
547647
const { branches, checkoutBranch, checkoutPullRequest, createBranch } = useGitBranches({
548648
activeWorkspace,
549649
onDebug: addDebugEntry
@@ -583,9 +683,6 @@ function MainApp() {
583683
isEnabled: isBranchSwitcherEnabled,
584684
onTrigger: openBranchSwitcher,
585685
});
586-
const alertError = useCallback((error: unknown) => {
587-
alert(error instanceof Error ? error.message : String(error));
588-
}, []);
589686
const {
590687
applyWorktreeChanges: handleApplyWorktreeChanges,
591688
revertAllGitChanges: handleRevertAllGitChanges,
@@ -602,9 +699,6 @@ function MainApp() {
602699
onRefreshGitDiffs: refreshGitDiffs,
603700
onError: alertError,
604701
});
605-
606-
const resolvedModel = selectedModel?.model ?? null;
607-
const resolvedEffort = reasoningSupported ? selectedEffort : null;
608702
const { activeGitRoot, handleSetGitRoot, handlePickGitRoot } = useGitRootSelection({
609703
activeWorkspace,
610704
updateWorkspaceSettings,
@@ -646,102 +740,16 @@ function MainApp() {
646740
],
647741
);
648742

649-
650743
useSyncSelectedDiffPath({
651744
diffSource,
652745
centerMode,
653746
gitPullRequestDiffs,
654747
gitCommitDiffs,
748+
perFileDiffGroups,
655749
selectedDiffPath,
656750
setSelectedDiffPath,
657751
});
658752

659-
const { collaborationModePayload } = useCollaborationModeSelection({
660-
selectedCollaborationMode,
661-
selectedCollaborationModeId,
662-
selectedEffort: resolvedEffort,
663-
resolvedModel,
664-
});
665-
666-
const {
667-
setActiveThreadId,
668-
activeThreadId,
669-
activeItems,
670-
approvals,
671-
userInputRequests,
672-
threadsByWorkspace,
673-
threadParentById,
674-
threadStatusById,
675-
threadResumeLoadingById,
676-
threadListLoadingByWorkspace,
677-
threadListPagingByWorkspace,
678-
threadListCursorByWorkspace,
679-
activeTurnIdByThread,
680-
tokenUsageByThread,
681-
rateLimitsByWorkspace,
682-
accountByWorkspace,
683-
planByThread,
684-
lastAgentMessageByThread,
685-
interruptTurn,
686-
removeThread,
687-
pinThread,
688-
unpinThread,
689-
isThreadPinned,
690-
getPinTimestamp,
691-
renameThread,
692-
startThreadForWorkspace,
693-
listThreadsForWorkspace,
694-
loadOlderThreadsForWorkspace,
695-
resetWorkspaceThreads,
696-
refreshThread,
697-
sendUserMessage,
698-
sendUserMessageToThread,
699-
startFork,
700-
startReview,
701-
startResume,
702-
startCompact,
703-
startApps,
704-
startMcp,
705-
startStatus,
706-
reviewPrompt,
707-
closeReviewPrompt,
708-
showPresetStep,
709-
choosePreset,
710-
highlightedPresetIndex,
711-
setHighlightedPresetIndex,
712-
highlightedBranchIndex,
713-
setHighlightedBranchIndex,
714-
highlightedCommitIndex,
715-
setHighlightedCommitIndex,
716-
handleReviewPromptKeyDown,
717-
confirmBranch,
718-
selectBranch,
719-
selectBranchAtIndex,
720-
selectCommit,
721-
selectCommitAtIndex,
722-
confirmCommit,
723-
updateCustomInstructions,
724-
confirmCustom,
725-
handleApprovalDecision,
726-
handleApprovalRemember,
727-
handleUserInputSubmit,
728-
refreshAccountInfo,
729-
refreshAccountRateLimits,
730-
} = useThreads({
731-
activeWorkspace,
732-
onWorkspaceConnected: markWorkspaceConnected,
733-
onDebug: addDebugEntry,
734-
model: resolvedModel,
735-
effort: resolvedEffort,
736-
collaborationMode: collaborationModePayload,
737-
accessMode,
738-
reviewDeliveryMode: appSettings.reviewDeliveryMode,
739-
steerEnabled: appSettings.steerEnabled,
740-
threadTitleAutogenerationEnabled: appSettings.threadTitleAutogenerationEnabled,
741-
customPrompts: prompts,
742-
onMessageActivity: queueGitStatusRefresh,
743-
threadSortKey: threadListSortKey,
744-
});
745753
const { apps } = useApps({
746754
activeWorkspace,
747755
activeThreadId,
@@ -1920,9 +1928,11 @@ function MainApp() {
19201928
: undefined,
19211929
gitStatus,
19221930
fileStatus,
1931+
perFileDiffGroups,
19231932
selectedDiffPath,
19241933
diffScrollRequestId,
19251934
onSelectDiff: handleSelectDiff,
1935+
onSelectPerFileDiff: handleSelectPerFileDiff,
19261936
diffSource,
19271937
gitLogEntries,
19281938
gitLogTotal,

0 commit comments

Comments
 (0)