← Back to task

Commit dd1c8abe

commit dd1c8abe0e149eeeab879426329a32d69308855e
Author: Ben Sima <ben@bensima.com>
Date:   Tue Nov 25 22:47:26 2025

    fix(agent): show elapsed duration instead of wall clock time
    
    Task-Id: t-1o2g8gu6p8o

diff --git a/Omni/Agent/Log.hs b/Omni/Agent/Log.hs
index e0e05a18..b1020c5a 100644
--- a/Omni/Agent/Log.hs
+++ b/Omni/Agent/Log.hs
@@ -13,6 +13,8 @@ import Data.IORef (IORef, modifyIORef', newIORef, readIORef, writeIORef)
 import qualified Data.Text as Text
 import qualified Data.Text.Encoding as TE
 import qualified Data.Text.IO as TIO
+import Data.Time.Clock (NominalDiffTime, UTCTime, diffUTCTime, getCurrentTime)
+import Data.Time.Format (defaultTimeLocale, parseTimeOrError)
 import qualified System.Console.ANSI as ANSI
 import qualified System.IO as IO
 import System.IO.Unsafe (unsafePerformIO)
@@ -25,33 +27,37 @@ data Status = Status
     statusThread :: Maybe Text,
     statusFiles :: Int,
     statusCredits :: Double,
-    statusTime :: Text, -- formatted time string
+    statusStartTime :: UTCTime,
     statusActivity :: Text
   }
   deriving (Show, Eq)
 
-emptyStatus :: Text -> Status
-emptyStatus workerName =
+emptyStatus :: Text -> UTCTime -> Status
+emptyStatus workerName startTime =
   Status
     { statusWorker = workerName,
       statusTask = Nothing,
       statusThread = Nothing,
       statusFiles = 0,
       statusCredits = 0.0,
-      statusTime = "00:00",
+      statusStartTime = startTime,
       statusActivity = "Idle"
     }
 
 -- | Global state for the status bar
 {-# NOINLINE currentStatus #-}
 currentStatus :: IORef Status
-currentStatus = unsafePerformIO (newIORef (emptyStatus "Unknown"))
+currentStatus = unsafePerformIO (newIORef (emptyStatus "Unknown" defaultStartTime))
+
+defaultStartTime :: UTCTime
+defaultStartTime = parseTimeOrError True defaultTimeLocale "%Y-%m-%d %H:%M:%S %Z" "2000-01-01 00:00:00 UTC"
 
 -- | Initialize the status bar system
 init :: Text -> IO ()
 init workerName = do
   IO.hSetBuffering IO.stderr IO.LineBuffering
-  writeIORef currentStatus (emptyStatus workerName)
+  startTime <- getCurrentTime
+  writeIORef currentStatus (emptyStatus workerName startTime)
   -- Reserve 5 lines at bottom
   IO.hPutStrLn IO.stderr ""
   IO.hPutStrLn IO.stderr ""
@@ -96,8 +102,11 @@ log msg = do
 render :: IO ()
 render = do
   Status {..} <- readIORef currentStatus
+  now <- getCurrentTime
   let taskStr = maybe "None" identity statusTask
       threadStr = maybe "None" identity statusThread
+      elapsed = diffUTCTime now statusStartTime
+      elapsedStr = formatElapsed elapsed
 
   -- Line 1: Worker | Thread
   ANSI.hSetCursorColumn IO.stderr 0
@@ -117,11 +126,11 @@ render = do
   let creditsStr = Text.pack (printf "%.2f" statusCredits)
   TIO.hPutStr IO.stderr ("Files: " <> tshow statusFiles <> " | Credits: $" <> creditsStr)
 
-  -- Line 4: Time
+  -- Line 4: Time (elapsed duration)
   ANSI.hCursorDown IO.stderr 1
   ANSI.hSetCursorColumn IO.stderr 0
   ANSI.hClearLine IO.stderr
-  TIO.hPutStr IO.stderr ("Time: " <> statusTime)
+  TIO.hPutStr IO.stderr ("Time: " <> elapsedStr)
 
   -- Line 5: Activity
   ANSI.hCursorDown IO.stderr 1
@@ -168,15 +177,16 @@ updateFromEntry :: LogEntry -> Status -> Status
 updateFromEntry LogEntry {..} s =
   s
     { statusThread = leThreadId <|> statusThread s,
-      statusCredits = maybe (statusCredits s) (/ 100.0) leTotalCredits, -- Only update if totalCredits is present
-      statusTime = maybe (statusTime s) formatTime leTimestamp
+      statusCredits = maybe (statusCredits s) (/ 100.0) leTotalCredits -- Only update if totalCredits is present
     }
 
-formatTime :: Text -> Text
-formatTime ts =
-  -- "2025-11-22T21:24:02.512Z" -> "21:24"
-  case Text.splitOn "T" ts of
-    [_, time] -> case Text.splitOn ":" time of
-      (h : m : _) -> h <> ":" <> m
-      _ -> ts
-    _ -> ts
+-- | Format elapsed time as MM:SS or HH:MM:SS
+formatElapsed :: NominalDiffTime -> Text
+formatElapsed elapsed =
+  let totalSecs = floor elapsed :: Int
+      hours = totalSecs `div` 3600
+      mins = (totalSecs `mod` 3600) `div` 60
+      secs = totalSecs `mod` 60
+   in if hours > 0
+        then Text.pack (printf "%02d:%02d:%02d" hours mins secs)
+        else Text.pack (printf "%02d:%02d" mins secs)