Files
davideandClaude Sonnet 5.5 5870de6fda FakeClaude, test per area e renderer diviso in due file
- tests/FakeClaude: eseguibile finto 'claude' configurabile con variabili
  d'ambiente (registro di argomenti/cwd/stdin, output, exit code, ritardo),
  con le prove FK-01…FK-05.
- Test organizzati per livello (Gui/, Process/, Support/) e struttura
  descritta in TESTING.md.
- MarkdownView: la parte sulle immagini passa in MarkdownView.Images.cs
  (partial), senza cambiare il comportamento.

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

8.9 KiB

AGENT.md

Guida per gli agenti di codice (Claude Code, Gemini CLI, altri) che lavorano in questo repository. È l'unica sorgente delle istruzioni: CLAUDE.md e GEMINI.md sono puntatori che importano questo file, quindi ogni modifica si fa qui (vedi docs/README.md).

Progetto

agent-wiki-ui (già LlmRun; il nome ha un'unica sorgente, vedi docs/README.md): eseguibile C# (.NET 10, Windows e Linux) che invoca Claude Code (claude -p) o Codex (codex exec) da terminale. Senza argomenti apre una GUI di chat Avalonia, con argomenti funziona da CLI.

Workflow doc-first (obbligatorio)

  • Stato attuale, stadio (MVP), debiti e cosa manca: docs/PROJECT_STATE.md; aggiornarlo nello stesso commit di ogni cambio di stadio, funzione, ADR o debito. Specifica e criteri di accettazione: docs/MVP.md. Fasi e stato: docs/ROADMAP.md. Indice dei doc e regole (SSOT, ADR): docs/README.md; una decisione architetturale si scrive solo nel suo ADR, gli altri doc la richiamano con un link. Uso: README.md.
  • Test obbligatori (docs/TESTING.md, ADR-0003): ogni nuova funzione, correzione o cambio di comportamento va coperta da test nello stesso commit; prima si aggiunge la riga (con ID) alla matrice in TESTING.md, poi i test, poi il codice. Un bug si corregge partendo da un test che fallisce.
  • Ad ogni richiesta di modifica: aggiornare prima i doc interessati (MVP.md, ROADMAP.md con le spunte, README.md se cambia l'uso; un nuovo ADR in docs/adr/ per ogni scelta architetturale), poi il codice, poi questo file se cambiano comandi, design o vincoli. Nessuna modifica deve lasciare i doc disallineati.

Comandi

  • Build: dotnet build dalla radice (soluzione agent-wiki-ui.slnx: app in src/agent-wiki-ui/, test in tests/; net10.0, Avalonia)
  • GUI: dotnet run --project src/agent-wiki-ui; CLI: dotnet run --project src/agent-wiki-ui -- "prompt"
  • Publish single-file (uno per sistema): scripts/publish.sh (Linux/WSL/macOS) o scripts/publish.ps1 (Windows PowerShell): creano dist/win-x64/ e dist/linux-x64/ (dist/ è ignorata da git); i due script vanno tenuti allineati, oppure a mano dotnet publish src/agent-wiki-ui -c Release -r win-x64 --self-contained -p:PublishSingleFile=true e -r linux-x64
  • Test: dotnet test dalla radice (xUnit v3 + Avalonia.Headless con Skia reale; tests/FakeClaude è il claude finto per i test di processo). Per ora coprono solo le immagini del renderer (MD-14, MD-19…MD-30); il resto è pianificato in docs/TESTING.md (Fase 6). Per verificare la GUI senza schermo si può usare Avalonia.Headless con CaptureRenderedFrame() in un progetto di prova fuori dal repo.

Architettura

Decisioni e motivazioni negli ADR (docs/adr/); qui solo la mappa del codice.

  • Program.cs: top-level statements. Con argomenti è la CLI (EngineRunner.RunInherited, motore scelto con --engine <id> come primo argomento, default Claude Code); senza avvia Avalonia (App).
  • Core/Engine.cs: astrazione "motore" (ADR-0002): Engine (id, nome, eseguibile, modelli, effort, BuildArgs, Parse, FetchLatestVersionAsync per il controllo delle versioni), ClaudeEngine, CodexEngine, registro Engines e ricerca nel PATH (PathSearch). Gli elenchi modelli sono fissi, da aggiornare quando ne escono di nuovi; DefaultModelId indica il modello più piccolo, scelto all'avvio insieme a effort low (se esce un modello più piccolo, aggiornarlo).
  • Core/EngineRunner.cs: unico punto di avvio dei motori (cartella dell'exe, stdin chiuso, ArgumentList): CLI con output ereditato, GUI con output catturato e interpretato da Engine.Parse, e RunToolAsync per i comandi di servizio (--version, update) con tempo massimo.
  • Core/EngineUpdater.cs: controllo delle versioni in sola lettura (CheckAsync, IsNewer) e aggiornamento di un CLI con il suo update ufficiale (ADR-0004): versione prima/dopo, esito leggibile, metodo di installazione dedotto dal percorso reale e comando manuale da suggerire (l'app lo mostra, non lo esegue).
  • Core/ChatStore.cs: cronologia, un JSON per chat in <LocalApplicationData>/<nome-app>/chats/<guid>.json (nome file = id della chat, validato come Guid prima dell'uso; campi Engine e SessionId opzionali: i file vecchi sono chat di Claude Code).
  • Core/AppInfo.cs: nome dell'app, letto dall'AssemblyName del csproj (unica sorgente).
  • Gui/MainViewModel.cs: stato e logica della chat (invio, apertura/eliminazione, salvataggio subito all'invio e di nuovo alla risposta, riapertura dell'ultima chat all'avvio, interruttore CLI: cambiare motore apre una nuova chat; aggiornamento dei CLI con un solo aggiornamento alla volta, bloccando invio e cambio motore).
  • Gui/MainWindow.axaml (+ .cs): layout XAML con binding compilati. Gui/App.axaml: token di colore come risorse di tema chiaro/scuro e stili; specifiche in docs/MVP.md → "Design (UI/UX)". Cambiando l'aspetto aggiornare quella sezione.
  • Gui/MarkdownView.cs: renderer markdown proprio (albero Markdig → controlli Avalonia, DisableHtml); la parte sulle immagini è in Gui/MarkdownView.Images.cs (partial). Le immagini si mostrano solo da file locale (ADR-0006), mai da URL; i percorsi relativi si cercano nella cartella dell'exe e poi nelle superiori (radice della wiki).
  • Dipendenze NuGet: Avalonia (+ Desktop, Themes.Fluent), Markdig.

Vincoli non ovvi

  • La working directory di claude deve essere la cartella dell'exe: usare AppContext.BaseDirectory, mai Environment.CurrentDirectory né Assembly.Location (vuoto in single-file).
  • Lo stdin del motore va redirezionato e chiuso subito: claude aspetta 3 s, codex stampa "Reading additional input from stdin…" e attende.
  • claude è un eseguibile nativo (~/.local/bin), avviabile direttamente. Se fosse claude.cmd (Windows) serve cmd.exe /c.
  • Codex (CodexEngine): l'id di sessione lo genera Codex e si legge da thread.started nell'output JSONL (--json); la risposta è l'ultimo agent_message; exec resume non accetta -s, la sola lettura si impone con -c 'sandbox_mode="read-only"'; serve --skip-git-repo-check (la cartella dell'exe non è un repository); -- prima del prompt. Dettagli e prove in ADR-0002. Il modello predefinito è quello di ~/.codex/config.toml: se richiede un Codex più recente l'errore compare nella chat (vedi docs/INSTALL.md).
  • Il controllo delle versioni contatta solo downloads.claude.ai (Claude Code) e api.github.com (Codex, serve lo User-Agent), al massimo ogni 5 minuti e in background; un errore di rete non è un errore dell'app (stato "sconosciuto").
  • L'aggiornamento di un CLI è sempre un gesto esplicito dell'utente (pulsante Aggiorna): nessun aggiornamento automatico e nessun fallback che esegua npm/brew/winget al posto suo.
  • Windows: l'eseguibile è WinExe (nessuna console al doppio clic); in modalità CLI Core/ConsoleHost.cs riaggancia il terminale padre con AttachConsole e collega stdout/stderr a CONOUT$ solo se non sono già reindirizzati (ADR-0005). Il codice deve poter fallire in silenzio senza terminale. Conseguenza: su Windows l'exit code della CLI arriva solo se il chiamante attende il processo.
  • Il nome dell'app non va scritto a mano nel codice: usare AppInfo.Name. Cambiare nome cambia la cartella dati (vedi checklist in docs/README.md; ChatStore migra le cartelle dei nomi precedenti).
  • Avalonia 12: la clipboard si usa con using Avalonia.Input.Platform; (SetTextAsync è un'estensione); TextBox.Watermark è obsoleto, usare PlaceholderText.
  • Nel renderer markdown i colori si risolvono al momento del rendering (TryFindResource con ActualThemeVariant) e la vista si ricostruisce al cambio di tema.
  • I link nel markdown si aprono con hit-test sul testo (TextLayout.HitTestPoint) solo se http(s) e se non c'è una selezione in corso.
  • Il publish single-file richiede IncludeNativeLibrariesForSelfExtract (nel csproj): Skia e HarfBuzz sono librerie native.

Skill del repo

.claude/settings.json abilita il plugin ui-ux-pro-max (marketplace nextlevelbuilder/ui-ux-pro-max-skill). Usarlo per le modifiche alla GUI Avalonia (layout, usabilità, accessibilità).

Commit

Messaggi di commit in italiano: titolo breve all'indicativo o in forma nominale, eventuale corpo che spiega il perché. Mantenere la riga finale Co-Authored-By prevista dall'ambiente. Fare commit solo su richiesta.