Skip to main content

albert_compat/
lib.rs

1use std::fs;
2use std::path::{Path, PathBuf};
3
4use commands::{CommandManifestEntry, CommandRegistry, CommandSource};
5use runtime::{BootstrapPhase, BootstrapPlan};
6use tools::{ToolManifestEntry, ToolRegistry, ToolSource};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct UpstreamPaths {
10    repo_root: PathBuf,
11}
12
13impl UpstreamPaths {
14    #[must_use]
15    pub fn from_repo_root(repo_root: impl Into<PathBuf>) -> Self {
16        Self {
17            repo_root: repo_root.into(),
18        }
19    }
20
21    #[must_use]
22    pub fn from_workspace_dir(workspace_dir: impl AsRef<Path>) -> Self {
23        let workspace_dir = workspace_dir
24            .as_ref()
25            .canonicalize()
26            .unwrap_or_else(|_| workspace_dir.as_ref().to_path_buf());
27        let primary_repo_root = workspace_dir
28            .parent()
29            .map_or_else(|| PathBuf::from(".."), Path::to_path_buf);
30        let repo_root = resolve_upstream_repo_root(&primary_repo_root);
31        Self { repo_root }
32    }
33
34    #[must_use]
35    pub fn commands_path(&self) -> PathBuf {
36        self.repo_root.join("src/commands.ts")
37    }
38
39    #[must_use]
40    pub fn tools_path(&self) -> PathBuf {
41        self.repo_root.join("src/tools.ts")
42    }
43
44    #[must_use]
45    pub fn cli_path(&self) -> PathBuf {
46        self.repo_root.join("src/entrypoints/cli.tsx")
47    }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct ExtractedManifest {
52    pub commands: CommandRegistry,
53    pub tools: ToolRegistry,
54    pub bootstrap: BootstrapPlan,
55}
56
57fn resolve_upstream_repo_root(primary_repo_root: &Path) -> PathBuf {
58    let candidates = upstream_repo_candidates(primary_repo_root);
59    candidates
60        .into_iter()
61        .find(|candidate| candidate.join("src/commands.ts").is_file())
62        .unwrap_or_else(|| primary_repo_root.to_path_buf())
63}
64
65fn upstream_repo_candidates(primary_repo_root: &Path) -> Vec<PathBuf> {
66    let mut candidates = vec![primary_repo_root.to_path_buf()];
67
68    if let Some(explicit) = std::env::var_os("CLAUDE_CODE_UPSTREAM") {
69        candidates.push(PathBuf::from(explicit));
70    }
71
72    for ancestor in primary_repo_root.ancestors().take(4) {
73        candidates.push(ancestor.join("claw-code"));
74        candidates.push(ancestor.join("clawd-code"));
75    }
76
77    candidates.push(
78        primary_repo_root
79            .join("reference-source")
80            .join("claw-code"),
81    );
82    candidates.push(primary_repo_root.join("vendor").join("claw-code"));
83
84    let mut deduped = Vec::new();
85    for candidate in candidates {
86        if !deduped.iter().any(|seen: &PathBuf| seen == &candidate) {
87            deduped.push(candidate);
88        }
89    }
90    deduped
91}
92
93pub fn extract_manifest(paths: &UpstreamPaths) -> std::io::Result<ExtractedManifest> {
94    let commands_source = fs::read_to_string(paths.commands_path())?;
95    let tools_source = fs::read_to_string(paths.tools_path())?;
96    let cli_source = fs::read_to_string(paths.cli_path())?;
97
98    Ok(ExtractedManifest {
99        commands: extract_commands(&commands_source),
100        tools: extract_tools(&tools_source),
101        bootstrap: extract_bootstrap_plan(&cli_source),
102    })
103}
104
105#[must_use]
106pub fn extract_commands(source: &str) -> CommandRegistry {
107    let mut entries = Vec::new();
108    let mut in_internal_block = false;
109
110    for raw_line in source.lines() {
111        let line = raw_line.trim();
112
113        if line.starts_with("export const INTERNAL_ONLY_COMMANDS = [") {
114            in_internal_block = true;
115            continue;
116        }
117
118        if in_internal_block {
119            if line.starts_with(']') {
120                in_internal_block = false;
121                continue;
122            }
123            if let Some(name) = first_identifier(line) {
124                entries.push(CommandManifestEntry {
125                    name,
126                    source: CommandSource::InternalOnly,
127                });
128            }
129            continue;
130        }
131
132        if line.starts_with("import ") {
133            for imported in imported_symbols(line) {
134                entries.push(CommandManifestEntry {
135                    name: imported,
136                    source: CommandSource::Builtin,
137                });
138            }
139        }
140
141        if line.contains("feature('") && line.contains("./commands/") {
142            if let Some(name) = first_assignment_identifier(line) {
143                entries.push(CommandManifestEntry {
144                    name,
145                    source: CommandSource::FeatureGated,
146                });
147            }
148        }
149    }
150
151    dedupe_commands(entries)
152}
153
154#[must_use]
155pub fn extract_tools(source: &str) -> ToolRegistry {
156    let mut entries = Vec::new();
157
158    for raw_line in source.lines() {
159        let line = raw_line.trim();
160        if line.starts_with("import ") && line.contains("./tools/") {
161            for imported in imported_symbols(line) {
162                if imported.ends_with("Tool") {
163                    entries.push(ToolManifestEntry {
164                        name: imported,
165                        source: ToolSource::Base,
166                    });
167                }
168            }
169        }
170
171        if line.contains("feature('") && line.contains("Tool") {
172            if let Some(name) = first_assignment_identifier(line) {
173                if name.ends_with("Tool") || name.ends_with("Tools") {
174                    entries.push(ToolManifestEntry {
175                        name,
176                        source: ToolSource::Conditional,
177                    });
178                }
179            }
180        }
181    }
182
183    dedupe_tools(entries)
184}
185
186#[must_use]
187pub fn extract_bootstrap_plan(source: &str) -> BootstrapPlan {
188    let mut phases = vec![BootstrapPhase::CliEntry];
189
190    if source.contains("--version") {
191        phases.push(BootstrapPhase::FastPathVersion);
192    }
193    if source.contains("startupProfiler") {
194        phases.push(BootstrapPhase::StartupProfiler);
195    }
196    if source.contains("--dump-system-prompt") {
197        phases.push(BootstrapPhase::SystemPromptFastPath);
198    }
199    if source.contains("--ternlang-in-chrome-mcp") {
200        phases.push(BootstrapPhase::ChromeMcpFastPath);
201    }
202    if source.contains("--daemon-worker") {
203        phases.push(BootstrapPhase::DaemonWorkerFastPath);
204    }
205    if source.contains("remote-control") {
206        phases.push(BootstrapPhase::BridgeFastPath);
207    }
208    if source.contains("args[0] === 'daemon'") {
209        phases.push(BootstrapPhase::DaemonFastPath);
210    }
211    if source.contains("args[0] === 'ps'") || source.contains("args.includes('--bg')") {
212        phases.push(BootstrapPhase::BackgroundSessionFastPath);
213    }
214    if source.contains("args[0] === 'new' || args[0] === 'list' || args[0] === 'reply'") {
215        phases.push(BootstrapPhase::TemplateFastPath);
216    }
217    if source.contains("environment-runner") {
218        phases.push(BootstrapPhase::EnvironmentRunnerFastPath);
219    }
220    phases.push(BootstrapPhase::MainRuntime);
221
222    BootstrapPlan::from_phases(phases)
223}
224
225fn imported_symbols(line: &str) -> Vec<String> {
226    let Some(after_import) = line.strip_prefix("import ") else {
227        return Vec::new();
228    };
229
230    let before_from = after_import
231        .split(" from ")
232        .next()
233        .unwrap_or_default()
234        .trim();
235    if before_from.starts_with('{') {
236        return before_from
237            .trim_matches(|c| c == '{' || c == '}')
238            .split(',')
239            .filter_map(|part| {
240                let trimmed = part.trim();
241                if trimmed.is_empty() {
242                    return None;
243                }
244                Some(trimmed.split_whitespace().next()?.to_string())
245            })
246            .collect();
247    }
248
249    let first = before_from.split(',').next().unwrap_or_default().trim();
250    if first.is_empty() {
251        Vec::new()
252    } else {
253        vec![first.to_string()]
254    }
255}
256
257fn first_assignment_identifier(line: &str) -> Option<String> {
258    let trimmed = line.trim_start();
259    let candidate = trimmed.split('=').next()?.trim();
260    first_identifier(candidate)
261}
262
263fn first_identifier(line: &str) -> Option<String> {
264    let mut out = String::new();
265    for ch in line.chars() {
266        if ch.is_ascii_alphanumeric() || ch == '_' || ch == '-' {
267            out.push(ch);
268        } else if !out.is_empty() {
269            break;
270        }
271    }
272    (!out.is_empty()).then_some(out)
273}
274
275fn dedupe_commands(entries: Vec<CommandManifestEntry>) -> CommandRegistry {
276    let mut deduped = Vec::new();
277    for entry in entries {
278        let exists = deduped.iter().any(|seen: &CommandManifestEntry| {
279            seen.name == entry.name && seen.source == entry.source
280        });
281        if !exists {
282            deduped.push(entry);
283        }
284    }
285    CommandRegistry::new(deduped)
286}
287
288fn dedupe_tools(entries: Vec<ToolManifestEntry>) -> ToolRegistry {
289    let mut deduped = Vec::new();
290    for entry in entries {
291        let exists = deduped
292            .iter()
293            .any(|seen: &ToolManifestEntry| seen.name == entry.name && seen.source == entry.source);
294        if !exists {
295            deduped.push(entry);
296        }
297    }
298    ToolRegistry::new(deduped)
299}
300
301#[cfg(test)]
302mod tests {
303    use super::*;
304
305    fn fixture_paths() -> UpstreamPaths {
306        let workspace_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
307        UpstreamPaths::from_workspace_dir(workspace_dir)
308    }
309
310    fn has_upstream_fixture(paths: &UpstreamPaths) -> bool {
311        paths.commands_path().is_file()
312            && paths.tools_path().is_file()
313            && paths.cli_path().is_file()
314    }
315
316    #[test]
317    fn extracts_non_empty_manifests_from_upstream_repo() {
318        let paths = fixture_paths();
319        if !has_upstream_fixture(&paths) {
320            return;
321        }
322        let manifest = extract_manifest(&paths).expect("manifest should load");
323        assert!(!manifest.commands.entries().is_empty());
324        assert!(!manifest.tools.entries().is_empty());
325        assert!(!manifest.bootstrap.phases().is_empty());
326    }
327
328    #[test]
329    fn detects_known_upstream_command_symbols() {
330        let paths = fixture_paths();
331        if !paths.commands_path().is_file() {
332            return;
333        }
334        let commands =
335            extract_commands(&fs::read_to_string(paths.commands_path()).expect("commands.ts"));
336        let names: Vec<_> = commands
337            .entries()
338            .iter()
339            .map(|entry| entry.name.as_str())
340            .collect();
341        assert!(names.contains(&"addDir"));
342        assert!(names.contains(&"review"));
343        assert!(!names.contains(&"INTERNAL_ONLY_COMMANDS"));
344    }
345
346    #[test]
347    fn detects_known_upstream_tool_symbols() {
348        let paths = fixture_paths();
349        if !paths.tools_path().is_file() {
350            return;
351        }
352        let tools = extract_tools(&fs::read_to_string(paths.tools_path()).expect("tools.ts"));
353        let names: Vec<_> = tools
354            .entries()
355            .iter()
356            .map(|entry| entry.name.as_str())
357            .collect();
358        assert!(names.contains(&"AgentTool"));
359        assert!(names.contains(&"BashTool"));
360    }
361}