Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/assets/screenstudio-demo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
[workspace]
members = [
"crates/app-services",
"crates/loopforge-adapters",
"crates/loopforge-api",
"crates/loopforge-app",
"crates/loopforge-app-core",
"crates/native-shell",
"crates/ralph-core",
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ At any iteration the loop honours three control files: `.ralph-pause` freezes wo
## Demo

> [!TIP]
> A one minute video walkthrough is on the [Releases page](https://github.com/taberoajorge/loopforge/releases). For a text walkthrough of a real session, see [Your first loop](#your-first-loop).
> Watch the short product walkthrough on Screen Studio.
>
> [![LoopForge demo preview](.github/assets/screenstudio-demo.jpg)](https://screen.studio/share/1LFJxw9J)
>
> Installers and release notes are on the [Releases page](https://github.com/taberoajorge/loopforge/releases). For a text walkthrough of a real session, see [Your first loop](#your-first-loop).

## Quick start

Expand Down
1 change: 1 addition & 0 deletions crates/app-services/src/events/ask.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/app-services/src/events/loop_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

12 changes: 12 additions & 0 deletions crates/app-services/src/events/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use serde::Serialize;

pub mod ask;
pub mod loop_events;
pub mod plan;

pub trait Event: Send + 'static {
const NAME: &'static str;
type Payload: Serialize + Send + 'static;

fn payload(&self) -> Self::Payload;
}
1 change: 1 addition & 0 deletions crates/app-services/src/events/plan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/app-services/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod events;
pub mod monitor;
pub mod project_queries;
pub mod session;
Expand Down
10 changes: 10 additions & 0 deletions crates/loopforge-adapters/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "loopforge-adapters"
version = "0.1.0"
edition = "2021"

[dependencies]
rusqlite = { version = "0.32", features = ["bundled"] }
tokio = { version = "1", features = ["full"] }
thiserror = "1"
serde = { version = "1", features = ["derive"] }
1 change: 1 addition & 0 deletions crates/loopforge-adapters/src/channel_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/loopforge-adapters/src/filesystem/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/loopforge-adapters/src/inmemory/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

5 changes: 5 additions & 0 deletions crates/loopforge-adapters/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod channel_events;
pub mod filesystem;
pub mod inmemory;
pub mod paths;
pub mod sqlite;
1 change: 1 addition & 0 deletions crates/loopforge-adapters/src/paths.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/loopforge-adapters/src/sqlite/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

9 changes: 9 additions & 0 deletions crates/loopforge-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "loopforge-api"
version = "0.1.0"
edition = "2021"
description = "API contract definitions for LoopForge methods and events"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
1 change: 1 addition & 0 deletions crates/loopforge-api/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions crates/loopforge-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod events;
pub mod methods;
1 change: 1 addition & 0 deletions crates/loopforge-api/src/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

14 changes: 14 additions & 0 deletions crates/loopforge-app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "loopforge-app"
version = "0.1.0"
edition = "2021"
description = "Application layer for LoopForge hexagonal architecture"

[dependencies]
ralph-core = { path = "../ralph-core" }
async-trait = "0.1"
serde = { version = "1", features = ["derive"] }
thiserror = "2"
tokio = { version = "1", features = ["rt-multi-thread", "sync", "macros"] }
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1", features = ["v4", "serde"] }
50 changes: 50 additions & 0 deletions crates/loopforge-app/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::path::PathBuf;
use thiserror::Error;
use uuid::Uuid;

pub type AppResult<T> = Result<T, AppError>;

#[derive(Debug, Error)]
pub enum AppError {
#[error("Project not found: {0}")]
ProjectNotFound(Uuid),

#[error("Session not found: {0}")]
SessionNotFound(Uuid),

#[error("Artifact error for '{path}': {message}")]
ArtifactError { path: PathBuf, message: String },

#[error("Storage error: {0}")]
StorageError(String),

#[error("Validation error: {0}")]
ValidationError(String),

#[error("Service error in '{service}': {message}")]
ServiceError { service: String, message: String },
}

impl AppError {
pub fn artifact(path: impl Into<PathBuf>, message: impl Into<String>) -> Self {
Self::ArtifactError {
path: path.into(),
message: message.into(),
}
}

pub fn storage(message: impl Into<String>) -> Self {
Self::StorageError(message.into())
}

pub fn validation(message: impl Into<String>) -> Self {
Self::ValidationError(message.into())
}

pub fn service(service: impl Into<String>, message: impl Into<String>) -> Self {
Self::ServiceError {
service: service.into(),
message: message.into(),
}
}
}
4 changes: 4 additions & 0 deletions crates/loopforge-app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod errors;
pub mod models;
pub mod ports;
pub mod services;
1 change: 1 addition & 0 deletions crates/loopforge-app/src/models.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/loopforge-app/src/ports.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions crates/loopforge-app/src/services.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

9 changes: 6 additions & 3 deletions crates/native-shell/src/services/backend_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ mod tests {
})
})
.expect("open plan");
let output = BackendAdapter::write_plan_input("project-1", "Continue", |_, _| Ok::<_, ()>(()))
.expect("write plan");
let output =
BackendAdapter::write_plan_input("project-1", "Continue", |_, _| Ok::<_, ()>(()))
.expect("write plan");
let stopped =
BackendAdapter::stop_plan_session("project-1", |_| Ok::<_, ()>(())).expect("stop plan");

Expand All @@ -171,7 +172,9 @@ mod tests {
project_id: String::from("project-1"),
};
let stages = BackendAdapter::atomizer_stages(request.clone(), |_| {
Ok::<_, ()>(vec![loopforge_app_core::atomizer::AtomizerStage::CollectPlan])
Ok::<_, ()>(vec![
loopforge_app_core::atomizer::AtomizerStage::CollectPlan,
])
})
.expect("stages");
let run = BackendAdapter::run_atomizer(request.clone(), |request| {
Expand Down
Loading
Loading