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