1use std::collections::BTreeMap;
36use std::rc::Rc;
37use std::sync::Arc;
38
39use harn_vm::VmValue;
40
41use crate::error::HostlibError;
42use crate::registry::{BuiltinRegistry, HostlibCapability, RegisteredBuiltin, SyncHandler};
43
44pub(crate) mod args;
45mod cancel_handle;
46mod diagnostics;
47mod file_io;
48mod git;
49mod inspect_test_results;
50mod lang;
51pub mod long_running;
52mod manage_packages;
53mod outline;
54mod payload;
55pub mod permissions;
56mod proc;
57mod read_command_output;
58mod response;
59mod run_build_command;
60mod run_command;
61mod run_test;
62mod search;
63mod test_parsers;
64
65pub use permissions::FEATURE_TOOLS_DETERMINISTIC;
66
67#[derive(Default)]
69pub struct ToolsCapability;
70
71impl HostlibCapability for ToolsCapability {
72 fn module_name(&self) -> &'static str {
73 "tools"
74 }
75
76 fn register_builtins(&self, registry: &mut BuiltinRegistry) {
77 long_running::register_cleanup_hook();
80
81 register_gated(registry, "hostlib_tools_search", "search", search::run);
82 register_gated(
83 registry,
84 "hostlib_tools_read_file",
85 "read_file",
86 file_io::read_file,
87 );
88 register_gated(
89 registry,
90 "hostlib_tools_write_file",
91 "write_file",
92 file_io::write_file,
93 );
94 register_gated(
95 registry,
96 "hostlib_tools_delete_file",
97 "delete_file",
98 file_io::delete_file,
99 );
100 register_gated(
101 registry,
102 "hostlib_tools_list_directory",
103 "list_directory",
104 file_io::list_directory,
105 );
106 register_gated(
107 registry,
108 "hostlib_tools_get_file_outline",
109 "get_file_outline",
110 outline::run,
111 );
112 register_gated(registry, "hostlib_tools_git", "git", git::run);
113
114 register_gated(
115 registry,
116 "hostlib_tools_run_command",
117 "run_command",
118 run_command::handle,
119 );
120 register_gated(
121 registry,
122 read_command_output::NAME,
123 "read_command_output",
124 read_command_output::handle,
125 );
126 register_gated(
127 registry,
128 "hostlib_tools_run_test",
129 "run_test",
130 run_test::handle,
131 );
132 register_gated(
133 registry,
134 "hostlib_tools_run_build_command",
135 "run_build_command",
136 run_build_command::handle,
137 );
138 register_gated(
139 registry,
140 "hostlib_tools_inspect_test_results",
141 "inspect_test_results",
142 inspect_test_results::handle,
143 );
144 register_gated(
145 registry,
146 "hostlib_tools_manage_packages",
147 "manage_packages",
148 manage_packages::handle,
149 );
150 register_gated(
151 registry,
152 cancel_handle::NAME,
153 "cancel_handle",
154 cancel_handle::handle,
155 );
156
157 let handler: SyncHandler = Arc::new(handle_enable);
160 registry.register(RegisteredBuiltin {
161 name: "hostlib_enable",
162 module: "tools",
163 method: "enable",
164 handler,
165 });
166 }
167}
168
169fn register_gated(
172 registry: &mut BuiltinRegistry,
173 name: &'static str,
174 method: &'static str,
175 runner: fn(&[VmValue]) -> Result<VmValue, HostlibError>,
176) {
177 registry.register(RegisteredBuiltin {
178 name,
179 module: "tools",
180 method,
181 handler: permissions::gated_handler(name, runner),
182 });
183}
184
185fn handle_enable(args: &[VmValue]) -> Result<VmValue, HostlibError> {
190 let feature = match args.first() {
191 Some(VmValue::String(s)) => s.to_string(),
192 Some(VmValue::Dict(dict)) => match dict.get("feature") {
193 Some(VmValue::String(s)) => s.to_string(),
194 _ => {
195 return Err(HostlibError::MissingParameter {
196 builtin: "hostlib_enable",
197 param: "feature",
198 });
199 }
200 },
201 _ => {
202 return Err(HostlibError::MissingParameter {
203 builtin: "hostlib_enable",
204 param: "feature",
205 });
206 }
207 };
208
209 match feature.as_str() {
210 permissions::FEATURE_TOOLS_DETERMINISTIC => {
211 let newly_enabled = permissions::enable(&feature);
212 let mut map: BTreeMap<String, VmValue> = BTreeMap::new();
213 map.insert("feature".to_string(), VmValue::String(Rc::from(feature)));
214 map.insert("enabled".to_string(), VmValue::Bool(true));
215 map.insert("newly_enabled".to_string(), VmValue::Bool(newly_enabled));
216 Ok(VmValue::Dict(Rc::new(map)))
217 }
218 other => Err(HostlibError::InvalidParameter {
219 builtin: "hostlib_enable",
220 param: "feature",
221 message: format!("unknown feature `{other}`; supported: [`tools:deterministic`]"),
222 }),
223 }
224}