use std::path::Path;
#[derive(Debug, Clone)]
pub struct BeadsTask {
pub id: String,
pub title: String,
pub description: Option<String>,
}
pub fn find_in_progress_tasks(working_dir: &str) -> Vec<BeadsTask> {
let jsonl_path = Path::new(working_dir).join(".beads/issues.jsonl");
let content = match std::fs::read_to_string(&jsonl_path) {
Ok(c) => c,
Err(_) => return Vec::new(),
};
let mut tasks: Vec<(String, BeadsTask)> = Vec::new();
for line in content.lines() {
if !line.contains("\"in_progress\"") {
continue;
}
if let Ok(val) = serde_json::from_str::<serde_json::Value>(line) {
let status = val
.get("status")
.and_then(|v| v.as_str())
.unwrap_or_default();
if status != "in_progress" {
continue;
}
let id = val
.get("id")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string();
let title = val
.get("title")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string();
let updated_at = val
.get("updated_at")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string();
let description = val
.get("description")
.and_then(|v| v.as_str())
.filter(|s| !s.is_empty())
.map(|s| s.to_string());
if !id.is_empty() && !title.is_empty() {
tasks.push((
updated_at,
BeadsTask {
id,
title,
description,
},
));
}
}
}
tasks.sort_by(|a, b| b.0.cmp(&a.0));
tasks.into_iter().map(|(_, task)| task).collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_find_in_progress_tasks_empty() {
let dir = tempfile::tempdir().unwrap();
let result = find_in_progress_tasks(dir.path().to_str().unwrap());
assert!(result.is_empty());
}
#[test]
fn test_find_in_progress_tasks() {
let dir = tempfile::tempdir().unwrap();
let beads_dir = dir.path().join(".beads");
fs::create_dir_all(&beads_dir).unwrap();
fs::write(
beads_dir.join("issues.jsonl"),
r#"{"id":"test-1","title":"Open task","status":"open","updated_at":"2026-01-01T00:00:00Z"}
{"id":"test-2","title":"Active task","status":"in_progress","updated_at":"2026-01-02T00:00:00Z"}
{"id":"test-3","title":"Done task","status":"closed","updated_at":"2026-01-03T00:00:00Z"}
{"id":"test-4","title":"Another active","status":"in_progress","updated_at":"2026-01-04T00:00:00Z"}
"#,
)
.unwrap();
let result = find_in_progress_tasks(dir.path().to_str().unwrap());
assert_eq!(result.len(), 2);
assert_eq!(result[0].title, "Another active"); assert_eq!(result[1].title, "Active task");
}
}