warble_claude_code/emit/
resolution.rs1use crate::error::DispatchError;
6use crate::ir::ComponentNode;
7use crate::resolve::{resolve_capabilities, ResolutionReport};
8use crate::targets::{is_known_target, known_target_names, TargetId};
9
10fn format_summary_line(entry: &crate::resolve::ResolvedCapability) -> String {
13 let outcome = serde_json::to_value(entry.outcome)
14 .ok()
15 .and_then(|v| v.as_str().map(str::to_string))
16 .unwrap_or_default();
17 let provided = serde_json::to_value(entry.provided_by)
18 .ok()
19 .and_then(|v| v.as_str().map(str::to_string))
20 .unwrap_or_default();
21 let criticality = serde_json::to_value(entry.criticality)
22 .ok()
23 .and_then(|v| v.as_str().map(str::to_string))
24 .unwrap_or_default();
25 let suffix = entry
26 .note
27 .as_ref()
28 .map(|n| format!(" — {n}"))
29 .unwrap_or_default();
30 format!(
31 " {:<28} {:<12} ({provided}, {criticality}){suffix}",
32 entry.capability, outcome
33 )
34}
35
36pub(super) fn print_resolution_summary(target_label: &str, report: &ResolutionReport) {
37 eprintln!("warble-dispatch: capability resolution for target '{target_label}':");
38 for entry in report {
39 eprintln!("{}", format_summary_line(entry));
40 }
41}
42
43pub fn resolve_node_capabilities(
46 node: &ComponentNode,
47 target_id: &str,
48) -> Result<ResolutionReport, DispatchError> {
49 if !is_known_target(target_id) {
50 return Err(DispatchError(format!(
51 "target '{target_id}' has no capability profile (known targets: {})",
52 known_target_names().join(", ")
53 )));
54 }
55 let profile = TargetId::parse(target_id)
56 .expect("known target parses")
57 .profile();
58 resolve_capabilities(node, target_id, &profile)
59}
60
61pub(super) fn resolve_node_with_shared_binding(
69 node: &ComponentNode,
70 top: &crate::ir::ContextBinding,
71 target_id: &str,
72 profile: &crate::targets::CapabilityProfile,
73) -> Result<ResolutionReport, DispatchError> {
74 if node.context_binding.resolved.is_some() || top.resolved.is_none() {
75 return crate::resolve::resolve_capabilities(node, target_id, profile);
76 }
77 let mut hydrated = node.clone();
78 hydrated.context_binding.resolved = top.resolved.clone();
79 crate::resolve::resolve_capabilities(&hydrated, target_id, profile)
80}