pub struct WorkspaceRoot { /* private fields */ }Expand description
The server’s one workspace root, resolved once and read everywhere.
Carries the RESULT of resolution rather than requiring it: a server whose home cannot resolve must still boot (nothing else needs the root), so the failure is held here and surfaces as a terminal refusal at the first dispatch of a placeholder-bearing body.
Implementations§
Source§impl WorkspaceRoot
impl WorkspaceRoot
Sourcepub fn resolve() -> Self
pub fn resolve() -> Self
Resolve the workspace root from the server’s aion home:
crate::config::aion_home → <home>/clones.
This is the ONE derivation of the value. Everything downstream — the declared-body dispatcher, the startup banner, any composition point reading the banner — consumes the resolved value rather than re-deriving it, so two components can never disagree about where workspaces live.
Sourcepub const fn from_resolution(
resolution: Result<PathBuf, WorkspaceRootError>,
) -> Self
pub const fn from_resolution( resolution: Result<PathBuf, WorkspaceRootError>, ) -> Self
Build a root from an already-decided resolution.
For embedders and tests that need a known root (or a known failure)
without touching the process environment the production
WorkspaceRoot::resolve reads. Single derivation is a convention
the production path upholds, not an enforced invariant: nothing stops
a caller constructing a second, disagreeing root here.
The one-line rendering of this root for the startup banner: the
resolved path’s display form, or unresolvable: <reason> when
resolution failed — never a fabricated value.
Sourcepub fn resolved(&self) -> Result<&Path, &WorkspaceRootError>
pub fn resolved(&self) -> Result<&Path, &WorkspaceRootError>
The resolved root, or why there is none.
Read-only: reporting the value (the startup banner) must not create the directory. Creation happens at expansion time, where a failure has a dispatch to refuse.
§Errors
Returns the held WorkspaceRootError when resolution failed.
Sourcepub fn expand(
&self,
command: &str,
) -> Result<Option<ExpandedCommand>, WorkspaceRootError>
pub fn expand( &self, command: &str, ) -> Result<Option<ExpandedCommand>, WorkspaceRootError>
Expand every WORKSPACE_ROOT_PLACEHOLDER occurrence in command
with the resolved root.
A command without the placeholder is untouched — Ok(None), no
resolution requirement, no filesystem side effect — so an unresolved
root never affects a body that does not use it. A command WITH the
placeholder requires the full chain: every occurrence standing alone
as one whole, unquoted argv word, then a resolved, absolute, UTF-8
root with no shape-changing characters, and an existing directory
(created here, idempotently and owner-only 0700, if missing — an
already-existing root keeps whatever permissions the operator gave
it; they are the operator’s own).
§Errors
Returns WorkspaceRootError when a placeholder occurrence is not a
whole unquoted argv word, when the root is unresolved, not absolute,
not valid UTF-8, contains a character that would change the command’s
parsed shape, or does not exist and cannot be created.
Sourcepub fn expand_setting(
&self,
value: &str,
) -> Result<Option<String>, WorkspaceRootError>
pub fn expand_setting( &self, value: &str, ) -> Result<Option<String>, WorkspaceRootError>
Expand every WORKSPACE_ROOT_PLACEHOLDER occurrence in a harness
section’s PATH-VALUED setting — an ACP command, either kind’s cwd, a
Norn binary — with the resolved root.
A value without the placeholder is untouched: Ok(None), no resolution
requirement, no filesystem side effect. A document that names an
absolute path outright is therefore unaffected by an unresolvable root,
exactly as it is unaffected by one today.
The rules that govern WorkspaceRoot::expand’s COMMAND splice are
deliberately NOT applied here, because a setting is not a command:
- No placeholder-placement rule. A command is split into argv words, so
an occurrence glued to other text would splice a fragment of some
larger word. A setting is one whole value that nothing splits, so
{workspace_root}/agentsis the ordinary way to write it. Where the placeholder may stand is the LANGUAGE’s rule, refused ataion_awl::harness_path_form— it must lead the value — and this layer does not restate it. - No shape-changing-character rule, save NUL. Whitespace, braces and
quotes change how a command PARSES; a directory named
/Users/a bis simply a directory, and refusing it here would refuse a legitimate path for a reason that belongs to a different consumer. NUL survives the cut on its own footing:execvecannot carry it.
The ROOT directory is created (idempotently, owner-only 0700) exactly
as the command path creates it, and for the harder reason: a process
cannot be started in a directory that does not exist. Only the root —
a value naming something BENEATH it ({workspace_root}/assistant) is
the document’s claim about a tree that should already be there, and
conjuring an empty one would turn a mistyped path into an agent working
against nothing. The adapter refuses a missing working directory by
name, before it spawns.
§Errors
Returns WorkspaceRootError when the root is unresolved, not
absolute, not valid UTF-8, carries a NUL byte, or does not exist and
cannot be created. Every one of them is terminal — the root is a
property of this box’s configuration and filesystem, so a second attempt
reads the same answer.
Trait Implementations§
Source§impl Clone for WorkspaceRoot
impl Clone for WorkspaceRoot
Source§fn clone(&self) -> WorkspaceRoot
fn clone(&self) -> WorkspaceRoot
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for WorkspaceRoot
impl RefUnwindSafe for WorkspaceRoot
impl Send for WorkspaceRoot
impl Sync for WorkspaceRoot
impl Unpin for WorkspaceRoot
impl UnsafeUnpin for WorkspaceRoot
impl UnwindSafe for WorkspaceRoot
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoMaybeUndefined<T> for T
impl<T> IntoMaybeUndefined<T> for T
Source§fn into_maybe_undefined(self) -> MaybeUndefined<T>
fn into_maybe_undefined(self) -> MaybeUndefined<T>
Source§impl<T> IntoOption<T> for T
impl<T> IntoOption<T> for T
Source§fn into_option(self) -> Option<T>
fn into_option(self) -> Option<T>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request