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"
20#include "nlohmann/json.hpp"
21using json = nlohmann::json;
30std::string CurrentTimestamp() {
31 auto now = absl::Now();
32 return absl::FormatTime(
"%Y-%m-%d %H:%M:%S", now, absl::LocalTimeZone());
57 if (str ==
"in_progress")
59 if (str ==
"completed")
63 if (str ==
"cancelled")
73 data_dir_ = (std::filesystem::current_path() /
".yaze" /
"agent").
string();
79 : data_dir_(data_dir),
80 todos_file_((std::filesystem::path(data_dir) /
"todos.json").string()) {}
97 return absl::OkStatus();
102 return absl::StrFormat(
"todo_%d",
next_id_++);
106 return CurrentTimestamp();
123 auto status =
Save();
135 [&
id](
const TodoItem& t) { return t.id == id; });
138 return absl::NotFoundError(
139 absl::StrFormat(
"TODO with ID %s not found",
id));
153 [&
id](
const TodoItem& t) { return t.id == id; });
156 return absl::NotFoundError(
157 absl::StrFormat(
"TODO with ID %s not found",
id));
168 [&
id](
const TodoItem& t) { return t.id == id; });
171 return absl::NotFoundError(
172 absl::StrFormat(
"TODO with ID %s not found",
id));
184 std::vector<TodoItem> result;
185 std::copy_if(
todos_.begin(),
todos_.end(), std::back_inserter(result),
186 [status](
const TodoItem& t) { return t.status == status; });
191 const std::string&
category)
const {
192 std::vector<TodoItem> result;
194 todos_.begin(),
todos_.end(), std::back_inserter(result),
202 auto dep_result =
GetTodo(dep_id);
203 if (!dep_result.ok()) {
215 std::vector<TodoItem> actionable;
216 for (
const auto& item :
todos_) {
220 actionable.push_back(item);
224 if (actionable.empty()) {
225 return absl::NotFoundError(
"No actionable TODOs found");
229 std::sort(actionable.begin(), actionable.end(),
231 return a.priority > b.priority;
234 return actionable[0];
239 [&
id](
const TodoItem& t) { return t.id == id; });
242 return absl::NotFoundError(
243 absl::StrFormat(
"TODO with ID %s not found",
id));
252 return t.status == TodoItem::Status::COMPLETED;
260 std::vector<TodoItem> plan;
261 std::vector<TodoItem> pending;
264 std::copy_if(
todos_.begin(),
todos_.end(), std::back_inserter(pending),
266 return t.status == TodoItem::Status::PENDING ||
267 t.status == TodoItem::Status::BLOCKED;
271 std::vector<TodoItem> sorted;
272 std::set<std::string> completed_ids;
274 while (!pending.empty()) {
275 bool made_progress =
false;
277 for (
auto it = pending.begin(); it != pending.end();) {
279 for (
const auto& dep_id : it->dependencies) {
280 if (completed_ids.find(dep_id) == completed_ids.end()) {
287 sorted.push_back(*it);
288 completed_ids.insert(it->id);
289 it = pending.erase(it);
290 made_progress =
true;
296 if (!made_progress && !pending.empty()) {
297 return absl::FailedPreconditionError(
298 "Circular dependency detected in TODOs");
303 std::stable_sort(sorted.begin(), sorted.end(),
305 return a.priority > b.priority;
313 json j_todos = json::array();
315 for (
const auto& item :
todos_) {
317 j_item[
"id"] = item.id;
318 j_item[
"description"] = item.description;
319 j_item[
"status"] = item.StatusToString();
320 j_item[
"category"] = item.category;
321 j_item[
"priority"] = item.priority;
322 j_item[
"dependencies"] = item.dependencies;
323 j_item[
"tools_needed"] = item.tools_needed;
324 j_item[
"created_at"] = item.created_at;
325 j_item[
"updated_at"] = item.updated_at;
326 j_item[
"notes"] = item.notes;
328 j_todos.push_back(j_item);
334 using yaze::platform::WasmStorage;
335 return WasmStorage::SaveProject(
"agent_todos", j_todos.dump());
338 if (!file.is_open()) {
339 return absl::InternalError(
340 absl::StrFormat(
"Failed to open file: %s",
todos_file_));
343 file << j_todos.dump(2);
344 return absl::OkStatus();
348 return absl::UnimplementedError(
"JSON support required for TODO persistence");
358 using yaze::platform::WasmStorage;
359 auto result = WasmStorage::LoadProject(
"agent_todos");
362 if (absl::IsNotFound(result.status())) {
364 return absl::OkStatus();
366 return result.status();
370 j_todos = json::parse(*result);
371 }
catch (
const std::exception& e) {
372 return absl::InternalError(
373 absl::StrFormat(
"Failed to parse persisted JSON: %s", e.what()));
377 if (!file.is_open()) {
378 return absl::InternalError(
379 absl::StrFormat(
"Failed to open file: %s",
todos_file_));
384 }
catch (
const std::exception& e) {
385 return absl::InternalError(
386 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
391 for (
const auto& j_item : j_todos) {
393 item.
id = j_item.value(
"id",
"");
394 item.
description = j_item.value(
"description",
"");
396 item.
category = j_item.value(
"category",
"");
397 item.
priority = j_item.value(
"priority", 0);
399 j_item.value(
"dependencies", std::vector<std::string>{});
401 j_item.value(
"tools_needed", std::vector<std::string>{});
402 item.
created_at = j_item.value(
"created_at",
"");
403 item.
updated_at = j_item.value(
"updated_at",
"");
404 item.
notes = j_item.value(
"notes",
"");
409 if (item.
id.find(
"todo_") == 0) {
410 int id_num = std::stoi(item.
id.substr(5));
417 return absl::OkStatus();
419 return absl::UnimplementedError(
"JSON support required for TODO persistence");
425 json j_todos = json::array();
427 for (
const auto& item :
todos_) {
429 j_item[
"id"] = item.id;
430 j_item[
"description"] = item.description;
431 j_item[
"status"] = item.StatusToString();
432 j_item[
"category"] = item.category;
433 j_item[
"priority"] = item.priority;
434 j_item[
"dependencies"] = item.dependencies;
435 j_item[
"tools_needed"] = item.tools_needed;
436 j_item[
"created_at"] = item.created_at;
437 j_item[
"updated_at"] = item.updated_at;
438 j_item[
"notes"] = item.notes;
440 j_todos.push_back(j_item);
443 return j_todos.dump(2);
452 json j_todos = json::parse(json_str);
455 for (
const auto& j_item : j_todos) {
457 item.
id = j_item.value(
"id",
"");
458 item.
description = j_item.value(
"description",
"");
460 item.
category = j_item.value(
"category",
"");
461 item.
priority = j_item.value(
"priority", 0);
463 j_item.value(
"dependencies", std::vector<std::string>{});
465 j_item.value(
"tools_needed", std::vector<std::string>{});
466 item.
created_at = j_item.value(
"created_at",
"");
467 item.
updated_at = j_item.value(
"updated_at",
"");
468 item.
notes = j_item.value(
"notes",
"");
474 }
catch (
const std::exception& e) {
475 return absl::InternalError(
476 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
479 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.
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