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