summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.tasks/tasks-backup.jsonl12
-rw-r--r--.tasks/tasks-test.jsonl8
-rw-r--r--.tasks/tasks.jsonl24
-rw-r--r--Omni/Task.hs17
-rw-r--r--Omni/Task/Core.hs76
5 files changed, 109 insertions, 28 deletions
diff --git a/.tasks/tasks-backup.jsonl b/.tasks/tasks-backup.jsonl
new file mode 100644
index 0000000..3c975e8
--- /dev/null
+++ b/.tasks/tasks-backup.jsonl
@@ -0,0 +1,12 @@
+{"taskCreatedAt":"2025-11-08T20:03:50.230851965Z","taskDependencies":[],"taskId":"t-a1b2c3","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Show help text when task invoked without args","taskUpdatedAt":"2025-11-08T20:06:02.605878048Z"}
+{"taskCreatedAt":"2025-11-08T20:03:53.429072631Z","taskDependencies":[],"taskId":"t-d4e5f6","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Move dev instructions from README.md to AGENTS.md","taskUpdatedAt":"2025-11-08T20:06:22.732392229Z"}
+{"taskCreatedAt":"2025-11-08T20:06:27.395834401Z","taskDependencies":[],"taskId":"t-g7h8i9","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Task ids should be shorter. Use the sqids package in haskell to generate ids","taskUpdatedAt":"2025-11-08T21:00:37.311865046Z"}
+{"taskCreatedAt":"2025-11-08T20:09:35.590622249Z","taskDependencies":[],"taskId":"t-j0k1L2","taskProject":"task-manager","taskStatus":"Open","taskTitle":"Tasks should have an optional namespace associated with them. Namespaces are first class citizens in this monorepo","taskUpdatedAt":"2025-11-08T20:09:35.590622249Z"}
+{"taskCreatedAt":"2025-11-08T20:10:09.944217463Z","taskDependencies":[],"taskId":"t-m3n4o5","taskProject":"task-manager","taskStatus":"Open","taskTitle":"There should be a command to list all projects.","taskUpdatedAt":"2025-11-08T20:10:09.944217463Z"}
+{"taskCreatedAt":"2025-11-08T20:20:38.785442739Z","taskDependencies":[],"taskId":"t-p6q7r8","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Instruct agents too use git-branchless and a patch based workflow rather than traditional git commands if and when they need to record things in git.","taskUpdatedAt":"2025-11-08T21:09:06.854871964Z"}
+{"taskCreatedAt":"2025-11-08T20:22:20.116289616Z","taskDependencies":[],"taskId":"t-s9T0u1","taskProject":"task-manager","taskStatus":"Open","taskTitle":"instruct agents to include tests with all new features and bug fixes","taskUpdatedAt":"2025-11-08T20:22:20.116289616Z"}
+{"taskCreatedAt":"2025-11-08T20:45:12.764939794Z","taskDependencies":[],"taskId":"t-v2w3x4","taskProject":"task-manager","taskStatus":"Open","taskTitle":"instruct agents to run 'bild --test' and 'lint' for whatever namespace(s) they are working on after completing a task and fix any reported errors","taskUpdatedAt":"2025-11-08T20:45:12.764939794Z"}
+{"taskCreatedAt":"2025-11-08T20:48:43.183226361Z","taskDependencies":[],"taskId":"t-y5z6A7","taskProject":"ide","taskStatus":"Open","taskTitle":"The script Omni/Ide/typecheck.sh needs to support Haskell type checking in a similar fashion as how Omni/Ide/repl.sh is able to handle multiple languages","taskUpdatedAt":"2025-11-08T20:48:43.183226361Z"}
+{"taskCreatedAt":"2025-11-08T21:00:27.020241869Z","taskDependencies":[],"taskId":"t-1ky7gJ2","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Test shorter IDs","taskUpdatedAt":"2025-11-08T21:04:00.990704969Z"}
+{"taskCreatedAt":"2025-11-08T21:00:29.901677247Z","taskDependencies":[],"taskId":"t-1kyjmjN","taskProject":"task-manager","taskStatus":"Done","taskTitle":"Another test task","taskUpdatedAt":"2025-11-08T21:04:04.081664205Z"}
+{"taskCreatedAt":"2025-11-08T21:11:41.013924674Z","taskDependencies":[],"taskId":"t-1lhJhgS","taskProject":"misc","taskStatus":"Open","taskTitle":"Remove the old aider config in .aider* files and directories. Aider stinks and we will use amp going forward","taskUpdatedAt":"2025-11-08T21:11:41.013924674Z"}
diff --git a/.tasks/tasks-test.jsonl b/.tasks/tasks-test.jsonl
new file mode 100644
index 0000000..abc13ef
--- /dev/null
+++ b/.tasks/tasks-test.jsonl
@@ -0,0 +1,8 @@
+{"taskCreatedAt":"2025-11-09T12:51:46.56267588Z","taskDependencies":[],"taskId":"t-OxPCj7","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Test task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.56267588Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.564712781Z","taskDependencies":[],"taskId":"t-OxPCPZ","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Test task for list","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.564712781Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.573780484Z","taskDependencies":[],"taskId":"t-OxPFce","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"First task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.573780484Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.57535537Z","taskDependencies":[{"depId":"t-OxPFce","depType":"Blocks"}],"taskId":"t-OxPFBE","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Blocked task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.57535537Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.57629654Z","taskDependencies":[],"taskId":"t-OxPFQO","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Original task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.57629654Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.576622253Z","taskDependencies":[{"depId":"t-OxPFQO","depType":"DiscoveredFrom"}],"taskId":"t-OxPFW5","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Discovered work","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.576622253Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.577425682Z","taskDependencies":[],"taskId":"t-OxPG92","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Task A","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.577425682Z"}
+{"taskCreatedAt":"2025-11-09T12:51:46.577613884Z","taskDependencies":[{"depId":"t-OxPG92","depType":"Related"}],"taskId":"t-OxPGc4","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Task B","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:51:46.577613884Z"}
diff --git a/.tasks/tasks.jsonl b/.tasks/tasks.jsonl
index ff2a394..be3699f 100644
--- a/.tasks/tasks.jsonl
+++ b/.tasks/tasks.jsonl
@@ -1,12 +1,12 @@
-{"taskCreatedAt":"2025-11-09T12:28:48.574806406Z","taskDependencies":[],"taskId":"t-N2zIIk","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Test task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.574806406Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.591902984Z","taskDependencies":[],"taskId":"t-N2zNa5","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"First task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.591902984Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.592205598Z","taskDependencies":[{"depId":"t-N2zNa5","depType":"Blocks"}],"taskId":"t-N2zNeY","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Blocked task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.592205598Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.593123597Z","taskDependencies":[],"taskId":"t-N2zNtM","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Original task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.593123597Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.59342775Z","taskDependencies":[{"depId":"t-N2zNtM","depType":"DiscoveredFrom"}],"taskId":"t-N2zNyG","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Discovered work","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.59342775Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.594193628Z","taskDependencies":[],"taskId":"t-N2zNL2","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Task A","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.594193628Z"}
-{"taskCreatedAt":"2025-11-09T12:28:48.594472081Z","taskDependencies":[{"depId":"t-N2zNL2","depType":"Related"}],"taskId":"t-N2zNPx","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Task B","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:28:48.594472081Z"}
-{"taskCreatedAt":"2025-11-09T12:30:08.108951426Z","taskDependencies":[],"taskId":"t-N7Xrb7","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Test task A","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:30:08.108951426Z"}
-{"taskCreatedAt":"2025-11-09T12:30:08.2734999Z","taskDependencies":[{"depId":"t-MTdiPS","depType":"Blocks"}],"taskId":"t-N7Y7Z8","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Test task B with blocking dep","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:30:08.2734999Z"}
-{"taskCreatedAt":"2025-11-09T12:30:08.459060403Z","taskDependencies":[{"depId":"t-MTdiPS","depType":"DiscoveredFrom"}],"taskId":"t-N7YUg2","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Discovered work","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:30:08.459060403Z"}
-{"taskCreatedAt":"2025-11-09T12:30:45.984751589Z","taskDependencies":[],"taskId":"t-Nawmp8","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Blocking task example","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:30:54.668780601Z"}
-{"taskCreatedAt":"2025-11-09T12:30:49.990290546Z","taskDependencies":[{"depId":"t-Nawmp8","depType":"Blocks"}],"taskId":"t-NaNaqA","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Dependent task","taskType":"WorkTask","taskUpdatedAt":"2025-11-09T12:30:49.990290546Z"}
+{"taskCreatedAt":"2025-11-08T20:03:50.230851965Z","taskDependencies":[],"taskId":"t-a1b2c3","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Show help text when task invoked without args","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:06:02.605878048Z"}
+{"taskCreatedAt":"2025-11-08T20:03:53.429072631Z","taskDependencies":[],"taskId":"t-d4e5f6","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Move dev instructions from README.md to AGENTS.md","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:06:22.732392229Z"}
+{"taskCreatedAt":"2025-11-08T20:06:27.395834401Z","taskDependencies":[],"taskId":"t-g7h8i9","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Task ids should be shorter. Use the sqids package in haskell to generate ids","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T21:00:37.311865046Z"}
+{"taskCreatedAt":"2025-11-08T20:09:35.590622249Z","taskDependencies":[],"taskId":"t-j0k1L2","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Tasks should have an optional namespace associated with them. Namespaces are first class citizens in this monorepo","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:09:35.590622249Z"}
+{"taskCreatedAt":"2025-11-08T20:10:09.944217463Z","taskDependencies":[],"taskId":"t-m3n4o5","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"There should be a command to list all projects.","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:10:09.944217463Z"}
+{"taskCreatedAt":"2025-11-08T20:20:38.785442739Z","taskDependencies":[],"taskId":"t-p6q7r8","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Instruct agents too use git-branchless and a patch based workflow rather than traditional git commands if and when they need to record things in git.","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T21:09:06.854871964Z"}
+{"taskCreatedAt":"2025-11-08T20:22:20.116289616Z","taskDependencies":[],"taskId":"t-s9T0u1","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"instruct agents to include tests with all new features and bug fixes","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:22:20.116289616Z"}
+{"taskCreatedAt":"2025-11-08T20:45:12.764939794Z","taskDependencies":[],"taskId":"t-v2w3x4","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"instruct agents to run 'bild --test' and 'lint' for whatever namespace(s) they are working on after completing a task and fix any reported errors","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:45:12.764939794Z"}
+{"taskCreatedAt":"2025-11-08T20:48:43.183226361Z","taskDependencies":[],"taskId":"t-y5z6A7","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"The script Omni/Ide/typecheck.sh needs to support Haskell type checking in a similar fashion as how Omni/Ide/repl.sh is able to handle multiple languages","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T20:48:43.183226361Z"}
+{"taskCreatedAt":"2025-11-08T21:00:27.020241869Z","taskDependencies":[],"taskId":"t-1ky7gJ2","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Test shorter IDs","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T21:04:00.990704969Z"}
+{"taskCreatedAt":"2025-11-08T21:00:29.901677247Z","taskDependencies":[],"taskId":"t-1kyjmjN","taskNamespace":null,"taskParent":null,"taskStatus":"Done","taskTitle":"Another test task","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T21:04:04.081664205Z"}
+{"taskCreatedAt":"2025-11-08T21:11:41.013924674Z","taskDependencies":[],"taskId":"t-1lhJhgS","taskNamespace":null,"taskParent":null,"taskStatus":"Open","taskTitle":"Remove the old aider config in .aider* files and directories. Aider stinks and we will use amp going forward","taskType":"WorkTask","taskUpdatedAt":"2025-11-08T21:11:41.013924674Z"}
diff --git a/Omni/Task.hs b/Omni/Task.hs
index 571c72e..f10ae25 100644
--- a/Omni/Task.hs
+++ b/Omni/Task.hs
@@ -13,6 +13,7 @@ import qualified Omni.Namespace as Namespace
import Omni.Task.Core
import qualified Omni.Test as Test
import System.Directory (doesFileExist, removeFile)
+import System.Environment (setEnv)
main :: IO ()
main = Cli.main plan
@@ -165,18 +166,24 @@ unitTests :: Test.Tree
unitTests =
Test.group
"Unit tests"
- [ Test.unit "can create task" <| do
- -- Clean up before test
- exists <- doesFileExist ".tasks/tasks.jsonl"
- when exists <| removeFile ".tasks/tasks.jsonl"
-
+ [ Test.unit "setup test database" <| do
+ -- Set up test mode for all tests
+ setEnv "TASK_TEST_MODE" "1"
+
+ -- Clean up test database before all tests
+ let testFile = ".tasks/tasks-test.jsonl"
+ exists <- doesFileExist testFile
+ when exists <| removeFile testFile
initTaskDb
+ True Test.@?= True,
+ Test.unit "can create task" <| do
task <- createTask "Test task" WorkTask Nothing Nothing []
taskTitle task Test.@?= "Test task"
taskType task Test.@?= WorkTask
taskStatus task Test.@?= Open
null (taskDependencies task) Test.@?= True,
Test.unit "can list tasks" <| do
+ _ <- createTask "Test task for list" WorkTask Nothing Nothing []
tasks <- listTasks Nothing Nothing
not (null tasks) Test.@?= True,
Test.unit "ready tasks exclude blocked ones" <| do
diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs
index 1137d8d..6285ef7 100644
--- a/Omni/Task/Core.hs
+++ b/Omni/Task/Core.hs
@@ -5,13 +5,18 @@
module Omni.Task.Core where
import Alpha
+import Control.Monad ((>>=))
import Data.Aeson (FromJSON, ToJSON, decode, encode)
+import qualified Data.Aeson as Aeson
+import qualified Data.Aeson.KeyMap as KM
+import Data.Aeson.Types (parseMaybe)
import qualified Data.ByteString.Lazy.Char8 as BLC
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Time (UTCTime, diffTimeToPicoseconds, getCurrentTime, utctDayTime)
import GHC.Generics ()
import System.Directory (createDirectoryIfMissing, doesFileExist)
+import System.Environment (lookupEnv)
-- Core data types
data Task = Task
@@ -66,14 +71,23 @@ instance ToJSON Task
instance FromJSON Task
+-- Get the tasks database file path (use test file if TASK_TEST_MODE is set)
+getTasksFilePath :: IO FilePath
+getTasksFilePath = do
+ testMode <- lookupEnv "TASK_TEST_MODE"
+ pure <| case testMode of
+ Just "1" -> ".tasks/tasks-test.jsonl"
+ _ -> ".tasks/tasks.jsonl"
+
-- Initialize the task database
initTaskDb :: IO ()
initTaskDb = do
createDirectoryIfMissing True ".tasks"
- exists <- doesFileExist ".tasks/tasks.jsonl"
+ tasksFile <- getTasksFilePath
+ exists <- doesFileExist tasksFile
unless exists <| do
- TIO.writeFile ".tasks/tasks.jsonl" ""
- putText "Initialized task database at .tasks/tasks.jsonl"
+ TIO.writeFile tasksFile ""
+ putText <| "Initialized task database at " <> T.pack tasksFile
-- Generate a short ID using base62 encoding of timestamp
generateId :: IO Text
@@ -101,13 +115,14 @@ toBase62 n = reverse <| go n
[] -> '0' -- Fallback (should never happen)
in char : go q
--- Load all tasks from JSONL file
+-- Load all tasks from JSONL file (with migration support)
loadTasks :: IO [Task]
loadTasks = do
- exists <- doesFileExist ".tasks/tasks.jsonl"
+ tasksFile <- getTasksFilePath
+ exists <- doesFileExist tasksFile
if exists
then do
- content <- TIO.readFile ".tasks/tasks.jsonl"
+ content <- TIO.readFile tasksFile
let taskLines = T.lines content
pure <| mapMaybe decodeTask taskLines
else pure []
@@ -116,13 +131,49 @@ loadTasks = do
decodeTask line =
if T.null line
then Nothing
- else decode (BLC.pack <| T.unpack line)
+ else case decode (BLC.pack <| T.unpack line) of
+ Just task -> Just task
+ Nothing -> migrateOldTask line
+
+ -- Migrate old task format (with taskProject field) to new format
+ migrateOldTask :: Text -> Maybe Task
+ migrateOldTask line = case Aeson.decode (BLC.pack <| T.unpack line) :: Maybe Aeson.Object of
+ Nothing -> Nothing
+ Just obj ->
+ let taskId' = KM.lookup "taskId" obj +> parseMaybe Aeson.parseJSON
+ taskTitle' = KM.lookup "taskTitle" obj +> parseMaybe Aeson.parseJSON
+ taskStatus' = KM.lookup "taskStatus" obj +> parseMaybe Aeson.parseJSON
+ taskCreatedAt' = KM.lookup "taskCreatedAt" obj +> parseMaybe Aeson.parseJSON
+ taskUpdatedAt' = KM.lookup "taskUpdatedAt" obj +> parseMaybe Aeson.parseJSON
+ -- Extract old taskDependencies (could be [Text] or [Dependency])
+ oldDeps = KM.lookup "taskDependencies" obj +> parseMaybe Aeson.parseJSON :: Maybe [Text]
+ newDeps = maybe [] (map (\tid -> Dependency {depId = tid, depType = Blocks})) oldDeps
+ -- taskProject is ignored in new format (use epics instead)
+ taskType' = WorkTask -- Old tasks become WorkTask by default
+ taskParent' = Nothing
+ taskNamespace' = KM.lookup "taskNamespace" obj +> parseMaybe Aeson.parseJSON
+ in case (taskId', taskTitle', taskStatus', taskCreatedAt', taskUpdatedAt') of
+ (Just tid, Just title, Just status, Just created, Just updated) ->
+ Just
+ Task
+ { taskId = tid,
+ taskTitle = title,
+ taskType = taskType',
+ taskParent = taskParent',
+ taskNamespace = taskNamespace',
+ taskStatus = status,
+ taskDependencies = newDeps,
+ taskCreatedAt = created,
+ taskUpdatedAt = updated
+ }
+ _ -> Nothing
-- Save a single task (append to JSONL)
saveTask :: Task -> IO ()
saveTask task = do
+ tasksFile <- getTasksFilePath
let json = encode task
- BLC.appendFile ".tasks/tasks.jsonl" (json <> "\n")
+ BLC.appendFile tasksFile (json <> "\n")
-- Create a new task
createTask :: Text -> TaskType -> Maybe Text -> Maybe Text -> [Dependency] -> IO Task
@@ -155,7 +206,8 @@ updateTaskStatus tid newStatus = do
then t {taskStatus = newStatus, taskUpdatedAt = now}
else t
-- Rewrite the entire file (simple approach for MVP)
- TIO.writeFile ".tasks/tasks.jsonl" ""
+ tasksFile <- getTasksFilePath
+ TIO.writeFile tasksFile ""
traverse_ saveTask updatedTasks
-- List tasks, optionally filtered by type or parent
@@ -225,7 +277,8 @@ exportTasks :: IO ()
exportTasks = do
tasks <- loadTasks
-- Rewrite the entire file with deduplicated tasks
- TIO.writeFile ".tasks/tasks.jsonl" ""
+ tasksFile <- getTasksFilePath
+ TIO.writeFile tasksFile ""
traverse_ saveTask tasks
-- Import tasks: Read from another JSONL file and merge with existing tasks
@@ -252,7 +305,8 @@ importTasks filePath = do
allTasks = updatedTasks ++ newTasks
-- Rewrite tasks.jsonl with merged data
- TIO.writeFile ".tasks/tasks.jsonl" ""
+ tasksFile <- getTasksFilePath
+ TIO.writeFile tasksFile ""
traverse_ saveTask allTasks
where
decodeTask :: Text -> Maybe Task