A Zulip bot agent to sit in our Black Sun. Ever evolving

Add debug logging for git commands in poe loop

Log the exact command and working directory for all git operations when
running with -vv verbosity. Also log the resolved monorepo path at startup
to help diagnose configuration issues like "not a git repository" errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+34 -24
+9 -3
lib/changelog.ml
··· 22 } 23 24 let get_commit_files ~proc ~cwd ~hash = 25 Eio.Switch.run @@ fun sw -> 26 let buf = Buffer.create 256 in 27 let child = Eio.Process.spawn proc ~sw ~cwd 28 ~stdout:(Eio.Flow.buffer_sink buf) 29 - ["git"; "diff-tree"; "--no-commit-id"; "--name-only"; "-r"; hash] 30 in 31 match Eio.Process.await child with 32 | `Exited 0 -> ··· 37 38 let get_git_log ~proc ~cwd ~since_head = 39 Log.info (fun m -> m "Getting commits since %s" since_head); 40 Eio.Switch.run @@ fun sw -> 41 let buf = Buffer.create 1024 in 42 let child = Eio.Process.spawn proc ~sw ~cwd 43 ~stdout:(Eio.Flow.buffer_sink buf) 44 - ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; since_head ^ "..HEAD"] 45 in 46 match Eio.Process.await child with 47 | `Exited 0 -> ··· 59 60 let get_recent_commits ~proc ~cwd ~count = 61 Log.info (fun m -> m "Getting last %d commits" count); 62 Eio.Switch.run @@ fun sw -> 63 let buf = Buffer.create 1024 in 64 let child = Eio.Process.spawn proc ~sw ~cwd 65 ~stdout:(Eio.Flow.buffer_sink buf) 66 - ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; "-n"; string_of_int count] 67 in 68 match Eio.Process.await child with 69 | `Exited 0 ->
··· 22 } 23 24 let get_commit_files ~proc ~cwd ~hash = 25 + let cmd = ["git"; "diff-tree"; "--no-commit-id"; "--name-only"; "-r"; hash] in 26 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 27 Eio.Switch.run @@ fun sw -> 28 let buf = Buffer.create 256 in 29 let child = Eio.Process.spawn proc ~sw ~cwd 30 ~stdout:(Eio.Flow.buffer_sink buf) 31 + cmd 32 in 33 match Eio.Process.await child with 34 | `Exited 0 -> ··· 39 40 let get_git_log ~proc ~cwd ~since_head = 41 Log.info (fun m -> m "Getting commits since %s" since_head); 42 + let cmd = ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; since_head ^ "..HEAD"] in 43 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 44 Eio.Switch.run @@ fun sw -> 45 let buf = Buffer.create 1024 in 46 let child = Eio.Process.spawn proc ~sw ~cwd 47 ~stdout:(Eio.Flow.buffer_sink buf) 48 + cmd 49 in 50 match Eio.Process.await child with 51 | `Exited 0 -> ··· 63 64 let get_recent_commits ~proc ~cwd ~count = 65 Log.info (fun m -> m "Getting last %d commits" count); 66 + let cmd = ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; "-n"; string_of_int count] in 67 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 68 Eio.Switch.run @@ fun sw -> 69 let buf = Buffer.create 1024 in 70 let child = Eio.Process.spawn proc ~sw ~cwd 71 ~stdout:(Eio.Flow.buffer_sink buf) 72 + cmd 73 in 74 match Eio.Process.await child with 75 | `Exited 0 ->
+25 -21
lib/loop.ml
··· 6 let src = Logs.Src.create "poe.loop" ~doc:"Poe polling loop" 7 module Log = (val Logs.src_log src : Logs.LOG) 8 9 - let get_git_head ~proc ~cwd = 10 - Eio.Switch.run @@ fun sw -> 11 - let buf = Buffer.create 64 in 12 - let child = Eio.Process.spawn proc ~sw ~cwd 13 - ~stdout:(Eio.Flow.buffer_sink buf) 14 - ["git"; "rev-parse"; "--short"; "HEAD"] 15 - in 16 - match Eio.Process.await child with 17 - | `Exited 0 -> Some (String.trim (Buffer.contents buf)) 18 - | _ -> None 19 - 20 - let run_git_pull ~proc ~cwd = 21 - Log.info (fun m -> m "Pulling latest changes from remote"); 22 Eio.Switch.run @@ fun sw -> 23 let buf_stdout = Buffer.create 256 in 24 let buf_stderr = Buffer.create 256 in 25 let child = Eio.Process.spawn proc ~sw ~cwd 26 ~stdout:(Eio.Flow.buffer_sink buf_stdout) 27 ~stderr:(Eio.Flow.buffer_sink buf_stderr) 28 - ["git"; "pull"; "--ff-only"] 29 in 30 match Eio.Process.await child with 31 - | `Exited 0 -> 32 - let output = String.trim (Buffer.contents buf_stdout) in 33 if output = "Already up to date." then 34 Log.info (fun m -> m "Repository already up to date") 35 else begin ··· 40 if line <> "" then Log.info (fun m -> m " %s" line)) 41 end; 42 true 43 - | `Exited code -> 44 - let stderr = String.trim (Buffer.contents buf_stderr) in 45 - Log.warn (fun m -> m "git pull exited with code %d: %s" code stderr); 46 false 47 - | `Signaled sig_ -> 48 - Log.warn (fun m -> m "git pull killed by signal %d" sig_); 49 false 50 51 let send_message ~client ~stream ~topic ~content = ··· 63 let storage = Zulip_bot.Storage.create client in 64 65 let monorepo_path = Eio.Path.(fs / config.Config.monorepo_path) in 66 67 Log.info (fun m -> m "Starting loop with %d second interval" interval); 68 69 let broadcast_loop () = 70 let rec loop () =
··· 6 let src = Logs.Src.create "poe.loop" ~doc:"Poe polling loop" 7 module Log = (val Logs.src_log src : Logs.LOG) 8 9 + let run_command ~proc ~cwd cmd = 10 + let cwd_str = Eio.Path.native_exn cwd in 11 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) cwd_str); 12 Eio.Switch.run @@ fun sw -> 13 let buf_stdout = Buffer.create 256 in 14 let buf_stderr = Buffer.create 256 in 15 let child = Eio.Process.spawn proc ~sw ~cwd 16 ~stdout:(Eio.Flow.buffer_sink buf_stdout) 17 ~stderr:(Eio.Flow.buffer_sink buf_stderr) 18 + cmd 19 in 20 + let stdout = Buffer.contents buf_stdout in 21 + let stderr = Buffer.contents buf_stderr in 22 match Eio.Process.await child with 23 + | `Exited code -> (code, stdout, stderr) 24 + | `Signaled sig_ -> (-sig_, stdout, stderr) 25 + 26 + let get_git_head ~proc ~cwd = 27 + match run_command ~proc ~cwd ["git"; "rev-parse"; "--short"; "HEAD"] with 28 + | (0, stdout, _) -> Some (String.trim stdout) 29 + | _ -> None 30 + 31 + let run_git_pull ~proc ~cwd = 32 + Log.info (fun m -> m "Pulling latest changes from remote"); 33 + match run_command ~proc ~cwd ["git"; "pull"; "--ff-only"] with 34 + | (0, stdout, _) -> 35 + let output = String.trim stdout in 36 if output = "Already up to date." then 37 Log.info (fun m -> m "Repository already up to date") 38 else begin ··· 43 if line <> "" then Log.info (fun m -> m " %s" line)) 44 end; 45 true 46 + | (code, _, stderr) when code > 0 -> 47 + Log.warn (fun m -> m "git pull exited with code %d: %s" code (String.trim stderr)); 48 false 49 + | (sig_, _, _) -> 50 + Log.warn (fun m -> m "git pull killed by signal %d" (-sig_)); 51 false 52 53 let send_message ~client ~stream ~topic ~content = ··· 65 let storage = Zulip_bot.Storage.create client in 66 67 let monorepo_path = Eio.Path.(fs / config.Config.monorepo_path) in 68 + let monorepo_native = Eio.Path.native_exn monorepo_path in 69 70 Log.info (fun m -> m "Starting loop with %d second interval" interval); 71 + Log.info (fun m -> m "Monorepo path: %s" monorepo_native); 72 73 let broadcast_loop () = 74 let rec loop () =