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,102 @@
/**
* Minimal "Settings → AI Profiles" panel (L5). An always-available entry point
* to review the configured profiles and re-run the setup wizard after the first
* run. Kept intentionally small; richer per-profile editing reuses the wizard.
*
* Pure presentation over the {@link ProfileGateway} port (no `invoke()`).
*/
import { useCallback, useEffect, useState } from "react";
import type { AgentProfile, GatewayError } from "@/domain";
import { useGateways } from "@/app/di";
import { Button, Panel } from "@/shared";
import { FirstRunWizard } from "./FirstRunWizard";
export function ProfilesSettings() {
const { profile } = useGateways();
const [profiles, setProfiles] = useState<AgentProfile[]>([]);
const [error, setError] = useState<string | null>(null);
const [editing, setEditing] = useState(false);
const refresh = useCallback(async () => {
setError(null);
try {
setProfiles(await profile.listProfiles());
} catch (e) {
setError(
e && typeof e === "object" && "message" in e
? String((e as GatewayError).message)
: String(e),
);
}
}, [profile]);
useEffect(() => {
void refresh();
}, [refresh]);
async function del(id: string) {
await profile.deleteProfile(id);
await refresh();
}
if (editing) {
// Reopened after the first run, so force the wizard to render.
return (
<FirstRunWizard
forceOpen
onDone={() => {
setEditing(false);
void refresh();
}}
/>
);
}
return (
<Panel
aria-label="ai profiles settings"
title="AI Profiles"
actions={
<Button size="sm" onClick={() => setEditing(true)}>
Configure profiles
</Button>
}
>
<div className="flex flex-col gap-3">
{error && (
<p role="alert" className="text-sm text-danger">
{error}
</p>
)}
{profiles.length === 0 ? (
<p className="text-sm text-muted">No profiles configured.</p>
) : (
<ul className="flex flex-col divide-y divide-border">
{profiles.map((p) => (
<li
key={p.id}
className="flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0"
>
<span className="flex items-baseline gap-2">
<strong className="text-sm text-content">{p.name}</strong>
<code className="text-xs text-muted">{p.command}</code>
</span>
<Button
size="sm"
variant="ghost"
aria-label={`delete ${p.name}`}
onClick={() => void del(p.id)}
>
Delete
</Button>
</li>
))}
</ul>
)}
</div>
</Panel>
);
}