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,133 @@
//! L5 tests for the profile/first-run DTO (de)serialisation contract: camelCase
//! on the wire, embedded [`AgentProfile`] shape preserved, and `parse_profile_id`
//! error behaviour.
use app_tauri_lib::dto::{
parse_delete_profile, parse_profile_id, ConfigureProfilesRequestDto, DetectProfilesRequestDto,
DetectProfilesResponseDto, FirstRunStateDto, ProfileListDto, SaveProfileRequestDto,
};
use application::{
ConfigureProfilesInput, DetectProfilesInput, DetectProfilesOutput, FirstRunStateOutput,
ProfileAvailability, SaveProfileInput,
};
use domain::ids::ProfileId;
use domain::profile::{AgentProfile, ContextInjection};
use serde_json::json;
use uuid::Uuid;
fn profile(id: u128, name: &str, command: &str) -> AgentProfile {
AgentProfile::new(
ProfileId::from_uuid(Uuid::from_u128(id)),
name,
command,
Vec::new(),
ContextInjection::convention_file("CLAUDE.md").unwrap(),
Some(format!("{command} --version")),
"{projectRoot}",
)
.unwrap()
}
#[test]
fn profile_list_dto_serialises_camelcase_profiles() {
let dto: ProfileListDto = vec![profile(1, "Claude", "claude")].into();
let v = serde_json::to_value(&dto).unwrap();
let arr = v.as_array().expect("transparent array");
assert_eq!(arr.len(), 1);
assert_eq!(arr[0]["command"], "claude");
assert_eq!(arr[0]["cwdTemplate"], "{projectRoot}");
assert_eq!(arr[0]["contextInjection"]["strategy"], "conventionFile");
}
#[test]
fn detect_request_deserialises_candidates() {
let raw = json!({
"candidates": [{
"id": Uuid::from_u128(1).to_string(),
"name": "Claude",
"command": "claude",
"args": [],
"contextInjection": { "strategy": "stdin" },
"detect": "claude --version",
"cwdTemplate": "{projectRoot}"
}]
});
let dto: DetectProfilesRequestDto = serde_json::from_value(raw).unwrap();
let input: DetectProfilesInput = dto.into();
assert_eq!(input.candidates.len(), 1);
assert_eq!(input.candidates[0].command, "claude");
}
#[test]
fn detect_response_serialises_available_flag_camelcase() {
let out = DetectProfilesOutput {
results: vec![ProfileAvailability {
profile: profile(1, "Claude", "claude"),
available: true,
}],
};
let dto: DetectProfilesResponseDto = out.into();
let v = serde_json::to_value(&dto).unwrap();
let arr = v.as_array().unwrap();
assert_eq!(arr[0]["available"], true);
assert_eq!(arr[0]["profile"]["command"], "claude");
}
#[test]
fn save_request_deserialises_profile() {
let raw = json!({
"profile": {
"id": Uuid::from_u128(2).to_string(),
"name": "Codex",
"command": "codex",
"args": ["--foo"],
"contextInjection": { "strategy": "conventionFile", "target": "AGENTS.md" },
"detect": null,
"cwdTemplate": ""
}
});
let dto: SaveProfileRequestDto = serde_json::from_value(raw).unwrap();
let input: SaveProfileInput = dto.into();
assert_eq!(input.profile.command, "codex");
assert_eq!(input.profile.args, vec!["--foo"]);
assert!(input.profile.detect.is_none());
}
#[test]
fn configure_request_deserialises_profiles() {
let raw = json!({ "profiles": [] });
let dto: ConfigureProfilesRequestDto = serde_json::from_value(raw).unwrap();
let input: ConfigureProfilesInput = dto.into();
assert!(input.profiles.is_empty());
}
#[test]
fn first_run_state_dto_serialises_camelcase() {
let out = FirstRunStateOutput {
is_first_run: true,
reference_profiles: vec![profile(1, "Claude", "claude")],
};
let dto: FirstRunStateDto = out.into();
let v = serde_json::to_value(&dto).unwrap();
assert_eq!(v["isFirstRun"], true);
assert!(v.get("is_first_run").is_none(), "no snake_case leak");
assert_eq!(v["referenceProfiles"][0]["command"], "claude");
}
#[test]
fn parse_profile_id_accepts_uuid_and_rejects_garbage() {
let id = Uuid::from_u128(7);
assert_eq!(
parse_profile_id(&id.to_string()).unwrap(),
ProfileId::from_uuid(id)
);
let err = parse_profile_id("not-a-uuid").expect_err("garbage rejected");
assert_eq!(err.code, "INVALID");
}
#[test]
fn parse_delete_profile_builds_input() {
let id = Uuid::from_u128(9);
let input = parse_delete_profile(&id.to_string()).unwrap();
assert_eq!(input.id, ProfileId::from_uuid(id));
}