summaryrefslogtreecommitdiff
path: root/Omni/Jr.hs
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-11-26 13:55:42 -0500
committerBen Sima <ben@bensima.com>2025-11-26 13:55:42 -0500
commit6305179905d5428879aaf8c08fef1722c734c3d7 (patch)
tree634e4c6ee7f102a510f11f8860c98617eb557657 /Omni/Jr.hs
parent1080ecd359dbf36bf571bb8f56347174edccdc5c (diff)
Jr: Gerrit-style conflict handling - kick back to coder with context
All tests pass and lint is clean. The implementation adds Gerrit-style c 1. **`gatherConflictContext`** - Creates rich context including: - The commit info (SHA, subject, body) - Current HEAD state (what branch moved to) - Per-file conflict details showing both your changes and recent chan 2. **`getFileConflictInfo`** - For each conflicting file, shows: - Your changes to that file (stat summary) - Recent changes by others (last 3 commits touching the file) 3. The context is stored in `retryReason` and passed to the worker via t Task-Id: t-1o2g8gudqlx
Diffstat (limited to 'Omni/Jr.hs')
-rw-r--r--Omni/Jr.hs92
1 files changed, 90 insertions, 2 deletions
diff --git a/Omni/Jr.hs b/Omni/Jr.hs
index 3ddb3b1..cd06a42 100644
--- a/Omni/Jr.hs
+++ b/Omni/Jr.hs
@@ -208,7 +208,7 @@ runLoop delaySec = do
Nothing -> do
autoReview tid task commitSha
--- | Handle merge conflict during review
+-- | Handle merge conflict during review (Gerrit-style: provide rich context)
handleConflict :: Text -> [Text] -> String -> IO ()
handleConflict tid conflictFiles commitSha = do
maybeCtx <- TaskCore.getRetryContext tid
@@ -219,17 +219,105 @@ handleConflict tid conflictFiles commitSha = do
putText "[review] Task has failed 3 times. Needs human intervention."
TaskCore.updateTaskStatus tid TaskCore.Open []
else do
+ conflictDetails <- gatherConflictContext commitSha conflictFiles
TaskCore.setRetryContext
TaskCore.RetryContext
{ TaskCore.retryTaskId = tid,
TaskCore.retryOriginalCommit = Text.pack commitSha,
TaskCore.retryConflictFiles = conflictFiles,
TaskCore.retryAttempt = attempt,
- TaskCore.retryReason = "merge_conflict"
+ TaskCore.retryReason = conflictDetails
}
TaskCore.updateTaskStatus tid TaskCore.Open []
putText ("[review] Task " <> tid <> " returned to queue (attempt " <> tshow attempt <> "/3).")
+-- | Gather Gerrit-style conflict context for the coder
+gatherConflictContext :: String -> [Text] -> IO Text
+gatherConflictContext commitSha conflictFiles = do
+ commitInfo <- getCommitInfo commitSha
+ currentHeadInfo <- getCurrentHeadInfo
+ fileDiffs <- traverse (getFileConflictInfo commitSha <. Text.unpack) conflictFiles
+
+ pure
+ <| Text.unlines
+ [ "MERGE CONFLICT - Your changes could not be cleanly applied",
+ "",
+ "== Your Commit ==",
+ commitInfo,
+ "",
+ "== Current HEAD ==",
+ currentHeadInfo,
+ "",
+ "== Conflicting Files ==",
+ Text.unlines fileDiffs,
+ "",
+ "== Resolution Instructions ==",
+ "1. The codebase has been updated since your work",
+ "2. Review the current state of conflicting files",
+ "3. Re-implement your changes on top of the current code",
+ "4. Ensure your changes still make sense given the updates"
+ ]
+
+-- | Get info about the commit that caused the conflict
+getCommitInfo :: String -> IO Text
+getCommitInfo sha = do
+ (_, out, _) <-
+ Process.readProcessWithExitCode
+ "git"
+ ["log", "-1", "--format=%h %s%n%b", sha]
+ ""
+ pure <| Text.pack out
+
+-- | Get info about current HEAD
+getCurrentHeadInfo :: IO Text
+getCurrentHeadInfo = do
+ (_, out, _) <-
+ Process.readProcessWithExitCode
+ "git"
+ ["log", "-1", "--format=%h %s (%cr)"]
+ ""
+ pure <| Text.pack out
+
+-- | Get file-level conflict context showing what changed in both branches
+getFileConflictInfo :: String -> FilePath -> IO Text
+getFileConflictInfo commitSha filePath = do
+ yourChanges <- getYourChangesToFile commitSha filePath
+ recentChanges <- getRecentChangesToFile filePath
+ pure
+ <| Text.unlines
+ [ "--- " <> Text.pack filePath <> " ---",
+ "",
+ "Your changes to this file:",
+ yourChanges,
+ "",
+ "Recent changes by others:",
+ recentChanges
+ ]
+
+-- | Get a summary of changes in a specific commit to a file
+getYourChangesToFile :: String -> FilePath -> IO Text
+getYourChangesToFile commitSha filePath = do
+ (code, out, _) <-
+ Process.readProcessWithExitCode
+ "git"
+ ["show", "--stat", commitSha, "--", filePath]
+ ""
+ case code of
+ Exit.ExitSuccess -> pure <| Text.pack (take 500 out)
+ Exit.ExitFailure _ -> pure "(unable to get diff)"
+
+-- | Get recent changes to a file (last few commits)
+getRecentChangesToFile :: FilePath -> IO Text
+getRecentChangesToFile filePath = do
+ (code, out, _) <-
+ Process.readProcessWithExitCode
+ "git"
+ ["log", "-3", "--oneline", "--", filePath]
+ ""
+ case code of
+ Exit.ExitSuccess -> pure <| Text.pack out
+ Exit.ExitFailure _ -> pure "(unable to get history)"
+
-- | Interactive review command (jr review <task-id>)
reviewTask :: Text -> Bool -> IO ()
reviewTask tid autoMode = do