ADR-0002 passa ad Accettata per Claude Code e Codex con l'esito delle prove reali: id di sessione da thread.started, output JSONL, risposta = ultimo agent_message, ripresa senza -s e sola lettura via sandbox_mode, -- prima del prompt. MVP, ROADMAP, INSTALL e README descrivono l'interruttore CLI, la nuova opzione --engine e il problema del modello predefinito che richiede un Codex più recente. TESTING.md aggiunge le righe CX, EN e ST-12. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
8.6 KiB
MVP (doc-first)
Obiettivo
Eseguibile C# a riga di comando che inoltra un prompt a Claude Code (claude) lanciandolo nella directory dell'eseguibile, e ne mostra l'output.
Uso
<nome-app> "spiega questo progetto"
Tutti gli argomenti sono uniti in un unico prompt. Con --engine <id> come primo argomento (claude o codex) si sceglie il motore, per esempio <nome-app> --engine codex "spiega questo progetto"; senza, si usa Claude Code. Id sconosciuto o prompt mancante: uso su stderr ed exit code 2.
Comportamento
- Se non ci sono argomenti: stampa l'uso ed esce con codice 2.
- Avvia il motore scelto in modalità non interattiva (
claude -p <prompt>ocodex exec … -- <prompt>) conWorkingDirectory = AppContext.BaseDirectory. - Ritrasmette stdout e stderr del processo figlio in tempo reale.
- Esce con lo stesso exit code di
claude. - Se l'eseguibile del motore non è trovato: messaggio chiaro ed exit code 127.
GUI (chat)
Senza argomenti si apre una finestra Avalonia (C# + XAML, nessun HTML) in stile claude.ai/ChatGPT, identica su Windows e Linux. Con argomenti resta la CLI. Decisione e motivazioni: ADR-0001.
Struttura della finestra
- Barra laterale (sinistra, comprimibile con il pulsante a tre linee): logo e nome dell'app, pulsante Nuova chat, elenco delle chat salvate (titolo = inizio del primo messaggio, data/ora dell'ultimo scambio; la chat aperta è evidenziata). Un clic su una chat la riapre; la ✕ (con conferma) la elimina. Elenco vuoto: "Nessuna chat salvata".
- Conversazione: messaggi alternati utente/Claude. Le risposte sono renderizzate in markdown: titoli, liste, tabelle, citazioni, blocchi di codice, grassetto/corsivo/barrato, codice inline, link. Il rendering è un renderer proprio (MarkdownView.cs) che trasforma l'albero di Markdig in controlli Avalonia; l'HTML grezzo è disabilitato. Il testo è selezionabile. Sulle risposte il pulsante Copia copia il markdown; sui blocchi di codice copia il codice.
- Schermata iniziale (chat vuota): solo logo, titolo e sottotitolo (nessun suggerimento precompilato).
- Composer (in basso, scheda arrotondata): campo di testo che cresce fino a ~8 righe e pulsante Invia circolare con icona.
Invioinvia,Maiusc+Inviova a capo. Hint sulla tastiera sotto la scheda. Non contiene più i selettori di modello ed effort. - Impostazioni (in alto a destra, pulsante con icona a cursori, simmetrico a quello della barra laterale): aprono un riquadro a comparsa con l'interruttore CLI (Claude Code, Codex; un motore non installato è mostrato "non installato" e non è selezionabile; disabilitato durante l'attesa), poi Modello (Predefinito, Fable 5.1, Opus 5.5, Sonnet 5.5, Haiku 5.5, "Altro ID…" con campo libero) ed Effort (Predefinito, low, medium, high, xhigh, max). Si chiude con
Esco con un clic fuori; le scelte restano valide per i messaggi successivi (non sono ancora salvate su disco). Passati come--model/--effort; con "Predefinito" il flag viene omesso. Solo GUI. - Motori (ADR-0002): una chat usa un solo motore. Cambiare CLI apre una nuova chat con quel motore; modello ed effort tornano a "Predefinito" e le liste dipendono dal motore (Codex: modelli GPT-5.6 Sol/Terra/Luna, stessi livelli di effort). Aprendo una chat salvata il selettore passa al motore di quella chat. L'etichetta sulle risposte, il segnaposto del composer e il messaggio d'attesa usano il nome del motore, e l'elenco chat lo indica sotto il titolo. Con Codex la sessione è letta dall'output (
thread_id) e usata per riprendere la chat; i permessi sono di sola lettura. - Contesto:
claude -p --session-id <guid>al primo messaggio,--resume <guid>ai successivi. "Nuova chat" svuota la vista e genera un nuovo guid. - Cronologia: dopo ogni scambio la chat è salvata in
<cartella dati>/<nome-app>/chats/<guid>.json, dove la cartella dati èEnvironment.SpecialFolder.LocalApplicationData(%LOCALAPPDATA%su Windows,~/.local/sharesu Linux; vedi Nome del progetto). Il file contiene guid (= id di sessione diclaude), titolo, data, flagstarted, messaggi con ruolo e testo, motore (Engine) e id di sessione del motore (SessionId); i file senza questi campi sono chat di Claude Code. Riaprendo una chat si rimostra la conversazione e si prosegue con--resume <guid>, quindiclaudericorda il contesto. Il messaggio dell'utente viene salvato subito, prima della risposta (così non si perde se l'app si chiude mentre Claude risponde); la risposta si aggiunge appena arriva. Una chat nuova e vuota non viene salvata. All'avvio l'app riapre automaticamente l'ultima conversazione (la più recente); se non ce ne sono parte con la schermata iniziale. "Nuova chat" resta sempre disponibile. Eliminare una chat cancella solo il file JSON, non la sessione diclaude. Non si può aprire/eliminare una chat mentre Claude sta rispondendo. - Limite noto: la sessione di
claudeè legata alla cartella in cui gira (quella dell'exe): se si sposta l'exe, le vecchie chat si leggono ancora ma--resumenon ritrova il contesto. - La risposta compare a fine generazione (nessuno streaming); durante l'attesa un indicatore di avanzamento e Invia disabilitato. Se
claudeesce con errore, lo stderr appare come messaggio di errore. - I link
http(s)si aprono nel browser di sistema. - Finestra orizzontale con proporzioni 16:10: larga il 75% dell'area utile dello schermo (max 1440 px logici), altezza di conseguenza (max 90% dell'area utile), centrata; minimo 900x600. Su un monitor Full HD 1920x1080 risulta circa 1440x900.
Design (UI/UX)
Sorgente di verità per l'aspetto, derivato dalla skill ui-ux-pro-max (stile "strumento per sviluppatori": slate + accento verde). I token vivono come risorse di tema in Gui/App.axaml.
- Tema: segue il sistema (chiaro/scuro) tramite
RequestedThemeVariant="Default". - Token (chiaro / scuro): sfondo
#FFFFFF/#0F172A, superficie composer#FFFFFF/#1E293B, testo#0F172A/#F8FAFC, testo secondario#475569/#94A3B8, bordi#CBD5E1/#334155, accento#15803D/#22C55E, errore#B91C1C/#F87171. Contrasto testo ≥ 4.5:1. - Tipografia: font di sistema (Segoe UI Variable/Segoe UI su Windows; Inter, Ubuntu, Cantarell, Noto Sans, DejaVu Sans su Linux; corpo 15.5, titoli fino a 24), Cascadia Code/Consolas/DejaVu Sans Mono per il codice. Nessun font incorporato (funziona offline).
- Forma: raggi 10–20, bordi sottili, pulsante d'invio circolare.
- Barra laterale: sfondo
Muted, 272 px; voce attiva con barra d'accento a sinistra; ✕ per eliminare. - Accessibilità: focus visibile (il composer prende il bordo d'accento),
AutomationProperties.Namesui pulsanti a sola icona e sul campo messaggio, target ≥ 30 px, icone vettoriali (nessuna emoji). - Non incluso: evidenziazione sintattica del codice.
Scelte tecniche
Le scelte architetturali sono negli ADR. Sintesi:
- .NET 10, un solo progetto
net10.0per Windows e Linux. Avalonia (GUI), Markdig (parsing markdown). Il codice è diviso inCore/(avvio diclaude, cronologia, nome app) eGui/(finestra, ViewModel, renderer markdown);Program.cssceglie CLI o GUI. ProcessStartInfo.ArgumentListper passare il prompt (niente problemi di quoting).claudeè un eseguibile nativo (~/.local/bin): si avvia direttamente, senzacmd /c. Lo stdin è chiuso subito per evitare l'attesa di 3s di claude.- Working dir:
AppContext.BaseDirectory, non la cwd del chiamante. - L'avvio dei motori è in un solo punto (Core/EngineRunner.cs), usato da CLI e GUI; ogni motore descrive argomenti e parser in Core/Engine.cs.
Fuori scope (MVP)
Streaming token-per-token nella GUI, annullamento di una risposta in corso, rinomina/ricerca delle chat, config file, altri motori oltre a Claude Code (Codex, Antigravity: vedi ADR-0002), logging su file, supporto macOS. I test automatici sono pianificati: TESTING.md.
Criteri di accettazione
Ogni criterio ha test automatici nella matrice di TESTING.md (CL-04, CL-08, CL-06, CL-01).
- Eseguito da un'altra cartella,
claudeparte nella cartella dell'exe (verificabile chiedendo "pwd"). - L'output appare in streaming, non solo alla fine.
- L'exit code è propagato.
- Un prompt con virgolette e spazi arriva intatto.
Domande aperte
- Permessi: serve
--allowedToolso--permission-modeper l'uso non interattivo? - Formato output: testo semplice o
--output-format stream-json?