Skip to main content

lean_ctx/core/import/
cursor.rs

1//! Cursor agent-transcript import.
2
3use std::path::{Path, PathBuf};
4
5use super::{ImportResult, ImportSource, home_dir, push_error, read_jsonl_files};
6
7/// Imports Cursor transcripts from `~/.cursor/projects/*/agent-transcripts`.
8#[must_use]
9pub fn import() -> ImportResult {
10    let Some(home) = home_dir() else {
11        return ImportResult::default();
12    };
13    import_from_root(&home.join(".cursor/projects"))
14}
15
16/// Imports agent transcript JSONL files from a Cursor projects directory.
17#[must_use]
18pub fn import_from_root(root: &Path) -> ImportResult {
19    let projects = match std::fs::read_dir(root) {
20        Ok(projects) => projects,
21        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
22            return ImportResult::default();
23        }
24        Err(error) => {
25            let mut result = ImportResult::default();
26            push_error(&mut result, format!("{}: {error}", root.display()));
27            return result;
28        }
29    };
30
31    let mut files = Vec::new();
32    let mut errors = Vec::new();
33    for project in projects.flatten() {
34        let transcript_dir = project.path().join("agent-transcripts");
35        if !transcript_dir.is_dir() {
36            continue;
37        }
38        match std::fs::read_dir(&transcript_dir) {
39            Ok(entries) => collect_jsonl_files(entries, &mut files),
40            Err(error) => errors.push(format!("{}: {error}", transcript_dir.display())),
41        }
42    }
43    files.sort();
44    let mut result = read_jsonl_files(ImportSource::Cursor, root, files);
45    for error in errors {
46        push_error(&mut result, error);
47    }
48    result
49}
50
51fn collect_jsonl_files(entries: std::fs::ReadDir, files: &mut Vec<PathBuf>) {
52    for entry in entries.flatten() {
53        let path = entry.path();
54        if path.is_file()
55            && path
56                .extension()
57                .is_some_and(|extension| extension == "jsonl")
58        {
59            files.push(path);
60        }
61    }
62}