From 0fea1f9ce76a2e3df5e4e69f7c50995acd4a0f81 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Thu, 20 Nov 2025 11:00:45 -0500 Subject: task: sync database --- Omni/Task/Core.hs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'Omni/Task/Core.hs') 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 -- cgit v1.2.3