Documentazione: aggiornamento dei CLI con controllo preventivo (ADR-0004)
Nuovo ADR-0004: dalle Impostazioni l'app controlla se Claude Code e Codex hanno una versione più recente (sorgenti ufficiali, cache di 5 minuti), evidenzia il pulsante Aggiorna solo se serve e lo esegue con il comando ufficiale, mostrando l'esito e il comando manuale adatto al metodo di installazione. MVP, ROADMAP, INSTALL, README, CLAUDE.md e la matrice di TESTING.md (righe UP) sono allineati; rimossi riferimenti obsoleti a WinForms e RunClaude. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e60d64ed58
commit
6498e45a0d
9 files changed
+125
-7
No files matched your search
@@ -24,11 +24,12 @@ agent-wiki-ui (già `LlmRun`; il nome ha un'unica sorgente, vedi [docs/README.md
|
||||
Decisioni e motivazioni negli ADR ([docs/adr/](docs/adr/)); qui solo la mappa del codice.
|
||||
|
||||
- [Program.cs](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](Core/Engine.cs): astrazione "motore" (ADR-0002): `Engine` (id, nome, eseguibile, modelli, effort, `BuildArgs`, `Parse`), `ClaudeEngine`, `CodexEngine`, registro `Engines` e ricerca nel PATH (`PathSearch`). Gli elenchi modelli sono fissi, da aggiornare quando ne escono di nuovi.
|
||||
- [Core/EngineRunner.cs](Core/EngineRunner.cs): **unico punto di avvio dei motori** (cartella dell'exe, stdin chiuso, `ArgumentList`), CLI con output ereditato e GUI con output catturato e interpretato da `Engine.Parse`.
|
||||
- [Core/Engine.cs](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.
|
||||
- [Core/EngineRunner.cs](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](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](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](Core/AppInfo.cs): nome dell'app, letto dall'`AssemblyName` del csproj (unica sorgente).
|
||||
- [Gui/MainViewModel.cs](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).
|
||||
- [Gui/MainViewModel.cs](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](Gui/MainWindow.axaml) (+ `.cs`): layout XAML con binding compilati. [Gui/App.axaml](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](Gui/MarkdownView.cs): renderer markdown proprio (albero Markdig → controlli Avalonia, `DisableHtml`).
|
||||
- Dipendenze NuGet: Avalonia (+ Desktop, Themes.Fluent), Markdig.
|
||||
@@ -39,6 +40,8 @@ Decisioni e motivazioni negli ADR ([docs/adr/](docs/adr/)); qui solo la mappa de
|
||||
- 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.
|
||||
- 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.
|
||||
@@ -47,7 +50,7 @@ Decisioni e motivazioni negli ADR ([docs/adr/](docs/adr/)); qui solo la mappa de
|
||||
|
||||
## 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 WinForms (layout, usabilità, accessibilità).
|
||||
`.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
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Eseguibile C# (.NET 10, Windows e Linux) che lancia Claude Code (`claude -p`) o
|
||||
|
||||
## Uso
|
||||
|
||||
GUI (nessun argomento): finestra di chat in stile claude.ai, con la conversazione in markdown in alto e il campo messaggio in basso (`Invio` invia, `Maiusc+Invio` va a capo, "Nuova chat" azzera il contesto). Il riquadro **Impostazioni** (in alto a destra) permette di scegliere la **CLI** (Claude Code o Codex), il **modello** e l'**effort** di ragionamento ("Predefinito" = nessun flag, vale la config del motore). Le chat si salvano su disco e l'ultima si riapre all'avvio.
|
||||
GUI (nessun argomento): finestra di chat in stile claude.ai, con la conversazione in markdown in alto e il campo messaggio in basso (`Invio` invia, `Maiusc+Invio` va a capo, "Nuova chat" azzera il contesto). Il riquadro **Impostazioni** (in alto a destra) permette di scegliere la **CLI** (Claude Code o Codex), il **modello** e l'**effort** di ragionamento ("Predefinito" = nessun flag, vale la config del motore). Le chat si salvano su disco e l'ultima si riapre all'avvio. Sempre nel riquadro, la sezione **Aggiornamenti** dice se Claude Code e Codex hanno una versione nuova (pulsante evidenziato) e li aggiorna uno alla volta.
|
||||
```
|
||||
dotnet run
|
||||
```
|
||||
|
||||
@@ -73,6 +73,18 @@ codex exec --help # uso non interattivo, usato dall'app
|
||||
|
||||
**Problema noto: "requires a newer version of Codex".** Se il modello predefinito del tuo `~/.codex/config.toml` richiede un Codex più recente, `codex exec` fallisce con quell'errore (l'app lo mostra nella chat). Aggiorna con `codex update`, oppure scegli un altro modello nelle Impostazioni dell'app. Controllato su questa macchina il 2026-10-15 con Codex 0.144.3.
|
||||
|
||||
## Aggiornare un CLI dall'app
|
||||
Nel riquadro Impostazioni, sezione **Aggiornamenti**, l'app controlla da sola, all'avvio e all'apertura del riquadro, se c'è una versione più recente (Claude Code: `downloads.claude.ai`; Codex: release di GitHub): se c'è, la riga dice "Aggiornamento disponibile", il pulsante **Aggiorna** si evidenzia e compare un puntino sul pulsante Impostazioni. Il pulsante esegue `claude update` o `codex update` (controllano e installano solo se c'è una versione nuova). Nulla si aggiorna senza un clic. Se non va a buon fine l'app mostra l'errore e il comando manuale, che dipende da come hai installato il CLI:
|
||||
|
||||
| Installazione | Claude Code | Codex |
|
||||
|---|---|---|
|
||||
| npm | `npm install -g @anthropic-ai/claude-code@latest` | `npm install -g @openai/codex@latest` |
|
||||
| Homebrew | `brew upgrade claude-code` | `brew upgrade --cask codex` |
|
||||
| WinGet | `winget upgrade Anthropic.ClaudeCode` | reinstalla con lo script PowerShell |
|
||||
| Nativo / script | `claude update` | `codex update` (o rilancia lo script di installazione) |
|
||||
|
||||
Dettagli e decisioni: [ADR-0004](adr/0004-aggiornamento-dei-cli.md).
|
||||
|
||||
## Controllo finale per l'app
|
||||
Dallo stesso terminale da cui avvii l'app:
|
||||
```
|
||||
|
||||
@@ -25,6 +25,7 @@ Senza argomenti si apre una finestra Avalonia (C# + XAML, nessun HTML) in stile
|
||||
- **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). 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](adr/0004-aggiornamento-dei-cli.md).
|
||||
- **Motori** ([ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md)): 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/share` su Linux; vedi [Nome del progetto](README.md#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.
|
||||
|
||||
@@ -39,3 +39,4 @@ Se il nome cambia di nuovo, aggiornare solo questi punti:
|
||||
| [0001](adr/0001-gui-multipiattaforma-avalonia.md) | GUI multipiattaforma in solo C# con Avalonia | Accettata |
|
||||
| [0002](adr/0002-motori-cli-claude-codex-antigravity.md) | Più motori CLI (Claude Code, Codex, Antigravity) su Windows e Linux | Accettata (Claude Code, Codex) |
|
||||
| [0003](adr/0003-strategia-di-test.md) | Strategia di test e regola "nuova funzione = nuovi test" | Proposta |
|
||||
| [0004](adr/0004-aggiornamento-dei-cli.md) | Aggiornamento dei CLI dalle Impostazioni | Proposta |
|
||||
+4
-1
@@ -26,7 +26,7 @@ Dettagli dell'MVP in [MVP.md](MVP.md).
|
||||
- [ ] Test automatici e CI (vedi Fase 6)
|
||||
|
||||
## Fase 4 — Più motori (Claude Code, Codex, Antigravity)
|
||||
Decisione, tabella dei comandi e rischi: [ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md). Qui solo i passi. Va fatta dopo (o insieme a) la Fase 5, che estrae il punto unico di avvio processo.
|
||||
Decisione, tabella dei comandi e rischi: [ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md). Qui solo i passi. Il punto unico di avvio processo l'ha estratto la Fase 5.
|
||||
|
||||
- [x] Verificare i flag reali di `codex` (provati su Linux/WSL, ADR-0002 accettata per Claude Code e Codex); `agy` e Windows da verificare
|
||||
- [x] Astrazione "motore" in C# (`Core/Engine.cs`, `Core/EngineRunner.cs`)
|
||||
@@ -39,6 +39,9 @@ Decisione, tabella dei comandi e rischi: [ADR-0002](adr/0002-motori-cli-claude-c
|
||||
- [x] Permessi di Codex in sola lettura (nessun flag che salta i controlli)
|
||||
- [ ] Opzione esplicita per concedere permessi di scrittura
|
||||
- [x] CLI: opzione `--engine`, coerente con la GUI
|
||||
- [x] Aggiornamento dei CLI dalle Impostazioni, un pulsante per CLI con `update` ufficiale ed esito leggibile ([ADR-0004](adr/0004-aggiornamento-dei-cli.md))
|
||||
- [x] Controllo preventivo della versione più recente (sorgenti ufficiali, cache di 5 minuti); pulsante Aggiorna evidenziato e puntino sul pulsante Impostazioni solo se c'è una versione nuova
|
||||
- [ ] Provare gli aggiornamenti reali (finora provati solo con CLI finti, e rilevamento del metodo di installazione sui percorsi reali) su Linux e Windows (installazione nativa e npm) e portare l'ADR-0004 ad "Accettata"
|
||||
|
||||
## Fase 5 — Multipiattaforma (Windows + Linux), GUI in solo C#
|
||||
Decisione e motivazioni: [ADR-0001](adr/0001-gui-multipiattaforma-avalonia.md). Qui solo i passi.
|
||||
|
||||
@@ -32,6 +32,7 @@ tests/FakeClaude/ eseguibile finto: registra argv/cwd/stdin; testo,
|
||||
## Predisposizioni di testabilità (prerequisito dei test)
|
||||
- [ ] `ChatStore` come istanza con cartella iniettata (oggi statico su `LocalApplicationData`)
|
||||
- [ ] `IEngineRunner` dietro `Core/EngineRunner.cs`, iniettato nel `MainViewModel`
|
||||
- [x] `EngineUpdater.CheckAsync` accetta un `HttpClient`: i test usano un gestore finto (rete assente, risposta non valida, versioni di prova)
|
||||
- [ ] `InternalsVisibleTo` verso il progetto di test
|
||||
- [ ] Spostamento in `src/` e `tests/` con soluzione unica
|
||||
|
||||
@@ -82,6 +83,31 @@ Le righe CL valgono per ogni motore; queste sono specifiche di Codex (ADR-0002).
|
||||
| CX-11 | In modalità CLI (output ereditato) non si usa `--json` | U | `Codex_cli_senza_json` | [ ] |
|
||||
| CX-12 | Con un `FakeClaude` configurato come Codex il ciclo primo messaggio + ripresa funziona (id letto e riusato) | P | `Codex_ciclo_completo_con_finto` | [ ] |
|
||||
|
||||
### Aggiornamento dei CLI — `Core/EngineUpdater.cs`, `Gui/MainViewModel.cs` (ADR-0004)
|
||||
Si provano con `FakeClaude`/`FakeCodex` che rispondono a `--version` e `update`; nessun test aggiorna un CLI reale.
|
||||
| ID | Requisito | Liv. | Test | |
|
||||
|---|---|---|---|---|
|
||||
| UP-01 | Versione letta da `--version` (prima riga ripulita); eseguibile assente ⇒ versione nulla | P | `Versione_letta` | [ ] |
|
||||
| UP-02 | Versione cambiata dopo `update` ⇒ esito "Aggiornato da X a Y" | P | `Aggiornato` | [ ] |
|
||||
| UP-03 | Exit 0 e versione invariata ⇒ "Già aggiornato (X)" | P | `Gia_aggiornato` | [ ] |
|
||||
| UP-04 | Exit ≠ 0 ⇒ errore con le ultime righe dell'output e il comando manuale | P | `Aggiornamento_fallito` | [ ] |
|
||||
| UP-05 | Tempo massimo superato ⇒ processo terminato ed errore chiaro | P | `Aggiornamento_scaduto` | [ ] |
|
||||
| UP-06 | Eseguibile assente ⇒ riga non offerta / errore "non trovato" | U | `Aggiornamento_senza_eseguibile` | [ ] |
|
||||
| UP-07 | Metodo di installazione dedotto dal percorso reale (npm, Homebrew, WinGet, nativo) con collegamenti simbolici risolti | U | `Metodo_di_installazione` | [ ] |
|
||||
| UP-08 | Comando manuale corretto per ogni coppia motore × metodo (tabella dell'ADR-0004) | U | `Comando_manuale` | [ ] |
|
||||
| UP-09 | Un solo aggiornamento alla volta; durante una risposta in corso i pulsanti sono disabilitati e la chat non parte durante l'aggiornamento | U | `Aggiornamento_esclusivo` | [ ] |
|
||||
| UP-10 | Dopo un aggiornamento riuscito le versioni mostrate si rileggono; la chat aperta resta invariata | U | `Versioni_rilette` | [ ] |
|
||||
| UP-11 | Le righe di aggiornamento compaiono solo per i CLI installati | U/G | `Righe_solo_installati` | [ ] |
|
||||
| UP-12 | Il pulsante Aggiorna del riquadro agisce solo sul CLI della sua riga | G | `Pulsante_per_riga` | [ ] |
|
||||
| UP-13 | Nessun aggiornamento parte senza un clic | U | `Nessun_aggiornamento_automatico` | [ ] |
|
||||
| UP-14 | Claude Code: l'ultima versione si legge dal testo di `…/claude-code-releases/latest` (spazi e a capo ripuliti) | U | `Ultima_versione_claude` | [ ] |
|
||||
| UP-15 | Codex: l'ultima versione si legge da `tag_name` della release GitHub (`rust-v0.162.1` ⇒ 0.162.1); intestazione User-Agent inviata | U | `Ultima_versione_codex` | [ ] |
|
||||
| UP-16 | Confronto: ultima > installata ⇒ disponibile; uguale o più nuova ⇒ aggiornato; versioni con testo attorno (`2.1.300 (Claude Code)`, `codex-cli 0.162.1`) lette bene | U | `Confronto_versioni` | [ ] |
|
||||
| UP-17 | Rete assente, risposta non valida o timeout ⇒ stato "sconosciuto", nessuna eccezione, pulsante normale | U | `Controllo_senza_rete` | [ ] |
|
||||
| UP-18 | Disponibile ⇒ riga con "Aggiornamento disponibile: X", pulsante evidenziato e puntino sul pulsante Impostazioni; aggiornato ⇒ nessuno dei tre | U/G | `Evidenziazione_aggiornamento` | [ ] |
|
||||
| UP-19 | Il controllo parte all'avvio e all'apertura del riquadro solo se l'ultimo ha più di 5 minuti; dopo un aggiornamento riuscito si ripete; non blocca invio né interfaccia | U | `Quando_si_controlla` | [ ] |
|
||||
| UP-20 | Il controllo non installa nulla e non modifica i CLI | P | `Controllo_in_sola_lettura` | [ ] |
|
||||
|
||||
### Cronologia — `Core/ChatStore.cs`, `Core/AppInfo.cs`
|
||||
| ID | Requisito | Liv. | Test | |
|
||||
|---|---|---|---|---|
|
||||
|
||||
@@ -14,7 +14,7 @@ L'app lancia solo `claude -p`. Si vuole usare dalla stessa chat anche **OpenAI C
|
||||
4. Nessuna scorciatoia che disattivi i controlli di permesso senza una scelta esplicita dell'utente.
|
||||
|
||||
## Decisione
|
||||
- **Astrazione "motore"** in C#. Ogni motore descrive: nome e eseguibile, argomenti per il primo messaggio e per la ripresa, elenco modelli, supporto effort, modo per ottenere l'id di sessione. `RunClaude` diventa `RunEngine(engine, …)`.
|
||||
- **Astrazione "motore"** in C#. Ogni motore descrive: nome e eseguibile, argomenti per il primo messaggio e per la ripresa, elenco modelli, supporto effort, modo per ottenere l'id di sessione. `RunClaude` è diventato `EngineRunner` con il motore come parametro.
|
||||
- **Rilevamento** dei motori cercando l'eseguibile nel PATH (su Windows anche le estensioni di PATHEXT). I motori assenti sono disabilitati nelle Impostazioni, con messaggio chiaro; la CLI esce con 127 come oggi.
|
||||
- **Una chat = un motore**. Il file JSON della chat memorizza il motore; il contesto di sessione non passa da un motore all'altro, quindi cambiare motore apre una nuova chat.
|
||||
- **Impostazioni** nella GUI: interruttore **CLI** (motore attivo), modello, effort. Cambiare motore apre una nuova chat; modello ed effort tornano a "Predefinito" e le liste sono quelle del motore. La persistenza su disco delle impostazioni è rinviata. La CLI ottiene `--engine <id>` (`claude`, `codex`).
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# ADR-0004 — Aggiornamento dei CLI dalle Impostazioni
|
||||
|
||||
- **Stato**: Proposta
|
||||
- **Data**: 2026-10-15
|
||||
- **Collegato a**: [ADR-0002](0002-motori-cli-claude-codex-antigravity.md) (motori), [INSTALL.md](../INSTALL.md)
|
||||
|
||||
## Contesto
|
||||
L'app usa i CLI già installati dall'utente. Un CLI vecchio può smettere di funzionare senza che l'app c'entri: su questa macchina Codex 0.144.3 ha come modello predefinito (`~/.codex/config.toml`) `gpt-6-astra`, che richiede un Codex più recente, e ogni messaggio con "Predefinito" fallisce con `requires a newer version of Codex`. L'unico rimedio è aggiornare il CLI, oggi da terminale, e l'utente non sa nemmeno che esiste una versione nuova.
|
||||
|
||||
Sulla macchina di sviluppo il 2026-10-15 i due CLI sono stati poi aggiornati (Codex 0.144.3 → 0.162.1, Claude Code 2.1.252 → 2.1.300) e Codex con il modello predefinito risponde: il problema si risolve aggiornando. Resta il bisogno di saperlo e di farlo dall'app.
|
||||
|
||||
Entrambi i CLI hanno un comando di aggiornamento che controlla e, se c'è una versione nuova, la installa: `claude update` (alias `upgrade`: "Check for updates and install if available") e `codex update` ("Update Codex to the latest version"). Verificato con `--help` il 2026-10-15; l'esecuzione reale non è ancora stata provata.
|
||||
|
||||
## Criteri di decisione
|
||||
1. L'app dice se c'è una versione nuova **prima** di proporre l'aggiornamento: evidenzia solo dove serve.
|
||||
1. L'utente aggiorna un CLI alla volta, senza uscire dall'app.
|
||||
2. L'app non tocca nulla senza un gesto esplicito (nessun aggiornamento automatico).
|
||||
3. Si usa il comando ufficiale del CLI, non una procedura inventata dall'app.
|
||||
4. Se l'aggiornamento non è possibile (installazione via gestore di pacchetti, permessi, rete) l'utente vede il motivo e il comando manuale giusto.
|
||||
5. Funziona su Windows e Linux e non blocca la GUI.
|
||||
|
||||
## Decisione
|
||||
- Nel riquadro Impostazioni, sezione **Aggiornamenti**: una riga per ogni CLI installato con nome, versione e pulsante **Aggiorna**. Ogni pulsante agisce solo su quel CLI.
|
||||
- **Controllo prima dell'aggiornamento** (sola lettura, nessuna installazione): l'app confronta la versione installata (`<cli> --version`) con l'ultima pubblicata.
|
||||
- Claude Code: `GET https://downloads.claude.ai/claude-code-releases/latest`, testo con la versione (la stessa sorgente dell'installer nativo).
|
||||
- Codex: `GET https://api.github.com/repos/openai/codex/releases/latest`, campo `tag_name` (es. `rust-v0.162.1`, si estrae `0.162.1`).
|
||||
- Le versioni si ricavano con il primo numero `N.N.N` del testo e si confrontano come versioni. Verificate il 2026-10-15: restituivano 2.1.300 e 0.162.1.
|
||||
- **Disponibile** (ultima > installata): la riga mostra "Aggiornamento disponibile: X", il pulsante Aggiorna è **evidenziato** (colore d'accento) e un puntino d'accento compare sul pulsante Impostazioni. **Aggiornato** (uguale o più nuova): riga neutra con "Aggiornato", pulsante normale, nessun puntino; resta cliccabile per forzare `update`. **Sconosciuto** (rete assente, risposta non valida, timeout di 10 s): "Controllo non riuscito", pulsante normale, nessun errore invasivo.
|
||||
- Quando si controlla: all'avvio, in background, e ogni volta che si apre il riquadro Impostazioni se l'ultimo controllo ha più di 5 minuti; subito dopo un aggiornamento. Mai in modo da rallentare la chat. Le richieste non inviano identificativi; l'app contatta solo i due indirizzi sopra.
|
||||
- **Flusso** di un clic: legge la versione (`<cli> --version`), lancia `<cli> update` (stdin chiuso, output catturato, tempo massimo 10 minuti), rilegge la versione e mostra l'esito sulla riga:
|
||||
- versione cambiata ⇒ "Aggiornato da X a Y";
|
||||
- exit 0 e versione invariata ⇒ "Già aggiornato (X)";
|
||||
- exit ≠ 0, tempo scaduto o eseguibile assente ⇒ errore con le ultime righe dell'output e il **comando manuale** adatto (sotto).
|
||||
- Pulsanti disabilitati mentre una risposta è in corso o un altro aggiornamento è attivo; la chat non parte durante l'aggiornamento.
|
||||
- **Comando manuale** scelto dal metodo di installazione, dedotto dal percorso reale dell'eseguibile (collegamenti simbolici risolti):
|
||||
|
||||
| Percorso contiene | Metodo | Claude Code | Codex |
|
||||
|---|---|---|---|
|
||||
| `node_modules`, `.npm` | npm | `npm install -g @anthropic-ai/claude-code@latest` | `npm install -g @openai/codex@latest` |
|
||||
| `Cellar`, `homebrew`, `linuxbrew` | Homebrew | `brew upgrade claude-code` (o `claude-code@latest`) | `brew upgrade --cask codex` |
|
||||
| `WinGet`, `WindowsApps` | WinGet | `winget upgrade Anthropic.ClaudeCode` | script PowerShell di [INSTALL.md](../INSTALL.md) |
|
||||
| altro | nativo/script | `claude update` da terminale | script di installazione di [INSTALL.md](../INSTALL.md) |
|
||||
|
||||
L'app **mostra** il comando, non lo esegue: un'installazione globale con npm o un gestore di pacchetti può richiedere permessi o scelte che spettano all'utente.
|
||||
- Dopo un aggiornamento riuscito le versioni mostrate si rileggono; la chat aperta non cambia.
|
||||
- L'aggiornamento di un CLI non rilancia la chat in corso: l'eventuale errore di versione già mostrato resta nella cronologia.
|
||||
|
||||
## Opzioni considerate
|
||||
| Opzione | Esito | Motivo |
|
||||
|---|---|---|
|
||||
| Solo documentare `codex update` | Scartata | L'utente deve uscire dall'app e conoscere il comando. |
|
||||
| Solo `update`, senza controllo preventivo | Scartata | Non dice se serve e non può evidenziare il pulsante: `update` controlla ma installa subito. |
|
||||
| Controllo con `npm view` | Scartata | Richiede npm anche per installazioni native. |
|
||||
| Aggiornamento automatico all'avvio | Scartata | Modifica programmi dell'utente senza un suo gesto. |
|
||||
| Fallback automatico a npm/brew/winget | Scartata | Permessi (`sudo`), scelta del canale e rischi di installazioni doppie spettano all'utente. |
|
||||
| **Controllo con le sorgenti ufficiali (annuncio delle versioni) + pulsante per CLI con `update` ufficiale + comando manuale suggerito** | **Scelta** | Ufficiale, sicura, uguale su Windows e Linux, evidenzia solo quando serve. |
|
||||
|
||||
## Conseguenze
|
||||
**Positive**: il caso "richiede un Codex più recente" si risolve dall'app; l'esito è comprensibile; nessuna azione nascosta.
|
||||
**Negative / costi**: il controllo richiede rete e due indirizzi esterni (GitHub ha un limite di richieste anonime, per questo c'è la cache di 5 minuti); il canale scelto da Claude Code (`latest` o `stable`) può dare un "disponibile" che `claude update` non installa, e in quel caso l'esito dopo l'aggiornamento è "Già aggiornato"; l'esito dipende dal testo e dal comportamento dei comandi `update` dei CLI, che possono cambiare; su Windows l'aggiornamento di un eseguibile in uso da un'altra sessione può fallire; un controllo della versione senza installare non c'è.
|
||||
|
||||
## Da verificare
|
||||
- [ ] Il controllo evidenzia correttamente in tutti i casi (installato più vecchio, uguale, più nuovo di `latest`) e senza rete.
|
||||
- [ ] Utente sul canale `stable` di Claude Code: il confronto con `latest` dà falsi "disponibile"; valutare di leggere anche `/stable` o `autoUpdatesChannel`.
|
||||
- [ ] Esecuzione reale di `claude update` e `codex update` su Linux e Windows, con installazione nativa e con npm: esito, exit code e testo. (Su Linux/WSL i due CLI risultano aggiornati alle ultime versioni; non è stato registrato l'output.)
|
||||
- [ ] Cosa stampano quando sono già aggiornati e quando falliscono per permessi.
|
||||
- [ ] Che `--version` di entrambi si possa leggere in un secondo dopo l'aggiornamento (nessun file bloccato).
|
||||
- [ ] Il tempo massimo di 10 minuti è adeguato (rete lenta).
|
||||
|
||||
## Riferimenti
|
||||
- Passi: [ROADMAP.md](../ROADMAP.md), Fase 4.
|
||||
- Matrice dei test: [TESTING.md](../TESTING.md), righe UP.
|
||||
Reference in new issue
Block a user