Skip to content

Commit 079246f

Browse files
feat(Common): Implement abstract core architecture with traits and effects
This commit establishes the entire abstract core of the Land project as defined in the final architecture. It includes: 1. **Effect System**: Added `ActionEffect` struct and `ApplicationRunTime` trait for declarative effect handling 2. **Environment**: Implemented `Environment`, `HasEnvironment`, and `Requires` traits for capability-based dependency injection 3. **Service Contracts**: Defined traits for all 20+ services (Command, Configuration, Document, FileSystem, IPC, etc.) with: - Abstract service traits (e.g., `CommandExecutor`, `DocumentProvider`) - Data Transfer Objects (DTOs) for cross-boundary communication - `ActionEffect` constructors for all operations 4. **Error Handling**: Added comprehensive `CommonError` enum with IO, configuration, and service-specific variants These changes create the architectural foundation for: - The `Mountain` backend to implement Rust-native service handlers - The `Cocoon` sidecar to communicate via gRPC using these contracts - The `Wind`/`Sky` UI layer to execute effects via Tauri commands The implementation enables type-safe, declarative programming across the entire stack using the effects-based paradigm.
1 parent 10aa053 commit 079246f

File tree

152 files changed

+6038
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+6038
-1
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ response to any behavior that they deem inappropriate, threatening, offensive,
4747
or harmful. Community leaders have the right and responsibility to remove, edit,
4848
or reject comments, commits, code, wiki edits, issues, and other contributions
4949
that are not aligned with this Code of Conduct, and will communicate reasons for
50-
moderation decisions when appropriate.
50+
pub moderation decisions when appropriate.
5151

5252
## Scope
5353

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ toml = { version = "0.8.20" }
66
async-trait = { workspace = true }
77
serde = { workspace = true }
88
serde_json = { workspace = true }
9+
thiserror.workspace = true
910
url = { workspace = true }
1011

1112

Source/Command/CommandExecutor.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! # CommandExecutor Trait
2+
//!
3+
//! Defines the abstract service trait for command management and execution
4+
//! capabilities.
5+
6+
use async_trait::async_trait;
7+
use serde_json::Value;
8+
9+
use crate::{Environment::Environment::Environment, Error::CommonError::CommonError};
10+
11+
/// An abstract service contract for an environment component that can execute
12+
/// and manage commands within the application.
13+
///
14+
/// This trait is implemented by the concrete `MountainEnvironment` and provides
15+
/// the core logic for the command palette and programmatic command execution.
16+
/// It is designed to handle both native commands implemented in Rust and
17+
/// proxied commands implemented in external sidecars.
18+
#[async_trait]
19+
pub trait CommandExecutor: Environment + Send + Sync {
20+
/// Executes a command with the given identifier and arguments.
21+
///
22+
/// # Parameters
23+
///
24+
/// * `CommandIdentifier`: The unique ID of the command to execute.
25+
/// * `Argument`: A `serde_json::Value` containing the arguments for the
26+
/// command.
27+
///
28+
/// # Returns
29+
///
30+
/// A `Result` containing the command's return value as a
31+
/// `serde_json::Value` on success, or a `CommonError` on failure.
32+
async fn ExecuteCommand(&self, CommandIdentifier:String, Argument:Value) -> Result<Value, CommonError>;
33+
34+
/// Registers a command that is implemented in an external sidecar process.
35+
///
36+
/// # Parameters
37+
///
38+
/// * `SidecarIdentifier`: The unique ID of the sidecar where the command
39+
/// logic resides.
40+
/// * `CommandIdentifier`: The unique ID of the command being registered.
41+
async fn RegisterCommand(&self, SidecarIdentifier:String, CommandIdentifier:String) -> Result<(), CommonError>;
42+
43+
/// Unregisters a previously registered command.
44+
async fn UnregisterCommand(&self, SidecarIdentifier:String, CommandIdentifier:String) -> Result<(), CommonError>;
45+
46+
/// Retrieves a list of all currently registered command identifiers.
47+
async fn GetAllCommands(&self) -> Result<Vec<String>, CommonError>;
48+
}

Source/Command/ExecuteCommand.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//! # ExecuteCommand Effect
2+
//!
3+
//! Defines the `ActionEffect` for executing a registered command.
4+
5+
use std::sync::Arc;
6+
7+
use serde_json::Value;
8+
9+
use super::CommandExecutor::CommandExecutor;
10+
use crate::{
11+
Effect::{ActionEffect::ActionEffect, ApplicationRunTime::ApplicationRunTime},
12+
Environment::Requires::Requires,
13+
Error::CommonError::CommonError,
14+
};
15+
16+
/// Creates an effect that, when executed, will run a command by its unique
17+
/// identifier.
18+
///
19+
/// It uses the `CommandExecutor` capability from the environment to dispatch
20+
/// the command to the appropriate handler, whether that handler is a native
21+
22+
/// Rust function or a proxied function in an external sidecar process.
23+
///
24+
/// # Parameters
25+
///
26+
/// * `CommandIdentifier`: The unique ID of the command to execute (e.g.,
27+
/// "FileSystem.ReadFile").
28+
/// * `Argument`: A `serde_json::Value` containing the arguments for the
29+
/// command.
30+
///
31+
/// # Returns
32+
///
33+
/// An `ActionEffect` that resolves with the command's return value as a
34+
/// `serde_json::Value`, or a `CommonError` if the command is not found or fails
35+
/// during execution.
36+
pub fn ExecuteCommand<TRunTime>(
37+
CommandIdentifier:String,
38+
Argument:Value,
39+
) -> ActionEffect<Arc<TRunTime>, CommonError, Value>
40+
where
41+
TRunTime: ApplicationRunTime + Send + Sync + 'static,
42+
TRunTime::EnvironmentType: Requires<Arc<dyn CommandExecutor>>, {
43+
ActionEffect::New(Arc::new(move |RunTime:Arc<TRunTime>| {
44+
let CommandIdentifierClone = CommandIdentifier.clone();
45+
let ArgumentClone = Argument.clone();
46+
Box::pin(async move {
47+
let Environment = RunTime.GetEnvironment();
48+
let Executor:Arc<dyn CommandExecutor> = Environment.Require();
49+
Executor.ExecuteCommand(CommandIdentifierClone, ArgumentClone).await
50+
})
51+
}))
52+
}

Source/Command/GetAllCommands.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! # GetAllCommands Effect
2+
//!
3+
//! Defines the `ActionEffect` for retrieving all registered command
4+
//! identifiers.
5+
6+
use std::sync::Arc;
7+
8+
use super::CommandExecutor::CommandExecutor;
9+
use crate::{
10+
Effect::{ActionEffect::ActionEffect, ApplicationRunTime::ApplicationRunTime},
11+
Environment::Requires::Requires,
12+
Error::CommonError::CommonError,
13+
};
14+
15+
/// Creates an effect that, when executed, will retrieve a list of all currently
16+
/// registered command identifiers.
17+
///
18+
/// This includes both native commands implemented in Rust and proxied commands
19+
/// contributed by external sidecars. It uses the `CommandExecutor` capability
20+
/// from the environment to perform the operation.
21+
///
22+
/// # Returns
23+
///
24+
/// An `ActionEffect` that resolves with a `Vec<String>` of command
25+
/// identifiers.
26+
pub fn GetAllCommands<TRunTime>() -> ActionEffect<Arc<TRunTime>, CommonError, Vec<String>>
27+
where
28+
TRunTime: ApplicationRunTime + Send + Sync + 'static,
29+
TRunTime::EnvironmentType: Requires<Arc<dyn CommandExecutor>>, {
30+
ActionEffect::New(Arc::new(move |RunTime:Arc<TRunTime>| {
31+
Box::pin(async move {
32+
let Environment = RunTime.GetEnvironment();
33+
let Executor:Arc<dyn CommandExecutor> = Environment.Require();
34+
Executor.GetAllCommands().await
35+
})
36+
}))
37+
}

Source/Command/RegisterCommand.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! # RegisterCommand Effect
2+
//!
3+
//! Defines the `ActionEffect` for registering a command that is implemented in
4+
//! an external sidecar process.
5+
6+
use std::sync::Arc;
7+
8+
use super::CommandExecutor::CommandExecutor;
9+
use crate::{
10+
Effect::{ActionEffect::ActionEffect, ApplicationRunTime::ApplicationRunTime},
11+
Environment::Requires::Requires,
12+
Error::CommonError::CommonError,
13+
};
14+
15+
/// Creates an effect that, when executed, will register a command that is
16+
/// implemented in a sidecar process like Cocoon.
17+
///
18+
/// This allows the host application (`Mountain`) to know about commands
19+
/// contributed by extensions so they can be displayed in the command palette
20+
/// and invoked correctly. The `CommandExecutor` implementation will typically
21+
/// store this as a `Proxied` command handler.
22+
///
23+
/// # Parameters
24+
///
25+
/// * `SidecarIdentifier`: The unique ID of the sidecar where the command logic
26+
/// resides.
27+
/// * `CommandIdentifier`: The unique ID of the command itself (e.g.,
28+
/// "MyExtension.DoSomething").
29+
///
30+
/// # Returns
31+
///
32+
/// An `ActionEffect` that resolves to `()` on success.
33+
pub fn RegisterCommand<TRunTime>(
34+
SidecarIdentifier:String,
35+
CommandIdentifier:String,
36+
) -> ActionEffect<Arc<TRunTime>, CommonError, ()>
37+
where
38+
TRunTime: ApplicationRunTime + Send + Sync + 'static,
39+
TRunTime::EnvironmentType: Requires<Arc<dyn CommandExecutor>>, {
40+
ActionEffect::New(Arc::new(move |RunTime:Arc<TRunTime>| {
41+
let SidecarIdentifierClone = SidecarIdentifier.clone();
42+
let CommandIdentifierClone = CommandIdentifier.clone();
43+
Box::pin(async move {
44+
let Environment = RunTime.GetEnvironment();
45+
let Executor:Arc<dyn CommandExecutor> = Environment.Require();
46+
Executor.RegisterCommand(SidecarIdentifierClone, CommandIdentifierClone).await
47+
})
48+
}))
49+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! # UnregisterCommand Effect
2+
//!
3+
//! Defines the `ActionEffect` for unregistering a previously registered
4+
//! command.
5+
6+
use std::sync::Arc;
7+
8+
use super::CommandExecutor::CommandExecutor;
9+
use crate::{
10+
Effect::{ActionEffect::ActionEffect, ApplicationRunTime::ApplicationRunTime},
11+
Environment::Requires::Requires,
12+
Error::CommonError::CommonError,
13+
};
14+
15+
/// Creates an effect that, when executed, will unregister a command from the
16+
/// host's command registry.
17+
///
18+
/// This is typically called when an extension is deactivated or explicitly
19+
/// disposes of a command registration.
20+
///
21+
/// # Parameters
22+
///
23+
/// * `SidecarIdentifier`: The unique ID of the sidecar that originally
24+
/// registered the command.
25+
/// * `CommandIdentifier`: The unique ID of the command to unregister.
26+
///
27+
/// # Returns
28+
///
29+
/// An `ActionEffect` that resolves to `()` on success.
30+
pub fn UnregisterCommand<TRunTime>(
31+
SidecarIdentifier:String,
32+
CommandIdentifier:String,
33+
) -> ActionEffect<Arc<TRunTime>, CommonError, ()>
34+
where
35+
TRunTime: ApplicationRunTime + Send + Sync + 'static,
36+
TRunTime::EnvironmentType: Requires<Arc<dyn CommandExecutor>>, {
37+
ActionEffect::New(Arc::new(move |RunTime:Arc<TRunTime>| {
38+
let SidecarIdentifierClone = SidecarIdentifier.clone();
39+
let CommandIdentifierClone = CommandIdentifier.clone();
40+
Box::pin(async move {
41+
let Environment = RunTime.GetEnvironment();
42+
let Executor:Arc<dyn CommandExecutor> = Environment.Require();
43+
Executor.UnregisterCommand(SidecarIdentifierClone, CommandIdentifierClone).await
44+
})
45+
}))
46+
}

Source/Command/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! # Command Service
2+
//!
3+
//! This module defines the abstract contract for the Command service. It
4+
//! includes the `CommandExecutor` trait, which outlines the capabilities for
5+
//! command management, and the `ActionEffect` constructors for all
6+
//! command-related operations.
7+
8+
#![allow(non_snake_case, non_camel_case_types)]
9+
10+
// --- Trait Definition ---
11+
pub mod CommandExecutor;
12+
// pub use self::CommandExecutor::CommandExecutor;
13+
14+
// --- Effect Constructors ---
15+
pub mod ExecuteCommand;
16+
pub mod GetAllCommands;
17+
pub mod RegisterCommand;
18+
pub mod UnregisterCommand;
19+
20+
// pub use self::ExecuteCommand::ExecuteCommand;
21+
// pub use self::GetAllCommands::GetAllCommands;
22+
// pub use self::RegisterCommand::RegisterCommand;
23+
// pub use self::UnregisterCommand::UnregisterCommand;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! # ConfigurationInspector Trait
2+
//!
3+
//! Defines the abstract service trait for inspecting the sources of
4+
//! configuration values.
5+
6+
use async_trait::async_trait;
7+
8+
use super::DTO::{ConfigurationOverridesDTO::ConfigurationOverridesDTO, InspectResultDataDTO::InspectResultDataDTO};
9+
use crate::{Environment::Environment::Environment, Error::CommonError::CommonError};
10+
11+
/// An abstract service contract for an environment component that can inspect
12+
/// a configuration key to provide details about its value in all relevant
13+
/// scopes (e.g., default, user, workspace) and its final effective value.
14+
///
15+
/// This capability is used to power UIs like the "Settings" editor, which
16+
/// often shows where a particular setting is defined and allows the user to
17+
/// see inherited values.
18+
#[async_trait]
19+
pub trait ConfigurationInspector: Environment + Send + Sync {
20+
/// Inspects a configuration key to get its value from all relevant scopes.
21+
///
22+
/// # Parameters
23+
///
24+
/// * `Key`: The dot-separated configuration key to inspect.
25+
/// * `Overrides`: A DTO specifying scope overrides (e.g., for a specific
26+
/// resource or language).
27+
///
28+
/// # Returns
29+
///
30+
/// A `Result` containing an `Option<InspectResultDataDTO>`, which holds
31+
/// the detailed breakdown of the key's values across all scopes. Returns
32+
/// `None` if the key is not found in any configuration source.
33+
async fn InspectConfigurationValue(
34+
&self,
35+
Key:String,
36+
Overrides:ConfigurationOverridesDTO,
37+
) -> Result<Option<InspectResultDataDTO>, CommonError>;
38+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//! # ConfigurationProvider Trait
2+
//!
3+
//! Defines the abstract service trait for providing and updating configuration
4+
//! values.
5+
6+
use async_trait::async_trait;
7+
use serde_json::Value;
8+
9+
use super::DTO::{ConfigurationOverridesDTO::ConfigurationOverridesDTO, ConfigurationTarget::ConfigurationTarget};
10+
use crate::{Environment::Environment::Environment, Error::CommonError::CommonError};
11+
12+
/// An abstract service contract for an environment component that can provide
13+
/// the final, merged configuration values and handle requests to update those
14+
/// values in their persistent storage (e.g., `settings.json` files).
15+
#[async_trait]
16+
pub trait ConfigurationProvider: Environment + Send + Sync {
17+
/// Retrieves a configuration value for a given section or key, applying
18+
/// specified overrides.
19+
///
20+
/// This method should return the final, effective value after merging all
21+
/// configuration sources (e.g., default, user, workspace) in the correct
22+
/// order of precedence.
23+
///
24+
/// # Parameters
25+
///
26+
/// * `Section`: An optional, dot-separated key to a specific configuration
27+
/// section. If `None`, the entire configuration object should be
28+
/// returned.
29+
/// * `Overrides`: A DTO specifying scope overrides (e.g., for a specific
30+
/// resource or language).
31+
///
32+
/// # Returns
33+
///
34+
/// A `Result` containing the requested configuration as a
35+
/// `serde_json::Value`.
36+
async fn GetConfigurationValue(
37+
&self,
38+
Section:Option<String>,
39+
Overrides:ConfigurationOverridesDTO,
40+
) -> Result<Value, CommonError>;
41+
42+
/// Updates a configuration value at a specific key and target scope.
43+
///
44+
/// # Parameters
45+
///
46+
/// * `Key`: The dot-separated configuration key to update.
47+
/// * `ValueToSet`: The new `serde_json::Value` to set for the key.
48+
/// * `Target`: The `ConfigurationTarget` enum specifying which scope to
49+
/// write to (e.g., User, WorkSpace).
50+
/// * `Overrides`: A DTO for scope overrides.
51+
/// * `ScopeToLanguage`: An optional flag related to language-specific
52+
/// settings.
53+
async fn UpdateConfigurationValue(
54+
&self,
55+
Key:String,
56+
ValueToSet:Value,
57+
Target:ConfigurationTarget,
58+
Overrides:ConfigurationOverridesDTO,
59+
ScopeToLanguage:Option<bool>,
60+
) -> Result<(), CommonError>;
61+
}

0 commit comments

Comments
 (0)