feat(agent): menu de profils restreint Claude/Codex + retrait custom (D7) — §17
Dernier lot de §17 : seuls les profils pilotables en mode structuré sont proposés à la sélection/création. - domain : AgentProfile::is_selectable() = structured_adapter.is_some(), source unique de vérité du prédicat. - infrastructure : AgentSessionFactory::supports délègue à is_selectable (supports et is_selectable ne peuvent plus diverger). - application : selectable_reference_profiles() = reference_profiles() filtré ; ReferenceProfiles et FirstRunState exposent la liste filtrée (Claude/Codex). reference_profiles() brut reste à 4 (data intacte) ⇒ un agent Gemini/Aider/custom legacy déjà configuré continue de tourner. - frontend : bloc AddCustomProfile retiré du wizard first-run, action addCustom retirée du viewmodel ; wizard n'affiche que la liste filtrée. Tests (QA) : is_selectable (table de vérité), cohérence stricte is_selectable<->supports, liste exposée=2 / data brute=4, garde anti-régression Vitest sur l'absence du bloc custom — validées par mutation. cargo test --workspace : 820 passed. npx vitest run : 344 passed. §17 COMPLET (D0->D7). Suivi restant : D6b (surfacer reply dans le writer wire .response.json pour la délégation par protocole fichier). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* `useFirstRun` — view-model for the first-run wizard and profile management
|
||||
* (L5). Owns the wizard state (reference candidates + selection + availability +
|
||||
* custom profiles) and the actions. Consumes the {@link ProfileGateway}
|
||||
* (L5). Owns the wizard state (selectable reference candidates + selection +
|
||||
* availability) and the actions. Consumes the {@link ProfileGateway}
|
||||
* exclusively — never `invoke()` — so the feature is testable with a mock.
|
||||
*/
|
||||
|
||||
@ -27,7 +27,7 @@ export interface WizardEntry {
|
||||
export interface FirstRunViewModel {
|
||||
/** Whether the wizard should be shown (null while loading). */
|
||||
isFirstRun: boolean | null;
|
||||
/** The candidate rows (reference + added custom profiles). */
|
||||
/** The candidate rows (selectable reference profiles). */
|
||||
entries: WizardEntry[];
|
||||
/** Last error message, or null. */
|
||||
error: string | null;
|
||||
@ -37,9 +37,7 @@ export interface FirstRunViewModel {
|
||||
toggle: (id: string) => void;
|
||||
/** Replaces a candidate's profile (edited command/args/injection). */
|
||||
updateProfile: (id: string, profile: AgentProfile) => void;
|
||||
/** Adds a custom profile (selected by default). */
|
||||
addCustom: (profile: AgentProfile) => void;
|
||||
/** Removes a candidate by id (e.g. a custom one). */
|
||||
/** Removes a candidate by id. */
|
||||
remove: (id: string) => void;
|
||||
/** Runs detection over all candidates, filling availability. */
|
||||
detect: () => Promise<void>;
|
||||
@ -116,13 +114,6 @@ export function useFirstRun(): FirstRunViewModel {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const addCustom = useCallback((p: AgentProfile) => {
|
||||
setEntries((prev) => [
|
||||
...prev,
|
||||
{ profile: p, selected: true, available: null },
|
||||
]);
|
||||
}, []);
|
||||
|
||||
const remove = useCallback((id: string) => {
|
||||
setEntries((prev) => prev.filter((e) => e.profile.id !== id));
|
||||
}, []);
|
||||
@ -169,7 +160,6 @@ export function useFirstRun(): FirstRunViewModel {
|
||||
busy,
|
||||
toggle,
|
||||
updateProfile,
|
||||
addCustom,
|
||||
remove,
|
||||
detect,
|
||||
finish,
|
||||
|
||||
Reference in New Issue
Block a user