summaryrefslogtreecommitdiff
path: root/Omni/Task/Core.hs
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-11-28 04:11:17 -0500
committerBen Sima <ben@bensima.com>2025-11-28 04:11:17 -0500
commitb616e753da03d234c7e4e0a0ea50c9e192644cf9 (patch)
tree70da65a76670d1c5726c9f5161d431abe755c6db /Omni/Task/Core.hs
parent0f3ec582e98fff87988b829d704e1152f52d8d1f (diff)
Add comments field to tasks for providing extra context
All tests pass. Here's a summary of the changes I made: 1. **Added `Comment` data type** in `Omni/Task/Core.hs` with `commentTex 2. **Added `taskComments` field** to the `Task` type to store a list of 3. **Updated database schema** with a `comments TEXT` column (stored as 4. **Added SQL instances** for `[Comment]` to serialize/deserialize 5. **Added `addComment` function** to add timestamped comments to tasks 6. **Added CLI command** `task comment <id> <message> [--json]` 7. **Updated `showTaskDetailed`** to display comments in the detailed vi 8. **Added unit tests** for comments functionality 9. **Added CLI tests** for the comment command 10. **Fixed dependent files** (`Omni/Agent/Worker.hs` and `Omni/Jr/Web.h Task-Id: t-167
Diffstat (limited to 'Omni/Task/Core.hs')
-rw-r--r--Omni/Task/Core.hs56
1 files changed, 53 insertions, 3 deletions
diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs
index 18f80e2..1be97b9 100644
--- a/Omni/Task/Core.hs
+++ b/Omni/Task/Core.hs
@@ -36,6 +36,7 @@ data Task = Task
taskPriority :: Priority, -- Priority level (0-4)
taskDependencies :: [Dependency], -- List of dependencies with types
taskDescription :: Text, -- Required description
+ taskComments :: [Comment], -- Timestamped comments for extra context
taskCreatedAt :: UTCTime,
taskUpdatedAt :: UTCTime
}
@@ -123,6 +124,13 @@ data Fact = Fact
}
deriving (Show, Eq, Generic)
+-- Comment for task notes/context
+data Comment = Comment
+ { commentText :: Text,
+ commentCreatedAt :: UTCTime
+ }
+ deriving (Show, Eq, Generic)
+
instance ToJSON TaskType
instance FromJSON TaskType
@@ -171,6 +179,10 @@ instance ToJSON Fact
instance FromJSON Fact
+instance ToJSON Comment
+
+instance FromJSON Comment
+
-- HTTP API Instances (for Servant query params)
instance FromHttpApiData Status where
@@ -240,6 +252,17 @@ instance SQL.FromField [Dependency] where
instance SQL.ToField [Dependency] where
toField deps = SQL.toField (BLC.unpack (encode deps))
+-- Store comments as JSON text
+instance SQL.FromField [Comment] where
+ fromField f = do
+ t <- SQL.fromField f :: SQLOk.Ok String
+ case Aeson.decode (BLC.pack t) of
+ Just x -> pure x
+ Nothing -> pure [] -- Default to empty if parse fail or null
+
+instance SQL.ToField [Comment] where
+ toField comments = SQL.toField (BLC.unpack (encode comments))
+
instance SQL.FromRow Task where
fromRow =
Task
@@ -252,6 +275,7 @@ instance SQL.FromRow Task where
<*> SQL.field
<*> SQL.field
<*> (fromMaybe "" </ SQL.field) -- Handle NULL description from legacy data
+ <*> SQL.field -- comments
<*> SQL.field
<*> SQL.field
@@ -266,6 +290,7 @@ instance SQL.ToRow Task where
SQL.toField (taskPriority t),
SQL.toField (taskDependencies t),
SQL.toField (taskDescription t),
+ SQL.toField (taskComments t),
SQL.toField (taskCreatedAt t),
SQL.toField (taskUpdatedAt t)
]
@@ -402,6 +427,7 @@ initTaskDb = do
\ priority TEXT NOT NULL, \
\ dependencies TEXT NOT NULL, \
\ description TEXT, \
+ \ comments TEXT NOT NULL DEFAULT '[]', \
\ created_at TIMESTAMP NOT NULL, \
\ updated_at TIMESTAMP NOT NULL \
\)"
@@ -488,6 +514,7 @@ tasksColumns =
("priority", "TEXT"),
("dependencies", "TEXT"),
("description", "TEXT"),
+ ("comments", "TEXT"),
("created_at", "TIMESTAMP"),
("updated_at", "TIMESTAMP")
]
@@ -584,7 +611,7 @@ getSuffix parent childId =
loadTasks :: IO [Task]
loadTasks =
withDb <| \conn -> do
- SQL.query_ conn "SELECT id, title, type, parent, namespace, status, priority, dependencies, description, created_at, updated_at FROM tasks"
+ SQL.query_ conn "SELECT id, title, type, parent, namespace, status, priority, dependencies, description, comments, created_at, updated_at FROM tasks"
-- Save a single task (UPSERT)
saveTask :: Task -> IO ()
@@ -593,8 +620,8 @@ saveTask task =
SQL.execute
conn
"INSERT OR REPLACE INTO tasks \
- \ (id, title, type, parent, namespace, status, priority, dependencies, description, created_at, updated_at) \
- \ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
+ \ (id, title, type, parent, namespace, status, priority, dependencies, description, comments, created_at, updated_at) \
+ \ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
task
-- Create a new task
@@ -621,6 +648,7 @@ createTask title taskType parent namespace priority deps description =
taskPriority = priority,
taskDependencies = deps',
taskDescription = description,
+ taskComments = [],
taskCreatedAt = now,
taskUpdatedAt = now
}
@@ -681,6 +709,20 @@ deleteTask tid =
withDb <| \conn ->
SQL.execute conn "DELETE FROM tasks WHERE id = ?" (SQL.Only tid)
+-- Add a comment to a task
+addComment :: Text -> Text -> IO Task
+addComment tid commentText =
+ withTaskLock <| do
+ tasks <- loadTasks
+ case findTask tid tasks of
+ Nothing -> panic "Task not found"
+ Just task -> do
+ now <- getCurrentTime
+ let newComment = Comment {commentText = commentText, commentCreatedAt = now}
+ updatedTask = task {taskComments = taskComments task ++ [newComment], taskUpdatedAt = now}
+ saveTask updatedTask
+ pure updatedTask
+
-- List tasks
listTasks :: Maybe TaskType -> Maybe Text -> Maybe Status -> Maybe Text -> IO [Task]
listTasks maybeType maybeParent maybeStatus maybeNamespace = do
@@ -963,6 +1005,11 @@ showTaskDetailed t = do
let indented = T.unlines <| map (" " <>) (T.lines (taskDescription t))
putText indented
+ unless (null (taskComments t)) <| do
+ putText ""
+ putText "Comments:"
+ traverse_ printComment (taskComments t)
+
putText ""
where
priorityDesc = case taskPriority t of
@@ -975,6 +1022,9 @@ showTaskDetailed t = do
printDependency dep =
putText <| " - " <> depId dep <> " [" <> T.pack (show (depType dep)) <> "]"
+ printComment c =
+ putText <| " [" <> T.pack (show (commentCreatedAt c)) <> "] " <> commentText c
+
red, green, yellow, blue, magenta, cyan, gray, bold :: Text -> Text
red t = "\ESC[31m" <> t <> "\ESC[0m"
green t = "\ESC[32m" <> t <> "\ESC[0m"