harn_hostlib/lib.rs
1//! `harn-hostlib`: opt-in host builtins for code intelligence (tree-sitter,
2//! repo scanning, deterministic indexing) and tool execution (search, file
3//! I/O, git, process lifecycle, file watcher).
4//!
5//! This crate is the Rust home of two classes of optional host capabilities:
6//!
7//! 1. **Code intelligence** — `ast/`, `code_index/`, `scanner/`, `fs_watch/`.
8//! 2. **Deterministic tools** — `tools/` (search, fs, git, process).
9//!
10//! These don't belong inside `harn-vm` — pulling tree-sitter grammars,
11//! ripgrep, and `notify` into the VM would balloon the footprint of every
12//! pipeline that doesn't index host code. Instead, this crate exposes a
13//! single [`HostlibCapability`] trait. Embedders such as `harn-cli`'s ACP
14//! server) compose the modules they need via [`HostlibRegistry`] and wire
15//! the resulting builtins into the VM through [`harn_vm::Vm::register_builtin`]
16//! / [`harn_vm::Vm::register_async_builtin`].
17//!
18//! ## Status
19//!
20//! The AST, scanner, code-index, and deterministic-tool surfaces are
21//! implemented. `fs_watch/` still registers its public contract with
22//! [`HostlibError::Unimplemented`] handlers. Module names, method names,
23//! and JSON schemas under `schemas/` are the source of truth for hostlib
24//! request/response compatibility, so they must stay stable while module
25//! bodies evolve.
26
27#![deny(rust_2018_idioms)]
28#![warn(missing_docs)]
29
30#[cfg(feature = "ast")]
31pub mod ast;
32#[cfg(feature = "ast")]
33pub mod code_index;
34#[cfg(feature = "computer")]
35pub mod computer;
36pub mod embed;
37pub mod error;
38pub mod fs;
39pub mod fs_snapshot;
40pub mod fs_watch;
41pub mod host_env_custody;
42pub mod host_lease;
43pub mod host_lease_capability;
44pub mod process;
45mod process_liveness;
46pub mod sandbox;
47pub mod scanner;
48pub mod schemas;
49pub mod secret_store;
50#[cfg(feature = "terminal-session")]
51pub mod terminal_session;
52pub mod tools;
53pub mod verdict;
54
55mod json;
56mod registry;
57mod text;
58mod value_args;
59
60pub use error::HostlibError;
61pub use host_lease::{
62 HostLeaseAcquireReceipt, HostLeaseAcquireStatus, HostLeaseCargoExecutionContext,
63 HostLeaseDeferReason, HostLeaseDeferReceipt, HostLeaseError, HostLeaseExecutionContext,
64 HostLeaseHandle, HostLeaseMetadataUpdateReceipt, HostLeaseOperationKind, HostLeasePathIdentity,
65 HostLeasePriorityClass, HostLeaseProcessExit, HostLeaseReleaseReceipt, HostLeaseRenewReceipt,
66 HostLeaseRequest, HostLeaseResourceClass, HostLeaseResourceDefinition, HostLeaseResourceKey,
67 HostLeaseRunLaunchFailure, HostLeaseRunReceipt, HostLeaseRunReleaseOutcome,
68 HostLeaseRunStartFailure, HostLeaseRunState, HostLeaseState, HostLeaseStore,
69 DEFAULT_HOST_LEASE_DOMAIN, HOST_LEASE_ROOT_ENV,
70};
71pub use registry::{BuiltinRegistry, HostlibCapability, HostlibRegistry, RegisteredBuiltin};
72
73/// Convenience: build a `HostlibRegistry` populated with every capability
74/// the crate ships, register them on the supplied VM, and return the
75/// registry so callers can introspect (e.g. for schema-drift tests).
76///
77/// This is the canonical entry point for embedders that want the full
78/// hostlib surface; pick-and-choose embedders should construct
79/// [`HostlibRegistry`] directly.
80pub fn install_default(vm: &mut harn_vm::Vm) -> HostlibRegistry {
81 let mut registry = HostlibRegistry::new();
82 // The code-intelligence capabilities (`ast` + `code_index`) are only
83 // compiled when the `ast` feature is on. Lean clients that omit it get
84 // the deterministic tool surface without tree-sitter or any grammar.
85 #[cfg(feature = "ast")]
86 {
87 let code_index = code_index::CodeIndexCapability::new();
88 registry = registry
89 .with(ast::AstCapabilityWithCodeIndex::new(code_index.shared()))
90 .with(code_index);
91 }
92 registry = registry
93 .with(scanner::ScannerCapability)
94 .with(embed::EmbedCapability::default())
95 .with(fs::FsCapability)
96 .with(fs_snapshot::FsSnapshotCapability)
97 .with(fs_watch::FsWatchCapability)
98 .with(tools::ToolsCapability)
99 .with(secret_store::SecretStoreCapability)
100 .with(verdict::VerdictCapability)
101 .with(host_lease_capability::HostLeaseCapability);
102 #[cfg(feature = "terminal-session")]
103 {
104 registry = registry.with(terminal_session::TerminalSessionCapability::new());
105 }
106 // Computer use (screenshot + mouse/keyboard) is opt-in at the feature
107 // level AND default-deny at runtime: even with `computer-local` compiled,
108 // the backend is a NullBackend unless `BURIN_COMPUTER_USE_TRANSPORT` is
109 // explicitly set to `local` (or `helper`/`remote`). In the product it is
110 // gated again by an off-by-default setting. Registering the builtins is
111 // therefore harmless when unarmed — every call fails with an explanatory
112 // message until the transport is explicitly chosen.
113 #[cfg(feature = "computer")]
114 {
115 registry = registry.with(computer::ComputerUseCapability::new());
116 }
117 registry.register_into_vm(vm);
118 registry
119}