agileplus-cli 0.3.0

Typed intent graphs for engineering work — convert prompts into validated DAGs of intents, features, tasks, tests, and edges, then store, query, and serve them from Rust, HTTP, or MCP.
/// Extract a short title from the first line of a prompt.
pub fn extract_title(prompt: &str) -> String {
    let first_line = prompt.lines().next().unwrap_or(prompt);
    let trimmed = first_line.trim();
    if trimmed.len() > 80 {
        format!("{:.80}...", trimmed)
    } else {
        trimmed.to_string()
    }
}

/// Decompose a prompt into candidate features via keyword scanning.
pub fn decompose_features(prompt: &str) -> Vec<String> {
    let mut features = Vec::new();
    let lower = prompt.to_lowercase();

    let keywords: Vec<(&str, Vec<&str>)> = vec![
        ("auth", vec!["Authentication flow", "Session management"]),
        ("login", vec!["User login flow", "Credential validation"]),
        ("oauth", vec!["OAuth2 integration", "Token refresh mechanism"]),
        (
            "database",
            vec!["Database schema", "Migration support", "Data access layer"],
        ),
        (
            "api",
            vec!["REST API endpoints", "API documentation", "OpenAPI spec"],
        ),
        (
            "ui",
            vec!["Frontend components", "User interface design", "Responsive layout"],
        ),
        ("test", vec!["Unit tests", "Integration tests", "E2E tests"]),
        (
            "deploy",
            vec!["Deployment pipeline", "Infrastructure setup", "CI/CD workflow"],
        ),
        (
            "cache",
            vec!["Caching layer", "Cache invalidation strategy", "Redis integration"],
        ),
        (
            "search",
            vec!["Search indexing", "Query optimization", "Full-text search"],
        ),
        (
            "email",
            vec!["Email notification", "SMTP integration", "Template rendering"],
        ),
        (
            "notification",
            vec![
                "Push notification",
                "In-app notification",
                "Notification queue",
            ],
        ),
        (
            "payment",
            vec!["Payment gateway", "Billing logic", "Invoice generation"],
        ),
        (
            "report",
            vec![
                "Reporting engine",
                "Analytics dashboard",
                "Export to CSV/PDF",
            ],
        ),
        (
            "security",
            vec!["Security audit", "Rate limiting", "Input sanitization"],
        ),
        (
            "monitor",
            vec!["Health monitoring", "Alerting rules", "Log aggregation"],
        ),
        (
            "import",
            vec!["Data import", "CSV/JSON parsing", "Validation rules"],
        ),
        ("export", vec!["Data export", "Format conversion", "Download API"]),
        (
            "admin",
            vec!["Admin panel", "Role-based access", "Audit log"],
        ),
    ];

    for (keyword, feats) in keywords {
        if lower.contains(keyword) {
            for feat in feats {
                if !features.contains(&feat.to_string()) {
                    features.push(feat.to_string());
                }
            }
        }
    }

    if features.is_empty() {
        features.push("Core feature implementation".to_string());
    }

    features
}

/// URL-friendly slug.
pub fn slugify(s: &str) -> String {
    s.to_lowercase()
        .replace(|c: char| !c.is_alphanumeric() && c != ' ', "")
        .replace(' ', "-")
        .replace("--", "-")
        .trim_matches('-')
        .to_string()
}