(
template: &str,
worktree: &std::path::Path,
known_agents: &[String],
)
| 2613 | const FILE_REFERENCE_REGEX: &str = r"(?:^|([^\w`]))@(\.?[^\s`,.]*(?:\.[^\s`,.]+)*)"; |
| 2614 | |
| 2615 | pub async fn resolve_prompt_parts( |
| 2616 | template: &str, |
| 2617 | worktree: &std::path::Path, |
| 2618 | known_agents: &[String], |
| 2619 | ) -> Vec<PartInput> { |
| 2620 | let mut parts = vec![PartInput::Text { |
| 2621 | text: template.to_string(), |
| 2622 | }]; |
| 2623 | |
| 2624 | let re = regex::Regex::new(FILE_REFERENCE_REGEX).unwrap(); |
| 2625 | let mut seen = std::collections::HashSet::new(); |
| 2626 | |
| 2627 | for cap in re.captures_iter(template) { |
| 2628 | // Group 1 is the preceding char — if it matched a word char or backtick |
| 2629 | // the overall pattern wouldn't match (they're excluded by [^\w`]). |
| 2630 | // Group 2 is the actual reference name. |
| 2631 | if let Some(name) = cap.get(2) { |
| 2632 | let name = name.as_str(); |
| 2633 | if name.is_empty() || seen.contains(name) { |
| 2634 | continue; |
| 2635 | } |
| 2636 | seen.insert(name.to_string()); |
| 2637 | |
| 2638 | let filepath = if name.starts_with("~/") { |
| 2639 | if let Some(home) = dirs::home_dir() { |
| 2640 | home.join(&name[2..]) |
| 2641 | } else { |
| 2642 | continue; |
| 2643 | } |
| 2644 | } else { |
| 2645 | worktree.join(name) |
| 2646 | }; |
| 2647 | |
| 2648 | if let Ok(metadata) = tokio::fs::metadata(&filepath).await { |
| 2649 | let url = format!("file://{}", filepath.display()); |
| 2650 | |
| 2651 | if metadata.is_dir() { |
| 2652 | parts.push(PartInput::File { |
| 2653 | url, |
| 2654 | filename: Some(name.to_string()), |
| 2655 | mime: Some("application/x-directory".to_string()), |
| 2656 | }); |
| 2657 | } else { |
| 2658 | parts.push(PartInput::File { |
| 2659 | url, |
| 2660 | filename: Some(name.to_string()), |
| 2661 | mime: Some("text/plain".to_string()), |
| 2662 | }); |
| 2663 | } |
| 2664 | } else if known_agents.iter().any(|a| a == name) { |
| 2665 | // Not a file — check if it's a known agent name |
| 2666 | parts.push(PartInput::Agent { |
| 2667 | name: name.to_string(), |
| 2668 | }); |
| 2669 | } |
| 2670 | } |
| 2671 | } |
| 2672 |
no test coverage detected