#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub use agent_bridle_core::*;
#[cfg(any(feature = "shell", feature = "carried-coreutils"))]
pub use agent_bridle_tool_shell::ShellTool;
#[cfg(any(feature = "shell", feature = "host-shell", feature = "brush"))]
pub use agent_bridle_tool_shell::{ShellInvocationId, ShellOutputObserver, ShellOutputStream};
#[cfg(feature = "host-shell")]
pub use agent_bridle_tool_shell::HostShellTool;
#[cfg(feature = "brush")]
pub use agent_bridle_tool_shell::{brush_private_control_supported, BrushShellTool};
#[cfg(feature = "brush")]
pub use agent_bridle_tool_shell::{
inspect_shell, DescendantExec, InspectedCommand, InspectedConstruct, InspectedRedirect,
RedirectOperation, ShellConstructKind, ShellInspection, ShellInspectionError,
};
#[cfg(feature = "brush")]
pub use agent_bridle_tool_shell::maybe_dispatch;
#[cfg(feature = "carried-coreutils")]
pub use agent_bridle_tool_shell::{install_default_providers, register_shims};
#[cfg(feature = "web")]
pub use agent_bridle_tool_web::WebFetchTool;
#[must_use]
pub fn registry() -> Registry {
#[allow(unused_mut)]
let mut builder = Registry::builder();
#[cfg(feature = "carried-coreutils")]
{
if brush_private_control_supported() {
builder = builder.tool(std::sync::Arc::new(BrushShellTool::new()));
} else {
builder = builder.tool(std::sync::Arc::new(ShellTool::new()));
}
}
#[cfg(all(feature = "shell", not(feature = "carried-coreutils")))]
{
builder = builder.tool(std::sync::Arc::new(ShellTool::new()));
}
#[cfg(feature = "web")]
{
builder = builder.tool(std::sync::Arc::new(WebFetchTool::new()));
}
builder.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(any(feature = "shell", feature = "carried-coreutils"))]
#[test]
fn shell_tool_is_present_with_feature() {
let reg = registry();
assert!(
reg.contains("shell"),
"expected `shell` tool to be registered"
);
let names = reg.tool_names();
assert!(
names.contains(&"shell"),
"tool_names missing shell: {names:?}"
);
}
#[cfg(all(
feature = "carried-coreutils",
any(target_os = "linux", target_os = "macos")
))]
#[test]
fn default_shell_is_the_carried_brush_engine() {
let reg = registry();
let shell = reg
.tool_definitions()
.into_iter()
.find(|definition| definition["name"] == "shell")
.expect("carried shell present");
let properties = shell["inputSchema"]["properties"]
.as_object()
.expect("shell schema properties");
assert!(properties.contains_key("cmd"), "Brush schema needs `cmd`");
assert!(
!properties.contains_key("program"),
"default registry must not select the argv safe-subset engine"
);
}
#[cfg(all(
feature = "carried-coreutils",
not(any(target_os = "linux", target_os = "macos"))
))]
#[test]
fn default_shell_falls_back_to_safe_subset_when_private_control_is_unsupported() {
assert!(!brush_private_control_supported());
let reg = registry();
let shell = reg
.tool_definitions()
.into_iter()
.find(|definition| definition["name"] == "shell")
.expect("safe-subset shell present");
let properties = shell["inputSchema"]["properties"]
.as_object()
.expect("shell schema properties");
assert!(
properties.contains_key("program"),
"fallback schema must disclose the argv safe-subset engine"
);
}
#[cfg(feature = "brush")]
#[test]
fn private_control_probe_matches_the_compiled_transport() {
assert_eq!(
brush_private_control_supported(),
cfg!(any(target_os = "linux", target_os = "macos"))
);
}
#[cfg(not(any(feature = "shell", feature = "carried-coreutils")))]
#[test]
fn shell_tool_absent_without_feature() {
let reg = registry();
assert!(!reg.contains("shell"));
}
#[cfg(feature = "web")]
#[test]
fn web_fetch_tool_is_present_with_feature() {
let reg = registry();
assert!(
reg.contains("web_fetch"),
"expected `web_fetch` tool to be registered"
);
assert!(
reg.tool_names().contains(&"web_fetch"),
"tool_names missing web_fetch: {:?}",
reg.tool_names()
);
}
#[cfg(not(feature = "web"))]
#[test]
fn web_fetch_tool_absent_without_feature() {
let reg = registry();
assert!(!reg.contains("web_fetch"));
}
#[cfg(all(
not(feature = "shell"),
not(feature = "carried-coreutils"),
not(feature = "web")
))]
#[test]
fn registry_is_empty_with_no_tool_features() {
let reg = registry();
assert!(reg.tool_names().is_empty());
}
#[test]
fn leash_types_are_reexported() {
let _c = Caveats::top();
let _s: Scope<String> = Scope::top();
let _b = CountBound::Unlimited;
let _k = SandboxKind::None;
}
#[cfg(feature = "verifier-webauthn")]
#[test]
fn webauthn_verifier_is_reexported() {
let _ = WebAuthnVerifier;
}
#[cfg(feature = "verifier-webauthn-es256")]
#[test]
fn webauthn_es256_verifier_is_reexported() {
let _ = WebAuthnEs256Verifier;
}
#[cfg(feature = "brush")]
#[test]
fn brush_inspection_is_reexported_for_preflight() {
let inspected: ShellInspection =
inspect_shell(r#"echo "$(printf '%s' "$((1 + 2))")""#).expect("inspection");
let substitution: &InspectedConstruct = &inspected.constructs[0];
assert_eq!(substitution.kind, ShellConstructKind::CommandSubstitution);
assert!(substitution.quoted);
let nested = substitution
.inspection
.as_deref()
.expect("recursive substitution inspection");
assert_eq!(
nested.constructs[0].kind,
ShellConstructKind::ArithmeticExpansion
);
assert_eq!(nested.constructs[0].body, "1 + 2");
let error = inspect_shell("echo $((runtime_value))")
.expect_err("runtime-state arithmetic must fail closed through the facade");
assert!(error.message().contains("runtime shell state"));
}
}