mdx_rust_analysis/
bundler.rs1use crate::finders::{
8 find_preambles, find_tools, looks_like_rig_agent, ExtractedPrompt, ExtractedTool,
9};
10use ignore::WalkBuilder;
11use std::fs;
12use std::path::{Path, PathBuf};
13
14#[derive(Debug, Clone, Default)]
16pub struct BundleScope {
17 pub optimizable_paths: Vec<PathBuf>,
18 pub read_only_paths: Vec<PathBuf>,
19}
20
21#[derive(Debug, Clone, Default)]
24pub struct AgentBundle {
25 pub scope: BundleScope,
26 pub preambles: Vec<ExtractedPrompt>,
27 pub tools: Vec<ExtractedTool>,
28 pub is_rig_agent: bool,
29 pub key_files: Vec<PathBuf>, }
31
32pub fn build_bundle_scope(
34 root: &Path,
35 custom_ignore_file: Option<&Path>,
36) -> anyhow::Result<BundleScope> {
37 let mut walker = WalkBuilder::new(root);
38
39 walker.git_ignore(true);
40 walker.git_global(true);
41 walker.git_exclude(true);
42
43 if let Some(ignore_path) = custom_ignore_file {
44 if ignore_path.exists() {
45 walker.add_ignore(ignore_path);
46 }
47 } else {
48 let default_ignore = root.join(".mdx-rust/.mdx-rustignore");
49 if default_ignore.exists() {
50 walker.add_ignore(default_ignore);
51 }
52 }
53
54 walker.require_git(false);
55
56 let mut optimizable = Vec::new();
57
58 for entry in walker.build() {
59 let entry = entry?;
60 let path = entry.path();
61
62 if path.is_file() {
63 optimizable.push(path.to_path_buf());
64 }
65 }
66
67 Ok(BundleScope {
68 optimizable_paths: optimizable,
69 read_only_paths: vec![],
70 })
71}
72
73pub fn analyze_agent(root: &Path, custom_ignore: Option<&Path>) -> anyhow::Result<AgentBundle> {
75 let scope = build_bundle_scope(root, custom_ignore)?;
76 let mut bundle = AgentBundle {
77 scope,
78 ..Default::default()
79 };
80
81 let candidates: Vec<_> = bundle
83 .scope
84 .optimizable_paths
85 .iter()
86 .filter(|p| p.extension().is_some_and(|e| e == "rs"))
87 .take(12)
88 .cloned()
89 .collect();
90
91 for path in &candidates {
92 if let Ok(source) = fs::read_to_string(path) {
93 if looks_like_rig_agent(&source) {
94 bundle.is_rig_agent = true;
95
96 let mut ps = find_preambles(&source, path);
98 bundle.preambles.append(&mut ps);
99
100 let mut ts = find_tools(&source, path);
102 bundle.tools.append(&mut ts);
103
104 if bundle.key_files.len() < 4 {
106 bundle.key_files.push(path.clone());
107 }
108 }
109 }
110 }
111
112 if bundle.key_files.is_empty() {
114 for p in candidates.iter().take(3) {
115 bundle.key_files.push(p.clone());
116 }
117 }
118
119 Ok(bundle)
120}