#pragma once #include #include #include #include #include namespace kanban { struct Issue { std::string id; std::string title; std::string status; std::string type; std::string scope; std::string priority; std::vector domain; std::vector tags; std::vector depends; std::vector blocks; std::vector related; std::string flow; std::string file_path; bool completed = false; std::string body; // only filled in detail GET }; struct Flow { std::string id; std::string title; std::string status; std::string kind; std::vector tags; std::string file_path; std::string body; }; struct Meta { std::vector statuses; std::vector priorities; std::vector scopes; std::vector types; }; struct Filters { std::set domains; std::set scopes; std::set priorities; std::set tags; bool include_completed = false; bool show_issues = true; bool show_flows = true; }; struct State { std::mutex mu; std::string backend_url = "http://127.0.0.1:8487"; std::vector issues; std::vector flows; Meta meta; Filters filters; std::string selected_issue_id; Issue selected_issue_detail; bool loading = false; std::string last_error; long long last_refresh_ns = 0; std::map agent_active; // issue_id -> run_id bool agent_runner_up = false; std::string last_launch_msg; }; State& state(); // HTTP operations (block briefly, called from background or coalesced). bool refresh_issues(); bool refresh_flows(); bool refresh_meta(); bool refresh_issue_detail(const std::string& id); bool patch_issue_status(const std::string& id, const std::string& new_status); bool patch_issue_fields(const std::string& id, const std::string& json_partial); bool refresh_agent_status(); bool launch_agent(const std::string& issue_id); bool is_agent_active(const std::string& issue_id); // Background SSE subscription (no-op if already started). void start_sse(); void stop_sse(); // Filters helpers. bool passes_filters(const Issue& iss); std::vector collect_domains(); std::vector collect_tags(); } // namespace kanban