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