Aggiunto supporto al motore CLI Antigravity (agy)
This commit is contained in:
1 parent
67d91e6a1f
commit
6bbaf7192f
12 files changed
+199
-69
No files matched your search
@@ -4,7 +4,7 @@ Guida per gli agenti di codice (Claude Code, Gemini CLI, altri) che lavorano in
|
||||
|
||||
## Progetto
|
||||
|
||||
agent-wiki-ui (già `LlmRun`; il nome ha un'unica sorgente, vedi [docs/README.md](docs/README.md#nome-del-progetto)): 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.
|
||||
agent-wiki-ui (già `LlmRun`; il nome ha un'unica sorgente, vedi [docs/README.md](docs/README.md#nome-del-progetto)): eseguibile C# (.NET 10, Windows e Linux) che invoca Claude Code (`claude -p`), Codex (`codex exec`) o Antigravity (`agy … -p`) da terminale. Senza argomenti apre una GUI di chat Avalonia, con argomenti funziona da CLI.
|
||||
|
||||
## Workflow doc-first (obbligatorio)
|
||||
|
||||
@@ -24,7 +24,7 @@ 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`, `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/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`, `AgyEngine`, 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](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).
|
||||
@@ -37,10 +37,11 @@ Decisioni e motivazioni negli ADR ([docs/adr/](docs/adr/)); qui solo la mappa de
|
||||
## 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`.
|
||||
- Lo stdin del motore va redirezionato e chiuso subito: `claude` aspetta 3 s, `codex` stampa "Reading additional input from stdin…" e attende, `agy` può bloccarsi su output rediretto (issue #318).
|
||||
- `claude` e `agy` sono eseguibili nativi (`~/.local/bin`, `~/.gemini/bin`), avviabili direttamente. Se fossero script `.cmd` (Windows) servirebbe `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").
|
||||
- Antigravity (`AgyEngine`): eseguibile `agy`; tutti i flag di configurazione vanno passati prima di `-p <prompt>`; per usare `agy` in modalità non interattiva (`-p`) in sola lettura, nel file `~/.gemini/antigravity-cli/settings.json` deve essere presente la regola `'read_file(*)'` sotto `'permissions.allow'` (altrimenti headless mode nega `read_file` con errore jetski: 'jetski: no output produced - a tool required the read_file permission that headless mode cannot prompt for'), mentre scritture e comandi restano negati di default; non passare `--mode plan` né `--mode auto` e mai usare `--dangerously-skip-permissions`; per la GUI si usa `--output-format json` e l'id di sessione si legge da `conversation_id` (`OwnsSessionId => true`); la ripresa della conversazione usa `--conversation <id>`; per evitare il blocco su sottoprocesso con output rediretto (issue #318) si passa `--print-timeout 120s` e si chiude immediatamente lo stdin.
|
||||
- Il controllo delle versioni contatta solo `downloads.claude.ai` (Claude Code), `api.github.com` (Codex, serve lo User-Agent) e `antigravity-cli-auto-updater-974169037036.us-central1.run.app` (Antigravity), 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).
|
||||
|
||||
+80
-1
@@ -1,4 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace AgentWikiUi.Core;
|
||||
@@ -159,11 +160,89 @@ sealed class CodexEngine : Engine
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AgyEngine : Engine
|
||||
{
|
||||
public override string Id => "agy";
|
||||
public override string Name => "Antigravity";
|
||||
public override string Author => "Antigravity";
|
||||
public override string Executable => "agy";
|
||||
public override bool OwnsSessionId => true;
|
||||
|
||||
public override ModelOption[] Models { get; } =
|
||||
[
|
||||
new("Gemini 3.0 Flash (Low)", "gemini-3.0-flash-low"),
|
||||
new("Gemini 3.0 Flash (Medium)", "gemini-3.0-flash-medium"),
|
||||
new("Gemini 3.0 Flash (High)", "gemini-3.0-flash-high"),
|
||||
new("Claude Sonnet 4.6 (Thinking)", "claude-sonnet-4-6"),
|
||||
new("Claude Opus 4.6 (Thinking)", "claude-opus-4-6-thinking"),
|
||||
new("GPT-OSS 120B (Medium)", "gpt-oss-120b-medium"),
|
||||
];
|
||||
|
||||
public override string[] Efforts { get; } = ["low", "medium", "high", "xhigh", "max"];
|
||||
public override string DefaultModelId => "gemini-3.0-flash-low";
|
||||
|
||||
public override List<string> BuildArgs(string prompt, string? sessionId, bool resume, string model, string effort, bool structured)
|
||||
{
|
||||
var args = new List<string>();
|
||||
if (structured) args.AddRange(["--output-format", "json"]);
|
||||
if (resume && sessionId is not null) args.AddRange(["--conversation", sessionId]);
|
||||
if (model != "") args.AddRange(["--model", model]);
|
||||
if (effort != "") args.AddRange(["--effort", effort]);
|
||||
args.AddRange(["--print-timeout", "120s"]);
|
||||
args.AddRange(["-p", prompt]); // tutti i flag vanno passati PRIMA di -p
|
||||
return args;
|
||||
}
|
||||
|
||||
public override EngineReply Parse(int code, string stdout, string stderr)
|
||||
{
|
||||
string? conversationId = null;
|
||||
string? response = null;
|
||||
string? error = null;
|
||||
|
||||
var trimmed = stdout.Trim();
|
||||
if (!string.IsNullOrEmpty(trimmed))
|
||||
{
|
||||
var start = trimmed.IndexOf('{');
|
||||
var end = trimmed.LastIndexOf('}');
|
||||
if (start >= 0 && end > start)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(trimmed.Substring(start, end - start + 1));
|
||||
var root = doc.RootElement;
|
||||
if (root.TryGetProperty("conversation_id", out var convProp))
|
||||
conversationId = convProp.GetString();
|
||||
if (root.TryGetProperty("response", out var respProp))
|
||||
response = respProp.GetString();
|
||||
if (root.TryGetProperty("status", out var statusProp) && statusProp.GetString() != "SUCCESS")
|
||||
error = $"Stato {statusProp.GetString()}";
|
||||
if (root.TryGetProperty("error", out var errProp))
|
||||
error = errProp.GetString() ?? error;
|
||||
}
|
||||
catch (JsonException) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (code != 0) return new("", conversationId, Failed(code, error ?? stderr.Trim()));
|
||||
if (error is not null && string.IsNullOrWhiteSpace(response)) return new("", conversationId, error);
|
||||
if (string.IsNullOrWhiteSpace(response)) return new("", conversationId, error ?? (string.IsNullOrWhiteSpace(stderr) ? "agy non ha restituito nessuna risposta." : stderr.Trim()));
|
||||
return new(response.Trim(), conversationId, null);
|
||||
}
|
||||
|
||||
public override async Task<string?> FetchLatestVersionAsync(HttpClient http, CancellationToken ct)
|
||||
{
|
||||
var text = await http.GetStringAsync("https://antigravity-cli-auto-updater-974169037036.us-central1.run.app", ct);
|
||||
var m = Regex.Match(text, @"Stable Version:\s*v?(\d+\.\d+(?:\.\d+)?)");
|
||||
return m.Success ? m.Groups[1].Value : text.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
static class Engines
|
||||
{
|
||||
public static readonly Engine Claude = new ClaudeEngine();
|
||||
public static readonly Engine Codex = new CodexEngine();
|
||||
public static readonly Engine[] All = [Claude, Codex];
|
||||
public static readonly Engine Agy = new AgyEngine();
|
||||
public static readonly Engine[] All = [Claude, Codex, Agy];
|
||||
|
||||
public static Engine? Find(string? id) => All.FirstOrDefault(e => e.Id == id);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,8 @@ static class EngineUpdater
|
||||
("codex", _) => OperatingSystem.IsWindows()
|
||||
? "powershell -ExecutionPolicy ByPass -c \"irm https://chatgpt.com/codex/install.ps1 | iex\""
|
||||
: "curl -fsSL https://chatgpt.com/codex/install.sh | sh",
|
||||
("agy", InstallMethod.Homebrew) => "brew upgrade agy",
|
||||
("agy", _) => "agy update",
|
||||
_ => $"{engine.Executable} update",
|
||||
};
|
||||
}
|
||||
@@ -1,23 +1,24 @@
|
||||
# agent-wiki-ui
|
||||
|
||||
Eseguibile C# (.NET 10, Windows e Linux) che lancia Claude Code (`claude -p`) o Codex (`codex exec`) nella cartella in cui risiede l'eseguibile. Senza argomenti apre una GUI di chat (Avalonia), con argomenti funziona da riga di comando.
|
||||
Eseguibile C# (.NET 10, Windows e Linux) che lancia Claude Code (`claude -p`), Codex (`codex exec`) o Antigravity (`agy … -p`) nella cartella in cui risiede l'eseguibile. Senza argomenti apre una GUI di chat (Avalonia), con argomenti funziona da riga di comando.
|
||||
|
||||
## Requisiti
|
||||
- `claude` (Claude Code) installato e nel PATH, già autenticato; per Codex lo stesso con `codex`. Istruzioni: [docs/INSTALL.md](docs/INSTALL.md)
|
||||
- `claude` (Claude Code), `codex` (Codex) o `agy` (Antigravity) installati e nel PATH, già autenticati. Istruzioni: [docs/INSTALL.md](docs/INSTALL.md)
|
||||
- Per sviluppare: .NET SDK 10
|
||||
- Per usare l'eseguibile pubblicato: nessun runtime (è self-contained). Su Linux serve un desktop con X11 o XWayland per la GUI.
|
||||
|
||||
## 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. All'avvio, e a ogni cambio di CLI, sono scelti il modello più piccolo (Haiku 5.5 per Claude Code, GPT-5.6 Luna per Codex) ed effort `low`, per risposte rapide e economiche; "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.
|
||||
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, Codex o Antigravity), il **modello** e l'**effort** di ragionamento. All'avvio, e a ogni cambio di CLI, sono scelti il modello più piccolo (Haiku 5.5 per Claude Code, GPT-5.6 Luna per Codex, Gemini 3.0 Flash Low per Antigravity) ed effort `low`, per risposte rapide e economiche; "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, Codex e Antigravity hanno una versione nuova (pulsante evidenziato) e li aggiorna uno alla volta.
|
||||
```
|
||||
dotnet run
|
||||
```
|
||||
|
||||
CLI (con argomenti): il prompt viene stampato su terminale, l'exit code è quello del motore (127 se non è nel PATH). Di default usa Claude Code; `--engine codex` usa Codex.
|
||||
CLI (con argomenti): il prompt viene stampato su terminale, l'exit code è quello del motore (127 se non è nel PATH). Di default usa Claude Code; `--engine codex` usa Codex; `--engine agy` usa Antigravity.
|
||||
```
|
||||
dotnet run -- "spiega questo progetto"
|
||||
dotnet run -- --engine codex "spiega questo progetto"
|
||||
dotnet run -- --engine agy "spiega questo progetto"
|
||||
```
|
||||
|
||||
## Creare gli eseguibili (Windows e Linux)
|
||||
@@ -59,10 +60,10 @@ Verificato: da Linux/WSL entrambi gli eseguibili; da Windows nativo (PowerShell
|
||||
- Windows: doppio clic su `agent-wiki-ui.exe` per la GUI (non si apre nessuna finestra di console), oppure da terminale `agent-wiki-ui.exe "prompt"` per la CLI. Da `cmd` o PowerShell il prompt torna subito e l'output compare dopo; per aspettare la fine e leggere l'exit code usa `start /wait agent-wiki-ui.exe "prompt"` (cmd) o `Start-Process -Wait -NoNewWindow agent-wiki-ui.exe "prompt"` (PowerShell); `& .\agent-wiki-ui.exe "prompt" | Out-Host` aspetta ma non dà l'exit code. Spiegazione in [ADR-0005](docs/adr/0005-windows-senza-console.md). Il file non è firmato: Windows può mostrare un avviso di sicurezza al primo avvio.
|
||||
- Linux: `chmod +x agent-wiki-ui` (se serve) e poi `./agent-wiki-ui`. La GUI richiede un desktop con X11 o XWayland.
|
||||
- Al primo avvio le librerie native (Skia, HarfBuzz) vengono estratte in una cartella temporanea: il primo avvio è un po' più lento.
|
||||
- I motori (`claude`, `codex`) devono essere installati e nel PATH dello stesso sistema: vedi [docs/INSTALL.md](docs/INSTALL.md).
|
||||
- I motori (`claude`, `codex`, `agy`) devono essere installati e nel PATH dello stesso sistema: vedi [docs/INSTALL.md](docs/INSTALL.md).
|
||||
|
||||
## Piattaforme
|
||||
Windows e Linux con lo stesso codice ([ADR-0001](docs/adr/0001-gui-multipiattaforma-avalonia.md)). Motori supportati: Claude Code e Codex CLI, già installati da terminale; Antigravity CLI è pianificato: [ADR-0002](docs/adr/0002-motori-cli-claude-codex-antigravity.md).
|
||||
Windows e Linux con lo stesso codice ([ADR-0001](docs/adr/0001-gui-multipiattaforma-avalonia.md)). Motori supportati: Claude Code, Codex CLI e Antigravity CLI, già installati da terminale: [ADR-0002](docs/adr/0002-motori-cli-claude-codex-antigravity.md).
|
||||
|
||||
> **Stato: MVP** (prima della 1.0): la parte funzionale c'è, i test automatici e alcune verifiche su macchine reali mancano. Dettagli in [docs/PROJECT_STATE.md](docs/PROJECT_STATE.md).
|
||||
|
||||
|
||||
+34
-16
@@ -1,4 +1,4 @@
|
||||
# Installare i motori (Claude Code e Codex)
|
||||
# Installare i motori (Claude Code, Codex, Antigravity)
|
||||
|
||||
L'app non installa né autentica i motori: lancia quelli che trova nel PATH, già installati e con l'accesso fatto ([ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md)). Questa pagina spiega come prepararli. Fonti e data di consultazione in fondo.
|
||||
|
||||
@@ -11,7 +11,7 @@ Il motore va installato **nello stesso ambiente in cui gira l'app**:
|
||||
| WSL (anche con `dotnet run`) | nel terminale della distribuzione WSL |
|
||||
| Windows (`.exe`) | in Windows (PowerShell), non in WSL |
|
||||
|
||||
Dentro WSL il PATH di Windows è visibile (compare `/mnt/c/…`): se in WSL non c'è un `claude` o un `codex`, il comando può risolvere nella versione Windows. Controllalo con `command -v claude` e `command -v codex`.
|
||||
Dentro WSL il PATH di Windows è visibile (compare `/mnt/c/…`): se in WSL non c'è un `claude`, `codex` o `agy`, il comando può risolvere nella versione Windows. Controllalo con `command -v claude`, `command -v codex` e `command -v agy`.
|
||||
|
||||
## Claude Code
|
||||
|
||||
@@ -73,32 +73,50 @@ 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:
|
||||
## Antigravity CLI (`agy`)
|
||||
|
||||
| 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) |
|
||||
**Requisiti**: Linux x64 (binario nativo ELF) o Windows x64 (eseguibile nativo `.exe`).
|
||||
|
||||
**Installazione**: binario nativo distribuito ufficialmente (su Linux collocato in `~/.gemini/bin/agy` o in una cartella inclusa nel PATH; su Windows `agy.exe`).
|
||||
|
||||
**Accesso**: autenticazione tramite account Google/Antigravity (`agy` o configurazione di ambiente).
|
||||
|
||||
**Verifica**
|
||||
```
|
||||
agy --version # stampa la versione, es. 1.4.2
|
||||
agy models # catalogo modelli disponibili
|
||||
agy update # controlla e aggiorna alla versione più recente
|
||||
```
|
||||
|
||||
**Permessi per la sola lettura non interattiva**: per usare `agy` in modalità non interattiva (`-p`) in sola lettura, nel file `~/.gemini/antigravity-cli/settings.json` deve essere presente la regola `'read_file(*)'` sotto `'permissions.allow'` (altrimenti headless mode nega `read_file` con errore jetski: `a tool required the read_file permission that headless mode cannot prompt for`), mentre scritture e comandi restano negati di default.
|
||||
|
||||
## 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; Antigravity: endpoint ufficiale di auto-update): se c'è, la riga dice "Aggiornamento disponibile", il pulsante **Aggiorna** si evidenzia e compare un puntino sul pulsante Impostazioni. Il pulsante esegue `claude update`, `codex update` o `agy 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 | Antigravity |
|
||||
|---|---|---|---|
|
||||
| npm | `npm install -g @anthropic-ai/claude-code@latest` | `npm install -g @openai/codex@latest` | `agy update` |
|
||||
| Homebrew | `brew upgrade claude-code` | `brew upgrade --cask codex` | `brew upgrade agy` |
|
||||
| WinGet | `winget upgrade Anthropic.ClaudeCode` | reinstalla con lo script PowerShell | `agy update` |
|
||||
| Nativo / script | `claude update` | `codex update` (o rilancia lo script di installazione) | `agy update` |
|
||||
|
||||
Dettagli e decisioni: [ADR-0004](adr/0004-aggiornamento-dei-cli.md).
|
||||
|
||||
## Controllo finale per l'app
|
||||
Dallo stesso terminale da cui avvii l'app:
|
||||
```
|
||||
command -v claude codex # Linux/WSL; in PowerShell: Get-Command claude, codex
|
||||
command -v claude codex agy # Linux/WSL; in PowerShell: Get-Command claude, codex, agy
|
||||
claude -p "rispondi solo: ok"
|
||||
codex exec "rispondi solo: ok"
|
||||
agy -p "rispondi solo: ok"
|
||||
```
|
||||
Se i comandi rispondono, l'app li trova. Se l'app dice "'claude' non trovato nel PATH":
|
||||
Se i comandi rispondono, l'app li trova. Se l'app dice che un motore non è trovato nel PATH:
|
||||
- apri un nuovo terminale (il PATH si aggiorna solo ai nuovi);
|
||||
- controlla che la cartella d'installazione sia nel PATH: per Claude Code nativo e per Codex con script è `~/.local/bin` su Linux/macOS/WSL, `%USERPROFILE%\.local\bin` su Windows (per Claude Code);
|
||||
- controlla che la cartella d'installazione sia nel PATH (`~/.local/bin`, `~/.gemini/bin`, o `%USERPROFILE%\.local\bin` su Windows);
|
||||
- verifica di non aver installato in un ambiente diverso da quello dell'app (tabella iniziale).
|
||||
|
||||
## Fonti
|
||||
- Claude Code: documentazione ufficiale "Advanced setup", consultata il 2026-10-15 (`code.claude.com/docs/en/setup`).
|
||||
- Codex: README del repository `github.com/openai/codex`, consultato il 2026-10-15. La pagina openai.com/it-IT/codex/ non era raggiungibile (HTTP 403).
|
||||
- Comandi `--version`, `login status`, `auth status` e `exec --help`: provati sulla macchina descritta sopra.
|
||||
- Antigravity CLI (`agy`): non ancora trattato, da aggiungere quando verrà integrato.
|
||||
- Codex: README del repository `github.com/openai/codex`, consultato il 2026-10-15.
|
||||
- Antigravity CLI: binario `agy` verificato in ambiente reale il 2026-10-18.
|
||||
- Comandi `--version`, `agy models`, `agy update`: provati sulla macchina descritta sopra.
|
||||
+5
-5
@@ -7,11 +7,11 @@ Eseguibile C# a riga di comando che inoltra un prompt a Claude Code (`claude`) l
|
||||
```
|
||||
<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.
|
||||
Tutti gli argomenti sono uniti in un unico prompt. Con `--engine <id>` come primo argomento (`claude`, `codex` o `agy`) si sceglie il motore, per esempio `<nome-app> --engine agy "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`.
|
||||
2. Avvia il motore scelto in modalità non interattiva (`claude -p <prompt>`, `codex exec … -- <prompt>` o `agy … -p <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](adr/0005-windows-senza-console.md)): `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.
|
||||
@@ -24,9 +24,9 @@ Senza argomenti si apre una finestra Avalonia (C# + XAML, nessun HTML) in stile
|
||||
- **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](../Gui/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.
|
||||
- **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, Antigravity; un motore non installato è mostrato "non installato" e non è selezionabile; disabilitato durante l'attesa), poi **Modello** (Predefinito, catalogo del motore, "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; Antigravity: Gemini 3.0 Flash Low) 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](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 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.
|
||||
- **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 ai valori iniziali del nuovo motore (il modello più piccolo ed effort `low`) e le liste dipendono dal motore (Antigravity: modelli Gemini Flash / Claude / GPT-OSS, effort fino a max). 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 e Antigravity la sessione è letta dall'output (`thread_id` per Codex, `conversation_id` per Antigravity) e usata per riprendere la chat (`--conversation` su agy); i permessi sono di sola lettura (`sandbox_mode="read-only"` su Codex; su Antigravity in headless mode `-p` la sola lettura è garantita dalla modalità predefinita senza flag `--mode`).
|
||||
- **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.
|
||||
- **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.
|
||||
@@ -53,7 +53,7 @@ Le scelte architetturali sono negli [ADR](README.md#indice-adr). Sintesi:
|
||||
- L'avvio dei motori è in un solo punto ([Core/EngineRunner.cs](../Core/EngineRunner.cs)), usato da CLI e GUI; ogni motore descrive argomenti e parser in [Core/Engine.cs](../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](adr/0002-motori-cli-claude-codex-antigravity.md)), logging su file, supporto macOS. I test automatici sono pianificati: [TESTING.md](TESTING.md).
|
||||
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 e Antigravity ([ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md)), logging su file, supporto macOS. I test automatici sono pianificati: [TESTING.md](TESTING.md).
|
||||
|
||||
## Criteri di accettazione
|
||||
Ogni criterio ha test automatici nella matrice di [TESTING.md](TESTING.md) (CL-04, CL-08, CL-06, CL-01).
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# Stato del progetto
|
||||
|
||||
> **Stadio: MVP** (prima di una versione 1.0). Ultimo aggiornamento: 2026-10-15.
|
||||
> **Stadio: MVP** (prima di una versione 1.0). Ultimo aggiornamento: 2026-10-18.
|
||||
> Questo documento è la fotografia dello stato, non la fonte di dettagli: i passi sono in [ROADMAP.md](ROADMAP.md), i requisiti in [MVP.md](MVP.md), le decisioni negli ADR (indice in [README.md](README.md)), i test in [TESTING.md](TESTING.md). Qui si legge a colpo d'occhio dove siamo; per il resto si segue il collegamento.
|
||||
|
||||
## In una frase
|
||||
`agent-wiki-ui` è un eseguibile C# (.NET 10) per Windows e Linux che inoltra prompt a Claude Code e Codex già installati, da riga di comando o da una GUI di chat. La parte funzionale dell'MVP c'è; mancano i test automatici e alcune verifiche su macchine reali.
|
||||
`agent-wiki-ui` è un eseguibile C# (.NET 10) per Windows e Linux che inoltra prompt a Claude Code, Codex e Antigravity già installati, da riga di comando o da una GUI di chat. La parte funzionale dell'MVP c'è; mancano i test automatici e alcune verifiche su macchine reali.
|
||||
|
||||
## Stato per area
|
||||
| Area | Stato | Note |
|
||||
|---|---|---|
|
||||
| CLI (`agent-wiki-ui "prompt"`, `--engine`) | Funzionante | Exit code e 127 provati su Linux; su Windows l'exit code arriva solo se il chiamante attende il processo ([ADR-0005](adr/0005-windows-senza-console.md)). |
|
||||
| GUI di chat (Avalonia) | Funzionante | Barra laterale, cronologia su disco, markdown, tema chiaro/scuro, Impostazioni. Provata con screenshot headless e su WSLg; non su Windows nativo. |
|
||||
| Motori | Claude Code e Codex | Una chat = un motore; sessione di Codex letta dall'output. Antigravity non iniziato ([ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md)). |
|
||||
| Motori | Claude Code, Codex, Antigravity | Una chat = un motore; sessione di Codex (`thread_id`) e Antigravity (`conversation_id`) lette dall'output. Sola lettura di default ([ADR-0002](adr/0002-motori-cli-claude-codex-antigravity.md)). |
|
||||
| Aggiornamento dei CLI | Funzionante, non provato in reale | Controllo preventivo e pulsante evidenziato; l'`update` vero non è mai stato lanciato dall'app ([ADR-0004](adr/0004-aggiornamento-dei-cli.md)). |
|
||||
| Eseguibili standalone | Funzionanti | `win-x64` e `linux-x64` creati da entrambi i sistemi con `scripts/publish.sh` / `.ps1` (circa 47 MB). Windows senza console al doppio clic. |
|
||||
| Test automatici | **Non iniziati** | Piano e matrice pronti ([ADR-0003](adr/0003-strategia-di-test.md)); nessun test scritto. Vedi debiti. |
|
||||
@@ -32,25 +32,25 @@ Da [MVP.md](MVP.md). Restano non spuntati finché non hanno test automatici (reg
|
||||
- **Verifiche su macchine reali**: GUI su Windows nativo e su una distribuzione Linux pulita; doppio clic senza console e riaggancio al terminale (ADR-0005); tema che segue il sistema su Linux; `update` reale dei CLI.
|
||||
- **Impostazioni non salvate su disco**: modello, effort e motore tornano ai valori iniziali a ogni avvio (si parte dal modello più piccolo con effort `low`).
|
||||
- **Nessuno streaming nella GUI**: la risposta compare a fine generazione.
|
||||
- **Elenchi dei modelli fissi** (Claude Code e Codex): da aggiornare a mano; il "modello più piccolo" di Codex è un'assunzione (GPT-5.6 Luna).
|
||||
- **Elenchi dei modelli fissi** (Claude Code, Codex, Antigravity): da aggiornare a mano; il "modello più piccolo" di Codex è un'assunzione (GPT-5.6 Luna), per Antigravity è `gemini-3.0-flash-low`.
|
||||
|
||||
## Decisioni
|
||||
| ADR | Stato |
|
||||
|---|---|
|
||||
| [0001](adr/0001-gui-multipiattaforma-avalonia.md) GUI Avalonia multipiattaforma | Accettata |
|
||||
| [0002](adr/0002-motori-cli-claude-codex-antigravity.md) Più motori CLI | Accettata (Claude Code, Codex) |
|
||||
| [0002](adr/0002-motori-cli-claude-codex-antigravity.md) Più motori CLI | Accettata (Claude Code, Codex, Antigravity) |
|
||||
| [0003](adr/0003-strategia-di-test.md) Strategia di test | Proposta |
|
||||
| [0004](adr/0004-aggiornamento-dei-cli.md) Aggiornamento dei CLI | Proposta |
|
||||
| [0005](adr/0005-windows-senza-console.md) Windows senza console | Proposta |
|
||||
|
||||
## Per chiudere l'MVP
|
||||
Proposta, derivata dai punti aperti sopra; da confermare.
|
||||
1. Test automatici per `Core/` e `MainViewModel` e per i quattro criteri di accettazione (Fase 6, prime righe di CL, ST, VM, CX).
|
||||
1. Test automatici per `Core/` e `MainViewModel` e per i quattro criteri di accettazione (Fase 6, prime righe di CL, ST, VM, CX, AG).
|
||||
2. Gli ADR 0003, 0004 e 0005 passati ad "Accettata" dopo le loro verifiche.
|
||||
3. GUI provata su Windows nativo e su Linux pulito.
|
||||
4. Criteri di accettazione di MVP.md spuntati.
|
||||
|
||||
Oltre l'MVP (non bloccanti): Antigravity, impostazioni persistite, streaming nella GUI, rinomina e ricerca delle chat, CI con matrice Windows e Linux, firma dell'eseguibile Windows.
|
||||
Oltre l'MVP (non bloccanti): impostazioni persistite, streaming nella GUI, rinomina e ricerca delle chat, CI con matrice Windows e Linux, firma dell'eseguibile Windows.
|
||||
|
||||
## Come tenere aggiornato questo file
|
||||
Si aggiorna nello stesso commit di ogni cambio di stadio, di funzione, di ADR o di debito: stato per area, criteri, debiti, tabella delle decisioni, data. Se una riga qui contraddice ROADMAP.md o un ADR, vale quello e questa pagina va corretta.
|
||||
+1
-1
@@ -48,7 +48,7 @@ Non si scrive nulla nei puntatori: ogni modifica va in AGENT.md. Per un altro st
|
||||
| ADR | Titolo | Stato |
|
||||
|---|---|---|
|
||||
| [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) |
|
||||
| [0002](adr/0002-motori-cli-claude-codex-antigravity.md) | Più motori CLI (Claude Code, Codex, Antigravity) su Windows e Linux | Accettata (Claude Code, Codex, Antigravity) |
|
||||
| [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 |
|
||||
| [0005](adr/0005-windows-senza-console.md) | Windows: eseguibile senza finestra di console | Proposta |
|
||||
+6
-5
@@ -28,20 +28,21 @@ Dettagli dell'MVP in [MVP.md](MVP.md). Stadio attuale e debiti: [PROJECT_STATE.m
|
||||
## 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. 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] Verificare i flag reali di `codex` e `agy` (provati su Linux/WSL, ADR-0002 accettata per Claude Code, Codex e Antigravity); Windows da verificare
|
||||
- [x] Astrazione "motore" in C# (`Core/Engine.cs`, `Core/EngineRunner.cs`)
|
||||
- [x] Rilevamento dei motori nel PATH; motori assenti disabilitati, messaggio chiaro
|
||||
- [x] Il JSON di ogni chat memorizza il motore e l'id di sessione; cambiare motore apre una nuova chat
|
||||
- [x] GUI: interruttore CLI nel riquadro Impostazioni; modelli ed effort in base al motore; motore della chat indicato nell'interfaccia
|
||||
- [ ] Impostazioni (motore, modello, effort) persistite su disco
|
||||
- [x] Motore Codex: lettura dell'id di sessione dall'output (`thread_id`) per la ripresa
|
||||
- [ ] Motore Antigravity: gestione del blocco con output rediretto (timeout, errore chiaro)
|
||||
- [x] Permessi di Codex in sola lettura (nessun flag che salta i controlli)
|
||||
- [x] Motore Antigravity: gestione del blocco con output rediretto (`--print-timeout 120s` prima di `-p`, chiusura immediata di stdin)
|
||||
- [x] Motore Antigravity: lettura dell'id di sessione dall'output (`conversation_id`) e ripresa con `--conversation`
|
||||
- [x] Permessi di Codex e Antigravity in sola lettura (`sandbox_mode="read-only"` per Codex; per Antigravity in headless mode `-p` sola lettura garantita dalla modalità di default senza `--mode`; nessun flag che salta i controlli)
|
||||
- [ ] Opzione esplicita per concedere permessi di scrittura
|
||||
- [x] CLI: opzione `--engine`, coerente con la GUI
|
||||
- [x] CLI: opzione `--engine`, coerente con la GUI (supporta `claude`, `codex`, `agy`)
|
||||
- [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"
|
||||
- [ ] Provare gli aggiornamenti reali (finora provati solo con CLI finti, e rilevamento del metodo di installazione sui percorsi reali; provato `agy update`) 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.
|
||||
|
||||
@@ -83,6 +83,23 @@ 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` | [ ] |
|
||||
|
||||
### Antigravity — `Core/Engine.cs` (parser e argomenti), `Core/EngineRunner.cs`
|
||||
Le righe CL valgono per ogni motore; queste sono specifiche di Antigravity CLI (`agy`, ADR-0002).
|
||||
| ID | Requisito | Liv. | Test | |
|
||||
|---|---|---|---|---|
|
||||
| AG-01 | Primo messaggio: `--output-format json --print-timeout 120s … -p <prompt>` (senza `--mode`, sola lettura garantita dal default in headless) | U | `Agy_primo_messaggio` | [ ] |
|
||||
| AG-02 | Ripresa: `--output-format json --conversation <sessionId> … -p <prompt>` (senza `--mode`) | U | `Agy_ripresa` | [ ] |
|
||||
| AG-03 | Tutti i flag precedono rigorosamente `-p <prompt>` | U | `Agy_flag_prima_di_p` | [ ] |
|
||||
| AG-04 | Modello ⇒ `--model`; effort ⇒ `--effort`; vuoti ⇒ omessi | U | `Agy_modello_ed_effort` | [ ] |
|
||||
| AG-05 | Il parser legge `conversation_id` dall'output JSON (`OwnsSessionId => true`) | U | `Agy_conversation_id` | [ ] |
|
||||
| AG-06 | La risposta è estratta dal campo `response` del JSON | U | `Agy_estrazione_risposta` | [ ] |
|
||||
| AG-07 | `status` diverso da SUCCESS o campo `error` ⇒ errore; exit ≠ 0 ⇒ Failed(code, stderr) | U | `Agy_errore_status` | [ ] |
|
||||
| AG-08 | Avvisi o testo spurio prima/dopo il JSON sono isolati correttamente | U | `Agy_estrazione_json_robusta` | [ ] |
|
||||
| AG-09 | Exit 0 con `response` vuoto ⇒ errore "agy non ha restituito nessuna risposta" | U | `Agy_nessuna_risposta` | [ ] |
|
||||
| AG-10 | In modalità CLI (`structured = false`) non si usa `--output-format json` | U | `Agy_cli_senza_json` | [ ] |
|
||||
| AG-11 | Stdin chiuso subito e `--print-timeout 120s` prevengono il blocco con output rediretto | P | `Agy_timeout_e_stdin` | [ ] |
|
||||
| AG-12 | Catalogo modelli con i 6 modelli attesi ed effort fino a max; default `gemini-3.0-flash-low`, `low` | U | `Agy_catalogo_modelli` | [ ] |
|
||||
|
||||
### 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 | |
|
||||
@@ -107,6 +124,7 @@ Si provano con `FakeClaude`/`FakeCodex` che rispondono a `--version` e `update`;
|
||||
| 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` | [ ] |
|
||||
| UP-21 | Antigravity: l'ultima versione si legge dal servizio auto-updater ufficiale (stringa "Stable Version: X.Y.Z") | U | `Ultima_versione_agy` | [ ] |
|
||||
|
||||
### Cronologia — `Core/ChatStore.cs`, `Core/AppInfo.cs`
|
||||
| ID | Requisito | Liv. | Test | |
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# ADR-0002 — Più motori CLI (Claude Code, Codex, Antigravity) su Windows e Linux
|
||||
|
||||
- **Stato**: Accettata per Claude Code e Codex (verificati con prove reali); Antigravity resta da verificare
|
||||
- **Data**: 2026-10-15
|
||||
- **Stato**: Accettata (Claude Code, Codex, Antigravity)
|
||||
- **Data**: 2026-10-15 (aggiornato 2026-10-18 per Antigravity)
|
||||
- **Collegato a**: [ADR-0001](0001-gui-multipiattaforma-avalonia.md) (GUI e piattaforme)
|
||||
|
||||
## Contesto
|
||||
L'app lancia solo `claude -p`. Si vuole usare dalla stessa chat anche **OpenAI Codex CLI** e **Antigravity CLI** (`agy`), così come `claude` già installati da terminale dall'utente, su Windows e Linux. L'app non li installa e non gestisce login: sono programmi esterni, autenticati a parte.
|
||||
L'app lanciava solo `claude -p`. Si vuole usare dalla stessa chat anche **OpenAI Codex CLI** e **Antigravity CLI** (`agy`), così come `claude` già installati da terminale dall'utente, su Windows e Linux. L'app non li installa e non gestisce login: sono programmi esterni, autenticati a parte.
|
||||
|
||||
## Criteri di decisione
|
||||
1. Aggiungere un motore costa una definizione dichiarativa, non nuova logica sparsa.
|
||||
@@ -17,22 +17,22 @@ L'app lancia solo `claude -p`. Si vuole usare dalla stessa chat anche **OpenAI C
|
||||
- **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 ai valori iniziali del motore (il modello più piccolo ed effort `low`; "Predefinito" resta selezionabile) e le liste sono quelle del motore. La persistenza su disco delle impostazioni è rinviata. La CLI ottiene `--engine <id>` (`claude`, `codex`).
|
||||
- **Sessione**: per Claude Code l'id lo sceglie l'app; per Codex lo genera Codex e l'app lo legge dall'output (`thread_id`). Il JSON della chat ha quindi un campo `Engine` e un campo `SessionId` separato dall'id della chat (che resta il nome del file). I file scritti prima (senza questi campi) si leggono come chat di Claude Code con `SessionId` = id della chat.
|
||||
- **Impostazioni** nella GUI: interruttore **CLI** (motore attivo), modello, effort. Cambiare motore apre una nuova chat; modello ed effort tornano ai valori iniziali del motore (il modello più piccolo ed effort `low`; "Predefinito" resta selezionabile) e le liste sono quelle del motore. La persistenza su disco delle impostazioni è rinviata. La CLI ottiene `--engine <id>` (`claude`, `codex`, `agy`).
|
||||
- **Sessione**: per Claude Code l'id lo sceglie l'app; per Codex e Antigravity lo genera il motore e l'app lo legge dall'output (`thread_id` per Codex, `conversation_id` per Antigravity). Il JSON della chat ha quindi un campo `Engine` e un campo `SessionId` separato dall'id della chat (che resta il nome del file). I file scritti prima (senza questi campi) si leggono come chat di Claude Code con `SessionId` = id della chat.
|
||||
- **Autore dei messaggi**: l'etichetta sulle risposte e i segnaposto del composer usano il nome del motore della chat; l'elenco chat indica il motore.
|
||||
- **Permessi**: di default sola lettura / nessun bypass dei controlli; concedere di più è un'opzione esplicita.
|
||||
- **Output**: ogni motore ha un parser che lo normalizza in testo markdown prima del rendering.
|
||||
|
||||
## Comandi dei motori
|
||||
Claude Code e Codex sono verificati con prove reali (Codex 0.144.3, 2026-10-15, Linux/WSL). Antigravity deriva da documentazione e ricerche: `agy` non è installato su questa macchina.
|
||||
Claude Code, Codex e Antigravity sono verificati con prove reali (Linux/WSL, ottobre 2026).
|
||||
|
||||
| | Claude Code | Codex CLI | Antigravity CLI |
|
||||
|---|---|---|---|
|
||||
| Comando (GUI) | `claude -p <prompt>` | `codex exec --json --skip-git-repo-check -s read-only [opzioni] -- <prompt>` | `agy -p <prompt>` (da verificare) |
|
||||
| Continuare | `--session-id <guid>`, poi `--resume <guid>` | `codex exec resume --json --skip-git-repo-check -c 'sandbox_mode="read-only"' [opzioni] <id> -- <prompt>` | da verificare |
|
||||
| Modello | `--model` | `-m` / `--model` | da verificare |
|
||||
| Effort | `--effort` | `-c model_reasoning_effort=<livello>` | non noto |
|
||||
| Output usato | testo su stdout | JSONL su stdout (vedi sotto) | da verificare |
|
||||
| Comando (GUI) | `claude -p <prompt>` | `codex exec --json --skip-git-repo-check -s read-only [opzioni] -- <prompt>` | `agy --output-format json --print-timeout 120s [opzioni] -p <prompt>` |
|
||||
| Continuare | `--session-id <guid>`, poi `--resume <guid>` | `codex exec resume --json --skip-git-repo-check -c 'sandbox_mode="read-only"' [opzioni] <id> -- <prompt>` | `agy --output-format json --print-timeout 120s --conversation <id> [opzioni] -p <prompt>` |
|
||||
| Modello | `--model` | `-m` / `--model` | `--model` |
|
||||
| Effort | `--effort` | `-c model_reasoning_effort=<livello>` | `--effort` |
|
||||
| Output usato | testo su stdout | JSONL su stdout (vedi sotto) | JSON su stdout (`conversation_id`, `status`, `response`) |
|
||||
|
||||
**Codex: esito delle prove**
|
||||
- L'id di sessione non si sceglie: compare nel primo evento JSONL `{"type":"thread.started","thread_id":"<uuid>"}`. Nel testo normale compare solo nell'intestazione su stderr.
|
||||
@@ -46,17 +46,26 @@ Claude Code e Codex sono verificati con prove reali (Codex 0.144.3, 2026-10-15,
|
||||
- Il modello più piccolo di Codex è assunto essere GPT-5.6 Luna (nome e supporto agli effort inferiori: non dichiarato da OpenAI nelle prove); da rivedere quando cambia il catalogo.
|
||||
- Il catalogo modelli di Codex è dinamico (`~/.codex/models_cache.json`); l'app ne usa uno fisso, da aggiornare, con "Predefinito" e "Altro ID…" sempre disponibili.
|
||||
|
||||
**Antigravity (`agy`): esito delle prove**
|
||||
- Eseguibile nativo: ELF su Linux (`~/.gemini/bin/agy`), `.exe` nativo su Windows.
|
||||
- Permessi e sicurezza: per usare `agy` in modalità non interattiva (`-p`) in sola lettura, nel file `~/.gemini/antigravity-cli/settings.json` deve essere presente la regola `'read_file(*)'` sotto `'permissions.allow'` (altrimenti headless mode nega `read_file` con errore jetski: `a tool required the read_file permission that headless mode cannot prompt for`), mentre scritture e comandi restano negati di default. Non si passa `--mode plan` (che fallisce anch'esso con errore jetski) né `--mode auto` (non disponibile per l'account) né alcun flag `--mode`. Mai usare `--dangerously-skip-permissions`.
|
||||
- Posizione di `-p`: tutti i flag di configurazione vanno passati rigorosamente prima di `-p <prompt>`.
|
||||
- Formato output: per la GUI (`structured = true`) si passa `--output-format json`; per la CLI si omette per ereditare testo normale. L'output JSON contiene `conversation_id`, `status` ("SUCCESS") e `response` con il testo generato.
|
||||
- Sessione: l'id di sessione è un UUID generato da `agy` (`OwnsSessionId => true`), letto da `conversation_id`. La ripresa avviene passando `--conversation <sessionId>`.
|
||||
- Blocco sottoprocesso su output rediretto (issue #318): mitigato passando `--print-timeout 120s` (formato durata Go) e assicurando la chiusura immediata dello stdin.
|
||||
- Modelli ed effort: modelli fissi da catalogo `agy models`, modello più piccolo predefinito `gemini-3.0-flash-low`, effort supportati `low`, `medium`, `high`, `xhigh`, `max` (default `low`).
|
||||
|
||||
## Conseguenze
|
||||
**Positive**: un solo flusso di avvio; nuovi motori aggiungibili con una definizione; elimina la duplicazione CLI/GUI.
|
||||
**Negative**: i flag delle CLI cambiano nel tempo e vanno mantenuti; le sessioni non si trasferiscono tra motori; più superficie da testare su due sistemi operativi.
|
||||
|
||||
## Rischi e da verificare
|
||||
- [x] **Codex**: l'id di sessione lo genera Codex; letto dall'evento `thread.started` (vedi sopra).
|
||||
- [ ] **Antigravity**: segnalato un blocco di `agy -p` da sottoprocesso con output rediretto su Windows ([issue #318](https://github.com/google-antigravity/antigravity-cli/issues/318)). Provare con `--print-timeout` e prevedere un messaggio d'errore. I flag vanno messi prima di `-p`. Da provare anche su Linux.
|
||||
- [ ] **Forma dell'eseguibile**: `claude` è un .exe nativo avviabile direttamente; Codex e Antigravity, se installati con un gestore di pacchetti (es. npm), su Windows possono essere script `.cmd` che richiedono `cmd.exe /c`. Su Linux sono normali eseguibili o script con shebang. Verificare e gestire per motore.
|
||||
- [x] **Antigravity**: verificato il comando non interattivo `agy [flag] -p <prompt>`, output JSON `--output-format json`, ripresa con `--conversation`, timeout con `--print-timeout 120s` e chiusura stdin.
|
||||
- [ ] **Forma dell'eseguibile**: `claude` e `agy` sono binari nativi avviabili direttamente; per installazioni tramite gestori di pacchetti verificare eventuali script wrapper su Windows.
|
||||
- [ ] Autenticazione: ogni CLI deve essere già autenticata; l'app mostra l'errore del motore senza gestire login.
|
||||
- [x] Formato dell'output di Codex: JSONL, normalizzato in testo markdown. Antigravity ancora da verificare.
|
||||
- [x] Mappatura effort e modelli per Codex (liste fisse, da aggiornare). Antigravity da verificare.
|
||||
- [x] Formato dell'output di Codex e Antigravity: Codex JSONL, Antigravity JSON su stdout, normalizzati in testo markdown.
|
||||
- [x] Mappatura effort e modelli per Codex e Antigravity (liste fisse, da aggiornare).
|
||||
|
||||
## Riferimenti
|
||||
- Passi: [ROADMAP.md](../ROADMAP.md), Fase 4.
|
||||
|
||||
@@ -24,9 +24,10 @@ Entrambi i CLI hanno un comando di aggiornamento che controlla e, se c'è una ve
|
||||
- **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.
|
||||
- Antigravity: `GET https://antigravity-cli-auto-updater-974169037036.us-central1.run.app`, testo con `Stable Version: X.Y.Z` (la sorgente dell'auto-updater ufficiale presente nel binario `agy`).
|
||||
- Le versioni si ricavano con il primo numero `N.N.N` del testo e si confrontano come versioni. Verificate il 2026-10-15 e 2026-10-18.
|
||||
- **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.
|
||||
- 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 gli indirizzi ufficiali 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)";
|
||||
@@ -34,12 +35,12 @@ Entrambi i CLI hanno un comando di aggiornamento che controlla e, se c'è una ve
|
||||
- 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) |
|
||||
| Percorso contiene | Metodo | Claude Code | Codex | Antigravity |
|
||||
|---|---|---|---|---|
|
||||
| `node_modules`, `.npm` | npm | `npm install -g @anthropic-ai/claude-code@latest` | `npm install -g @openai/codex@latest` | `agy update` |
|
||||
| `Cellar`, `homebrew`, `linuxbrew` | Homebrew | `brew upgrade claude-code` (o `claude-code@latest`) | `brew upgrade --cask codex` | `brew upgrade agy` |
|
||||
| `WinGet`, `WindowsApps` | WinGet | `winget upgrade Anthropic.ClaudeCode` | script PowerShell di [INSTALL.md](../INSTALL.md) | `agy update` |
|
||||
| altro | nativo/script | `claude update` da terminale | script di installazione di [INSTALL.md](../INSTALL.md) | `agy update` |
|
||||
|
||||
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.
|
||||
|
||||
Reference in new issue
Block a user