9#include "absl/strings/str_cat.h"
10#include "absl/strings/str_format.h"
11#include "absl/time/clock.h"
12#include "absl/time/time.h"
16#include "nlohmann/json.hpp"
17using json = nlohmann::json;
26std::string CurrentTimestamp() {
27 auto now = absl::Now();
28 return absl::FormatTime(
"%Y-%m-%d %H:%M:%S", now, absl::LocalTimeZone());
40 default:
return "unknown";
58 data_dir_ = (std::filesystem::current_path() /
".yaze" /
"agent").
string();
64 : data_dir_(data_dir),
65 todos_file_((std::filesystem::path(data_dir) /
"todos.json").string()) {}
78 return absl::OkStatus();
82 return absl::StrFormat(
"todo_%d",
next_id_++);
86 return CurrentTimestamp();
90 const std::string& description,
91 const std::string& category,
104 auto status =
Save();
115 [&
id](
const TodoItem& t) { return t.id == id; });
118 return absl::NotFoundError(absl::StrFormat(
"TODO with ID %s not found",
id));
131 [&
id](
const TodoItem& t) { return t.id == id; });
134 return absl::NotFoundError(absl::StrFormat(
"TODO with ID %s not found",
id));
145 [&
id](
const TodoItem& t) { return t.id == id; });
148 return absl::NotFoundError(absl::StrFormat(
"TODO with ID %s not found",
id));
159 std::vector<TodoItem> result;
160 std::copy_if(
todos_.begin(),
todos_.end(), std::back_inserter(result),
161 [status](
const TodoItem& t) { return t.status == status; });
166 std::vector<TodoItem> result;
167 std::copy_if(
todos_.begin(),
todos_.end(), std::back_inserter(result),
168 [&category](
const TodoItem& t) { return t.category == category; });
175 auto dep_result =
GetTodo(dep_id);
176 if (!dep_result.ok()) {
188 std::vector<TodoItem> actionable;
189 for (
const auto& item :
todos_) {
193 actionable.push_back(item);
197 if (actionable.empty()) {
198 return absl::NotFoundError(
"No actionable TODOs found");
202 std::sort(actionable.begin(), actionable.end(),
204 return a.priority > b.priority;
207 return actionable[0];
212 [&
id](
const TodoItem& t) { return t.id == id; });
215 return absl::NotFoundError(absl::StrFormat(
"TODO with ID %s not found",
id));
225 return t.status == TodoItem::Status::COMPLETED;
232 std::vector<TodoItem> plan;
233 std::vector<TodoItem> pending;
236 std::copy_if(
todos_.begin(),
todos_.end(), std::back_inserter(pending),
238 return t.status == TodoItem::Status::PENDING ||
239 t.status == TodoItem::Status::BLOCKED;
243 std::vector<TodoItem> sorted;
244 std::set<std::string> completed_ids;
246 while (!pending.empty()) {
247 bool made_progress =
false;
249 for (
auto it = pending.begin(); it != pending.end(); ) {
251 for (
const auto& dep_id : it->dependencies) {
252 if (completed_ids.find(dep_id) == completed_ids.end()) {
259 sorted.push_back(*it);
260 completed_ids.insert(it->id);
261 it = pending.erase(it);
262 made_progress =
true;
268 if (!made_progress && !pending.empty()) {
269 return absl::FailedPreconditionError(
270 "Circular dependency detected in TODOs");
275 std::stable_sort(sorted.begin(), sorted.end(),
277 return a.priority > b.priority;
285 json j_todos = json::array();
287 for (
const auto& item :
todos_) {
289 j_item[
"id"] = item.id;
290 j_item[
"description"] = item.description;
291 j_item[
"status"] = item.StatusToString();
292 j_item[
"category"] = item.category;
293 j_item[
"priority"] = item.priority;
294 j_item[
"dependencies"] = item.dependencies;
295 j_item[
"tools_needed"] = item.tools_needed;
296 j_item[
"created_at"] = item.created_at;
297 j_item[
"updated_at"] = item.updated_at;
298 j_item[
"notes"] = item.notes;
300 j_todos.push_back(j_item);
304 if (!file.is_open()) {
305 return absl::InternalError(
306 absl::StrFormat(
"Failed to open file: %s",
todos_file_));
309 file << j_todos.dump(2);
310 return absl::OkStatus();
312 return absl::UnimplementedError(
"JSON support required for TODO persistence");
319 if (!file.is_open()) {
320 return absl::InternalError(
321 absl::StrFormat(
"Failed to open file: %s",
todos_file_));
327 }
catch (
const std::exception& e) {
328 return absl::InternalError(
329 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
333 for (
const auto& j_item : j_todos) {
335 item.
id = j_item.value(
"id",
"");
336 item.
description = j_item.value(
"description",
"");
338 item.
category = j_item.value(
"category",
"");
339 item.
priority = j_item.value(
"priority", 0);
340 item.
dependencies = j_item.value(
"dependencies", std::vector<std::string>{});
341 item.
tools_needed = j_item.value(
"tools_needed", std::vector<std::string>{});
342 item.
created_at = j_item.value(
"created_at",
"");
343 item.
updated_at = j_item.value(
"updated_at",
"");
344 item.
notes = j_item.value(
"notes",
"");
349 if (item.
id.find(
"todo_") == 0) {
350 int id_num = std::stoi(item.
id.substr(5));
357 return absl::OkStatus();
359 return absl::UnimplementedError(
"JSON support required for TODO persistence");
365 json j_todos = json::array();
367 for (
const auto& item :
todos_) {
369 j_item[
"id"] = item.id;
370 j_item[
"description"] = item.description;
371 j_item[
"status"] = item.StatusToString();
372 j_item[
"category"] = item.category;
373 j_item[
"priority"] = item.priority;
374 j_item[
"dependencies"] = item.dependencies;
375 j_item[
"tools_needed"] = item.tools_needed;
376 j_item[
"created_at"] = item.created_at;
377 j_item[
"updated_at"] = item.updated_at;
378 j_item[
"notes"] = item.notes;
380 j_todos.push_back(j_item);
383 return j_todos.dump(2);
392 json j_todos = json::parse(json_str);
395 for (
const auto& j_item : j_todos) {
397 item.
id = j_item.value(
"id",
"");
398 item.
description = j_item.value(
"description",
"");
400 item.
category = j_item.value(
"category",
"");
401 item.
priority = j_item.value(
"priority", 0);
402 item.
dependencies = j_item.value(
"dependencies", std::vector<std::string>{});
403 item.
tools_needed = j_item.value(
"tools_needed", std::vector<std::string>{});
404 item.
created_at = j_item.value(
"created_at",
"");
405 item.
updated_at = j_item.value(
"updated_at",
"");
406 item.
notes = j_item.value(
"notes",
"");
412 }
catch (
const std::exception& e) {
413 return absl::InternalError(
414 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
417 return absl::UnimplementedError(
"JSON support required for TODO import");
absl::Status UpdateTodo(const std::string &id, const TodoItem &item)
Update an existing TODO item.
absl::Status ClearCompleted()
Clear all completed TODOs.
absl::Status ImportFromJson(const std::string &json)
Import TODOs from JSON string.
absl::Status Save()
Save TODOs to persistent storage.
absl::StatusOr< std::vector< TodoItem > > GenerateExecutionPlan() const
Generate an execution plan based on dependencies.
std::string GetTimestamp() const
absl::StatusOr< TodoItem > CreateTodo(const std::string &description, const std::string &category="", int priority=0)
Create a new TODO item.
absl::StatusOr< TodoItem > GetNextActionableTodo() const
Get the next actionable TODO (respecting dependencies and priority)
std::string ExportAsJson() const
Export TODOs as JSON string.
std::vector< TodoItem > GetTodosByCategory(const std::string &category) const
Get TODO items by category.
bool CanExecute(const TodoItem &item) const
absl::Status Load()
Load TODOs from persistent storage.
absl::Status DeleteTodo(const std::string &id)
Delete a TODO item.
absl::Status UpdateStatus(const std::string &id, TodoItem::Status status)
Update TODO status.
absl::Status Initialize()
Initialize the TODO manager and load persisted data.
std::vector< TodoItem > GetTodosByStatus(TodoItem::Status status) const
Get TODO items by status.
absl::StatusOr< TodoItem > GetTodo(const std::string &id) const
Get a TODO item by ID.
std::vector< TodoItem > todos_
std::vector< TodoItem > GetAllTodos() const
Get all TODO items.
Main namespace for the application.
Represents a single TODO item for task management.
enum yaze::cli::agent::TodoItem::Status status
static Status StringToStatus(const std::string &str)
std::vector< std::string > dependencies
std::vector< std::string > tools_needed
std::string StatusToString() const