summaryrefslogtreecommitdiff
path: root/Omni/Task
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2025-11-20 11:00:45 -0500
committerBen Sima <ben@bsima.me>2025-11-20 11:35:18 -0500
commit0fea1f9ce76a2e3df5e4e69f7c50995acd4a0f81 (patch)
treecdc5d1ca0c9b4605e01397291296f7184cede612 /Omni/Task
parent5974c919ac505f01e7fbe454b906162b94b1ddd6 (diff)
task: sync database
Diffstat (limited to 'Omni/Task')
-rw-r--r--Omni/Task/Core.hs53
1 files changed, 50 insertions, 3 deletions
diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs
index 0351cf4..6c472c5 100644
--- a/Omni/Task/Core.hs
+++ b/Omni/Task/Core.hs
@@ -25,6 +25,7 @@ data Task = Task
taskParent :: Maybe Text, -- Parent epic ID
taskNamespace :: Maybe Text, -- Optional namespace (e.g., "Omni/Task", "Biz/Cloud")
taskStatus :: Status,
+ taskPriority :: Priority, -- Priority level (0-4)
taskDependencies :: [Dependency], -- List of dependencies with types
taskCreatedAt :: UTCTime,
taskUpdatedAt :: UTCTime
@@ -37,6 +38,10 @@ data TaskType = Epic | WorkTask
data Status = Open | InProgress | Done
deriving (Show, Eq, Generic)
+-- Priority levels (matching beads convention)
+data Priority = P0 | P1 | P2 | P3 | P4
+ deriving (Show, Eq, Ord, Generic)
+
data Dependency = Dependency
{ depId :: Text, -- ID of the task this depends on
depType :: DependencyType -- Type of dependency relationship
@@ -58,6 +63,10 @@ instance ToJSON Status
instance FromJSON Status
+instance ToJSON Priority
+
+instance FromJSON Priority
+
instance ToJSON DependencyType
instance FromJSON DependencyType
@@ -134,7 +143,7 @@ loadTasks = do
Just task -> Just task
Nothing -> migrateOldTask line
- -- Migrate old task format (with taskProject field) to new format
+ -- Migrate old task format (with taskProject field or missing priority) to new format
migrateOldTask :: Text -> Maybe Task
migrateOldTask line = case Aeson.decode (BLC.pack <| T.unpack line) :: Maybe Aeson.Object of
Nothing -> Nothing
@@ -151,6 +160,8 @@ loadTasks = do
taskType' = WorkTask -- Old tasks become WorkTask by default
taskParent' = Nothing
taskNamespace' = KM.lookup "taskNamespace" obj +> parseMaybe Aeson.parseJSON
+ -- Default priority to P2 (medium) for old tasks
+ taskPriority' = fromMaybe P2 (KM.lookup "taskPriority" obj +> parseMaybe Aeson.parseJSON)
in case (taskId', taskTitle', taskStatus', taskCreatedAt', taskUpdatedAt') of
(Just tid, Just title, Just status, Just created, Just updated) ->
Just
@@ -161,6 +172,7 @@ loadTasks = do
taskParent = taskParent',
taskNamespace = taskNamespace',
taskStatus = status,
+ taskPriority = taskPriority',
taskDependencies = newDeps,
taskCreatedAt = created,
taskUpdatedAt = updated
@@ -175,8 +187,8 @@ saveTask task = do
BLC.appendFile tasksFile (json <> "\n")
-- Create a new task
-createTask :: Text -> TaskType -> Maybe Text -> Maybe Text -> [Dependency] -> IO Task
-createTask title taskType parent namespace deps = do
+createTask :: Text -> TaskType -> Maybe Text -> Maybe Text -> Priority -> [Dependency] -> IO Task
+createTask title taskType parent namespace priority deps = do
tid <- generateId
now <- getCurrentTime
let task =
@@ -187,6 +199,7 @@ createTask title taskType parent namespace deps = do
taskParent = parent,
taskNamespace = namespace,
taskStatus = Open,
+ taskPriority = priority,
taskDependencies = deps,
taskCreatedAt = now,
taskUpdatedAt = now
@@ -241,6 +254,20 @@ getReadyTasks = do
isReady task = all (`elem` doneIds) (blockingDepIds task)
pure <| filter isReady openTasks
+-- Get dependency tree for a task (returns tasks)
+getDependencyTree :: Text -> IO [Task]
+getDependencyTree tid = do
+ tasks <- loadTasks
+ case filter (\t -> taskId t == tid) tasks of
+ [] -> pure []
+ (task : _) -> pure <| collectDeps tasks task
+ where
+ collectDeps :: [Task] -> Task -> [Task]
+ collectDeps allTasks task =
+ let depIds = map depId (taskDependencies task)
+ deps = filter (\t -> taskId t `elem` depIds) allTasks
+ in task : concatMap (collectDeps allTasks) deps
+
-- Show dependency tree for a task
showDependencyTree :: Text -> IO ()
showDependencyTree tid = do
@@ -256,6 +283,26 @@ showDependencyTree tid = do
deps = filter (\t -> taskId t `elem` depIds) allTasks
traverse_ (\dep -> printTree allTasks dep (indent + 1)) deps
+-- Get task tree (returns tasks hierarchically)
+getTaskTree :: Maybe Text -> IO [Task]
+getTaskTree maybeId = do
+ tasks <- loadTasks
+ case maybeId of
+ Nothing -> do
+ -- Return all epics with their children
+ let epics = filter (\t -> taskType t == Epic) tasks
+ in pure <| concatMap (collectChildren tasks) epics
+ Just tid -> do
+ -- Return specific task/epic with its children
+ case filter (\t -> taskId t == tid) tasks of
+ [] -> pure []
+ (task : _) -> pure <| collectChildren tasks task
+ where
+ collectChildren :: [Task] -> Task -> [Task]
+ collectChildren allTasks task =
+ let children = filter (\t -> taskParent t == Just (taskId task)) allTasks
+ in task : concatMap (collectChildren allTasks) children
+
-- Show task tree (epic with children, or all epics if no ID given)
showTaskTree :: Maybe Text -> IO ()
showTaskTree maybeId = do