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,94 @@
/**
* L5 — the in-memory {@link MockProfileGateway}: first-run flag lifecycle,
* reference catalogue, simulated detection (only `claude` installed), and the
* save/list/delete/configure CRUD.
*/
import { describe, it, expect } from "vitest";
import type { AgentProfile } from "@/domain";
import { MockProfileGateway, MOCK_REFERENCE_PROFILES } from "./index";
function customProfile(id: string, command: string): AgentProfile {
return {
id,
name: `Custom ${id}`,
command,
args: [],
contextInjection: { strategy: "stdin" },
detect: null,
cwdTemplate: "{projectRoot}",
};
}
describe("MockProfileGateway", () => {
it("firstRunState is first-run with the four reference profiles", async () => {
const gw = new MockProfileGateway();
const state = await gw.firstRunState();
expect(state.isFirstRun).toBe(true);
expect(state.referenceProfiles.map((p) => p.command)).toEqual([
"claude",
"codex",
"gemini",
"aider",
]);
});
it("referenceProfiles returns a clone of the catalogue", async () => {
const gw = new MockProfileGateway();
const refs = await gw.referenceProfiles();
expect(refs).toEqual(MOCK_REFERENCE_PROFILES);
refs[0].command = "mutated";
const again = await gw.referenceProfiles();
expect(again[0].command).toBe("claude");
});
it("detectProfiles marks only claude as installed", async () => {
const gw = new MockProfileGateway();
const results = await gw.detectProfiles([...MOCK_REFERENCE_PROFILES]);
const byCommand = Object.fromEntries(
results.map((r) => [r.profile.command, r.available]),
);
expect(byCommand).toEqual({
claude: true,
codex: false,
gemini: false,
aider: false,
});
});
it("saveProfile upserts and listProfiles reflects it", async () => {
const gw = new MockProfileGateway();
await gw.saveProfile(customProfile("c1", "foo"));
await gw.saveProfile(customProfile("c1", "bar")); // same id ⇒ replace
const list = await gw.listProfiles();
expect(list).toHaveLength(1);
expect(list[0].command).toBe("bar");
});
it("deleteProfile removes by id", async () => {
const gw = new MockProfileGateway();
await gw.saveProfile(customProfile("a", "a"));
await gw.saveProfile(customProfile("b", "b"));
await gw.deleteProfile("a");
const list = await gw.listProfiles();
expect(list.map((p) => p.id)).toEqual(["b"]);
});
it("configureProfiles persists the batch and closes the first run", async () => {
const gw = new MockProfileGateway();
expect((await gw.firstRunState()).isFirstRun).toBe(true);
const chosen = [customProfile("x", "x")];
const out = await gw.configureProfiles(chosen);
expect(out).toEqual(chosen);
expect((await gw.firstRunState()).isFirstRun).toBe(false);
expect(await gw.listProfiles()).toEqual(chosen);
});
it("configureProfiles with an empty list still closes the first run", async () => {
const gw = new MockProfileGateway();
await gw.configureProfiles([]);
expect((await gw.firstRunState()).isFirstRun).toBe(false);
});
});