harn_hostlib/tools/
mod.rs1use harn_vm::VmDictExt;
38
39use harn_vm::VmValue;
40
41use crate::error::HostlibError;
42use crate::registry::{BuiltinRegistry, HostlibCapability};
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;
61pub(crate) use run_command::policy_blocked_response as policy_blocked_run_command_response;
62pub(crate) use run_command::request_is_background as run_command_request_is_background;
63mod run_test;
64mod search;
65mod test_parsers;
66mod toolchain_facts;
67mod wait_command;
68
69pub use permissions::{FEATURE_TERMINAL_SESSION, FEATURE_TOOLS_DETERMINISTIC};
70
71#[derive(Default)]
73pub struct ToolsCapability;
74
75impl HostlibCapability for ToolsCapability {
76 fn module_name(&self) -> &'static str {
77 "tools"
78 }
79
80 fn register_builtins(&self, registry: &mut BuiltinRegistry) {
81 long_running::register_cleanup_hook();
84
85 registry.register_gated_fn("tools", "hostlib_tools_search", "search", search::run);
86 registry.register_gated_fn(
87 "tools",
88 "hostlib_tools_read_file",
89 "read_file",
90 file_io::read_file,
91 );
92 registry.register_gated_fn(
93 "tools",
94 "hostlib_tools_write_file",
95 "write_file",
96 file_io::write_file,
97 );
98 registry.register_gated_fn(
99 "tools",
100 "hostlib_tools_delete_file",
101 "delete_file",
102 file_io::delete_file,
103 );
104 registry.register_gated_fn(
105 "tools",
106 "hostlib_tools_list_directory",
107 "list_directory",
108 file_io::list_directory,
109 );
110 registry.register_gated_fn(
111 "tools",
112 "hostlib_tools_get_file_outline",
113 "get_file_outline",
114 outline::run,
115 );
116 registry.register_gated_fn("tools", "hostlib_tools_git", "git", git::run);
117
118 registry.register_gated_command_fn(
119 "tools",
120 "hostlib_tools_run_command",
121 "run_command",
122 run_command::handle,
123 );
124 registry.register_gated_fn(
125 "tools",
126 read_command_output::NAME,
127 "read_command_output",
128 read_command_output::handle,
129 );
130 registry.register_gated_fn(
131 "tools",
132 wait_command::NAME,
133 "wait_command",
134 wait_command::handle,
135 );
136 registry.register_gated_fn(
137 "tools",
138 "hostlib_tools_run_test",
139 "run_test",
140 run_test::handle,
141 );
142 registry.register_gated_fn(
143 "tools",
144 "hostlib_tools_run_build_command",
145 "run_build_command",
146 run_build_command::handle,
147 );
148 registry.register_gated_fn(
149 "tools",
150 "hostlib_tools_inspect_test_results",
151 "inspect_test_results",
152 inspect_test_results::handle,
153 );
154 registry.register_gated_fn(
155 "tools",
156 "hostlib_tools_manage_packages",
157 "manage_packages",
158 manage_packages::handle,
159 );
160 registry.register_gated_fn(
161 "tools",
162 cancel_handle::NAME,
163 "cancel_handle",
164 cancel_handle::handle,
165 );
166 registry.register_gated_fn(
167 "tools",
168 toolchain_facts::NAME,
169 "toolchain_facts",
170 toolchain_facts::handle,
171 );
172
173 registry.register_fn("tools", "hostlib_enable", "enable", handle_enable);
176 }
177}
178
179fn handle_enable(args: &[VmValue]) -> Result<VmValue, HostlibError> {
184 let feature = match args.first() {
185 Some(VmValue::String(s)) => s.to_string(),
186 Some(VmValue::Dict(dict)) => match dict.get("feature") {
187 Some(VmValue::String(s)) => s.to_string(),
188 _ => {
189 return Err(HostlibError::MissingParameter {
190 builtin: "hostlib_enable",
191 param: "feature",
192 });
193 }
194 },
195 _ => {
196 return Err(HostlibError::MissingParameter {
197 builtin: "hostlib_enable",
198 param: "feature",
199 });
200 }
201 };
202
203 let supported = feature == permissions::FEATURE_TOOLS_DETERMINISTIC
204 || cfg!(feature = "terminal-session") && feature == permissions::FEATURE_TERMINAL_SESSION;
205 if !supported {
206 return Err(HostlibError::InvalidParameter {
207 builtin: "hostlib_enable",
208 param: "feature",
209 message: format!(
210 "unknown feature `{feature}`; supported: [`tools:deterministic`{}]",
211 if cfg!(feature = "terminal-session") {
212 ", `terminal:session`"
213 } else {
214 ""
215 }
216 ),
217 });
218 }
219
220 let newly_enabled = permissions::enable(&feature);
221 let mut map: harn_vm::value::DictMap = harn_vm::value::DictMap::new();
222 map.put_str("feature", feature);
223 map.insert(harn_vm::value::intern_key("enabled"), VmValue::Bool(true));
224 map.insert(
225 harn_vm::value::intern_key("newly_enabled"),
226 VmValue::Bool(newly_enabled),
227 );
228 Ok(VmValue::dict(map))
229}