Files
davideandClaude Sonnet 5.5 51993dd0c8 Immagini: percorsi relativi cercati nelle cartelle superiori (radice della wiki)
Il motore scrive i percorsi relativi alla radice del progetto (es. la wiki
cyber-tesi con l'exe in una sottocartella): ora si cercano nella cartella
dell'exe e poi in quelle superiori, vince la più vicina. Il catalogo JSON
delle figure resta del motore; l'app mostra solo le immagini citate.
Test MD-28…MD-30, ADR-0006, README, MVP e AGENT.md aggiornati.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:00:25 +02:00

11 KiB
Raw Permalink Blame History

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

  1. Se non ci sono argomenti: stampa l'uso ed esce con codice 2.
  2. Avvia il motore scelto in modalità non interattiva (claude -p <prompt> o codex exec … -- <prompt>) con WorkingDirectory = AppContext.BaseDirectory.
  3. Ritrasmette stdout e stderr del processo figlio in tempo reale.
  4. Esce con lo stesso exit code del motore. Su Windows l'eseguibile non ha finestra di console (ADR-0005): cmd e PowerShell non aspettano la fine del programma, quindi l'exit code è disponibile solo se il chiamante attende il processo (start /wait, Start-Process -Wait, | Out-Host, script).
  5. 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, immagini. Le immagini ![alt](percorso) si mostrano se il percorso è locale (assoluto, file:// o relativo: cercato nella cartella dell'exe e poi nelle cartelle superiori, cioè nella radice del progetto del motore) e il file è un'immagine leggibile entro i limiti (caricata in background: prima compare [alt], poi l'immagine); altrimenti, e sempre per gli URL http(s), compare il testo alternativo [alt] e non si scarica nulla (ADR-0006). 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. Invio invia, Maiusc+Invio va 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). Valori iniziali: il modello più piccolo del motore (Claude Code: Haiku 5.5; Codex: GPT-5.6 Luna) ed effort low, per risposte rapide e poco costose; sono quelli che si ritrovano all'avvio e a ogni cambio di CLI. Si chiude con Esc o 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.
  • Aggiornamenti (nello stesso riquadro, sotto le impostazioni): una riga per ogni CLI installato con nome, versione e pulsante Aggiorna. L'app controlla prima se esiste una versione più recente (all'avvio, all'apertura del riquadro se l'ultimo controllo ha più di 5 minuti, e dopo ogni aggiornamento): se c'è, la riga dice "Aggiornamento disponibile: X", il pulsante è evidenziato e un puntino compare sul pulsante Impostazioni; se no, la riga dice "Aggiornato" e nulla è evidenziato; senza rete "Controllo non riuscito". Il pulsante esegue il comando ufficiale <cli> update e mostra l'esito sulla riga: "Aggiornato da X a Y", "Già aggiornato (X)" o l'errore con il comando manuale adatto al metodo di installazione (npm, Homebrew, WinGet, nativo). Un solo aggiornamento alla volta; i pulsanti sono disabilitati durante una risposta. Nessun aggiornamento parte da solo. Vedi ADR-0004.
  • Motori (ADR-0002): una chat usa un solo motore. Cambiare CLI apre una nuova chat con quel motore; modello ed effort tornano ai valori iniziali del nuovo motore (il modello più piccolo ed effort low) 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/share su Linux; vedi Nome del progetto). Il file contiene guid (= id di sessione di claude), titolo, data, flag started, 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>, quindi claude ricorda 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 di claude. 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 --resume non ritrova il contesto.
  • La risposta compare a fine generazione (nessuno streaming); durante l'attesa un indicatore di avanzamento e Invia disabilitato. Se claude esce 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.Name sui 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.0 per Windows e Linux. Avalonia (GUI), Markdig (parsing markdown). Il codice è diviso in Core/ (avvio di claude, cronologia, nome app) e Gui/ (finestra, ViewModel, renderer markdown); Program.cs sceglie CLI o GUI.
  • ProcessStartInfo.ArgumentList per passare il prompt (niente problemi di quoting).
  • claude è un eseguibile nativo (~/.local/bin): si avvia direttamente, senza cmd /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, claude parte nella cartella dell'exe (verificabile chiedendo "pwd").
  • L'output appare in streaming, non solo alla fine.
  • L'exit code è propagato (su Windows, quando il chiamante attende il processo: vedi sopra).
  • Un prompt con virgolette e spazi arriva intatto.

Domande aperte

  • Permessi: serve --allowedTools o --permission-mode per l'uso non interattivo?
  • Formato output: testo semplice o --output-format stream-json?