← Back to task

Commit c4e5e379

commit c4e5e3791485b5dcb08066ab81e0157d6e70c1d2
Author: Ben Sima <ben@bensima.com>
Date:   Wed Nov 26 05:48:07 2025

    Add jr web command with Servant skeleton
    
    Task-Id: t-1o2g8gugkr1.1

diff --git a/Omni/Jr.hs b/Omni/Jr.hs
index 0cf22f66..f15a2b29 100644
--- a/Omni/Jr.hs
+++ b/Omni/Jr.hs
@@ -5,6 +5,10 @@
 -- : out jr
 -- : dep sqlite-simple
 -- : dep sqids
+-- : dep warp
+-- : dep servant-server
+-- : dep lucid
+-- : dep servant-lucid
 module Omni.Jr where
 
 import Alpha
@@ -13,6 +17,7 @@ import qualified Data.Text as Text
 import qualified Omni.Agent.Core as AgentCore
 import qualified Omni.Agent.Worker as AgentWorker
 import qualified Omni.Cli as Cli
+import qualified Omni.Jr.Web as Web
 import qualified Omni.Task as Task
 import qualified Omni.Task.Core as TaskCore
 import qualified Omni.Test as Test
@@ -45,6 +50,7 @@ jr
 Usage:
   jr task [<args>...]
   jr work [<task-id>]
+  jr web [--port=PORT]
   jr review <task-id>
   jr merge-driver <ours> <theirs>
   jr test
@@ -53,11 +59,13 @@ Usage:
 Commands:
   task          Manage tasks
   work          Start a worker agent on a task
+  web           Start the web UI server
   review        Review a completed task (show diff, accept/reject)
   merge-driver  Internal git merge driver
 
 Options:
-  -h --help  Show this help
+  -h --help     Show this help
+  --port=PORT   Port for web server [default: 8080]
 |]
 
 move :: Cli.Arguments -> IO ()
@@ -65,6 +73,11 @@ move args
   | args `Cli.has` Cli.command "task" = do
       let extraArgs = Cli.getAllArgs args (Cli.argument "args")
       withArgs extraArgs Task.main
+  | args `Cli.has` Cli.command "web" = do
+      let port = case Cli.getArg args (Cli.longOption "port") of
+            Just p -> fromMaybe Web.defaultPort (readMaybe p)
+            Nothing -> Web.defaultPort
+      Web.run port
   | args `Cli.has` Cli.command "work" = do
       -- Always run in current directory
       let path = "."
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs
new file mode 100644
index 00000000..0a00f54d
--- /dev/null
+++ b/Omni/Jr/Web.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- : dep warp
+-- : dep servant-server
+-- : dep lucid
+-- : dep servant-lucid
+module Omni.Jr.Web
+  ( run,
+    defaultPort,
+  )
+where
+
+import Alpha
+import qualified Lucid
+import qualified Network.Wai.Handler.Warp as Warp
+import Servant
+import qualified Servant.HTML.Lucid as Lucid
+
+defaultPort :: Warp.Port
+defaultPort = 8080
+
+type API = Get '[Lucid.HTML] HomePage
+
+newtype HomePage = HomePage ()
+
+instance Lucid.ToHtml HomePage where
+  toHtmlRaw = Lucid.toHtml
+  toHtml (HomePage ()) =
+    Lucid.doctypehtml_ <| do
+      Lucid.head_ <| do
+        Lucid.title_ "Jr Web UI"
+        Lucid.meta_ [Lucid.charset_ "utf-8"]
+        Lucid.meta_
+          [ Lucid.name_ "viewport",
+            Lucid.content_ "width=device-width, initial-scale=1"
+          ]
+      Lucid.body_ <| do
+        Lucid.h1_ "Jr Web UI"
+
+api :: Proxy API
+api = Proxy
+
+server :: Server API
+server = pure (HomePage ())
+
+app :: Application
+app = serve api server
+
+run :: Warp.Port -> IO ()
+run port = do
+  putText <| "Starting Jr web server on port " <> tshow port
+  Warp.run port app