feat: add main features

Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
2026-06-06 01:27:01 +02:00
parent 55b3bee2c8
commit 307ae71857
273 changed files with 48740 additions and 0 deletions

View File

@ -0,0 +1,115 @@
//! [`OpenProject`] and [`ListProjects`] (ARCHITECTURE §6).
use std::sync::Arc;
use domain::ports::{FileSystem, ProjectStore, RemotePath};
use domain::{AgentManifest, Project, ProjectId};
use crate::error::AppError;
use super::meta::{
from_json_bytes, join_root, ProjectMeta, AGENTS_FILE, IDEAI_DIR, PROJECT_FILE,
};
/// Input for [`OpenProject::execute`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpenProjectInput {
/// Id of the project to open (as known by the registry).
pub project_id: ProjectId,
}
/// Output of [`OpenProject::execute`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpenProjectOutput {
/// The opened project (registry source of truth for id/name/root/remote).
pub project: Project,
/// The project-local meta read from `.ideai/project.json`, if present and
/// readable. Read tolerantly: a missing/corrupt file does not fail the open.
pub meta: Option<ProjectMeta>,
/// The agent manifest read from `.ideai/agents.json`, if present. Tolerant:
/// absent in a brand-new project.
pub manifest: Option<AgentManifest>,
}
/// Loads a project, its `.ideai/project.json` meta and (tolerantly) its manifest.
pub struct OpenProject {
store: Arc<dyn ProjectStore>,
fs: Arc<dyn FileSystem>,
}
impl OpenProject {
/// Builds the use case from its injected ports.
#[must_use]
pub fn new(store: Arc<dyn ProjectStore>, fs: Arc<dyn FileSystem>) -> Self {
Self { store, fs }
}
/// Executes the open.
///
/// # Errors
/// - [`AppError::NotFound`] if the registry has no such project,
/// - [`AppError::Store`] on registry I/O failure.
///
/// Reading the `.ideai/` files is **tolerant**: their absence or a parse
/// failure yields `None` rather than an error, so a project whose `.ideai/`
/// was deleted can still be opened.
pub async fn execute(&self, input: OpenProjectInput) -> Result<OpenProjectOutput, AppError> {
let project = self.store.load_project(input.project_id).await?;
let meta = self
.read_optional_json::<ProjectMeta>(&project, PROJECT_FILE)
.await;
let manifest = self
.read_optional_json::<AgentManifest>(&project, AGENTS_FILE)
.await;
Ok(OpenProjectOutput {
project,
meta,
manifest,
})
}
/// Reads and parses a JSON file inside the project's `.ideai/`, tolerating
/// any failure (missing file, I/O error, parse error) by returning `None`.
async fn read_optional_json<T: for<'de> serde::Deserialize<'de>>(
&self,
project: &Project,
file: &str,
) -> Option<T> {
let path = RemotePath::new(join_root(&project.root, &format!("{IDEAI_DIR}/{file}")));
match self.fs.read(&path).await {
Ok(bytes) => from_json_bytes::<T>(&bytes).ok(),
Err(_) => None,
}
}
}
/// Output of [`ListProjects::execute`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ListProjectsOutput {
/// All projects known to the registry.
pub projects: Vec<Project>,
}
/// Lists the projects known to the registry.
pub struct ListProjects {
store: Arc<dyn ProjectStore>,
}
impl ListProjects {
/// Builds the use case from its injected port.
#[must_use]
pub fn new(store: Arc<dyn ProjectStore>) -> Self {
Self { store }
}
/// Executes the listing.
///
/// # Errors
/// [`AppError::Store`] on registry I/O failure.
pub async fn execute(&self) -> Result<ListProjectsOutput, AppError> {
let projects = self.store.list_projects().await?;
Ok(ListProjectsOutput { projects })
}
}