Documentazione: Windows senza finestra di console (ADR-0005)

Nuovo ADR-0005: su Windows l'eseguibile è senza console, così il doppio clic
mostra solo la GUI, e la CLI riaggancia il terminale padre. L'alternativa a
due file resta registrata. MVP, README e CLAUDE.md spiegano la conseguenza
sull'exit code (disponibile solo se il chiamante attende il processo, con
start /wait o Start-Process -Wait); TESTING.md aggiunge le righe WIN.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-15 12:13:01 +02:00
1 parent d7e8a341ab
commit d4b6c3693a
7 files changed
+60 -3

No files matched your search

+1
View File
@@ -42,6 +42,7 @@ Decisioni e motivazioni negli ADR ([docs/adr/](docs/adr/)); qui solo la mappa de
- Codex (`CodexEngine`): l'id di sessione lo genera Codex e si legge da `thread.started` nell'output JSONL (`--json`); la risposta è l'ultimo `agent_message`; `exec resume` non accetta `-s`, la sola lettura si impone con `-c 'sandbox_mode="read-only"'`; serve `--skip-git-repo-check` (la cartella dell'exe non è un repository); `--` prima del prompt. Dettagli e prove in ADR-0002. Il modello predefinito è quello di `~/.codex/config.toml`: se richiede un Codex più recente l'errore compare nella chat (vedi docs/INSTALL.md).
- Il controllo delle versioni contatta solo `downloads.claude.ai` (Claude Code) e `api.github.com` (Codex, serve lo User-Agent), al massimo ogni 5 minuti e in background; un errore di rete non è un errore dell'app (stato "sconosciuto").
- L'aggiornamento di un CLI è sempre un gesto esplicito dell'utente (pulsante Aggiorna): nessun aggiornamento automatico e nessun fallback che esegua npm/brew/winget al posto suo.
- Windows: l'eseguibile è `WinExe` (nessuna console al doppio clic); in modalità CLI `Core/ConsoleHost.cs` riaggancia il terminale padre con `AttachConsole` e collega stdout/stderr a `CONOUT$` solo se non sono già reindirizzati (ADR-0005). Il codice deve poter fallire in silenzio senza terminale. Conseguenza: su Windows l'exit code della CLI arriva solo se il chiamante attende il processo.
- Il nome dell'app non va scritto a mano nel codice: usare `AppInfo.Name`. Cambiare nome cambia la cartella dati (vedi checklist in docs/README.md; `ChatStore` migra le cartelle dei nomi precedenti).
- Avalonia 12: la clipboard si usa con `using Avalonia.Input.Platform;` (`SetTextAsync` è un'estensione); `TextBox.Watermark` è obsoleto, usare `PlaceholderText`.
- Nel renderer markdown i colori si risolvono al momento del rendering (`TryFindResource` con `ActualThemeVariant`) e la vista si ricostruisce al cambio di tema.
+1 -1
View File
@@ -44,7 +44,7 @@ dotnet publish -c Release -r linux-x64 --self-contained -p:PublishSingleFile=tru
Senza `-o` il risultato è in `bin/Release/net10.0/<rid>/publish/`.
**Usarli**
- Windows: doppio clic su `agent-wiki-ui.exe` per la GUI, oppure da terminale `agent-wiki-ui.exe "prompt"` per la CLI. Il file non è firmato: Windows può mostrare un avviso di sicurezza al primo avvio.
- 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).
+2 -2
View File
@@ -13,7 +13,7 @@ Tutti gli argomenti sono uniti in un unico prompt. Con `--engine <id>` come prim
1. Se non ci sono argomenti: stampa l'uso ed esce con codice 2.
2. Avvia il motore scelto in modalità non interattiva (`claude -p <prompt>` o `codex exec … -- <prompt>`) con `WorkingDirectory = AppContext.BaseDirectory`.
3. Ritrasmette stdout e stderr del processo figlio in tempo reale.
4. Esce con lo stesso exit code di `claude`.
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.
## GUI (chat)
@@ -60,7 +60,7 @@ Ogni criterio ha test automatici nella matrice di [TESTING.md](TESTING.md) (CL-0
- [ ] Eseguito da un'altra cartella, `claude` parte nella cartella dell'exe (verificabile chiedendo "pwd").
- [ ] L'output appare in streaming, non solo alla fine.
- [ ] L'exit code è propagato.
- [ ] L'exit code è propagato (su Windows, quando il chiamante attende il processo: vedi sopra).
- [ ] Un prompt con virgolette e spazi arriva intatto.
## Domande aperte
+1
View File
@@ -40,3 +40,4 @@ Se il nome cambia di nuovo, aggiornare solo questi punti:
| [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 |
| [0005](adr/0005-windows-senza-console.md) | Windows: eseguibile senza finestra di console | Proposta |
+1
View File
@@ -56,6 +56,7 @@ Decisione e motivazioni: [ADR-0001](adr/0001-gui-multipiattaforma-avalonia.md).
- [x] Rendering markdown in Avalonia (titoli, liste, tabelle, citazioni, codice), pulsante Copia, link nel browser di sistema
- [x] Tema chiaro/scuro che segue il sistema, con i token di MVP.md → "Design (UI/UX)" (da provare su un desktop Linux reale)
- [x] Eliminare `ui.html` e il protocollo `WebMessage`
- [x] Windows: eseguibile senza finestra di console, la CLI riaggancia il terminale padre ([ADR-0005](adr/0005-windows-senza-console.md)); da provare su Windows nativo
- [ ] Publish single-file self-contained `win-x64` e `linux-x64`: compilano e partono (Linux: CLI e GUI su WSLg; Windows: solo CLI, via WSL); da provare la GUI su Windows nativo e su una distribuzione Linux pulita
- [x] Aggiornare README.md e CLAUDE.md (comandi, architettura, vincoli) a migrazione conclusa
+9
View File
@@ -192,6 +192,15 @@ Si provano con `FakeClaude`/`FakeCodex` che rispondono a `--version` e `update`;
| UI-15 | Il nome dell'app compare nel titolo della finestra e nella barra laterale | G | `Nome_app_visibile` | [ ] |
### Eseguibile pubblicato
Righe WIN: console su Windows (ADR-0005).
| ID | Requisito | Liv. | Test | |
|---|---|---|---|---|
| WIN-01 | L'eseguibile `win-x64` pubblicato ha sottosistema "Windows GUI" (intestazione PE); quello `linux-x64` non è interessato | E | `Sottosistema_gui` | [ ] |
| WIN-02 | CLI con output reindirizzato su file o pipe: l'output arriva, handle ereditati non toccati | E | `Cli_con_output_reindirizzato` | [ ] |
| WIN-03 | CLI da un terminale: output visibile (`AttachConsole` + `CONOUT$`); senza terminale padre l'attacco fallisce in silenzio e l'app prosegue | E (manuale su Windows nativo) | `Cli_con_terminale_padre` | [ ] |
| WIN-04 | Exit code corretto quando il chiamante attende il processo (`start /wait`, `Start-Process -Wait`) | E (manuale su Windows nativo) | `ExitCode_con_attesa` | [ ] |
| WIN-05 | Il codice di `ConsoleHost` non fa nulla su Linux/macOS | U | `ConsoleHost_non_windows` | [ ] |
| ID | Requisito | Liv. | Test | |
|---|---|---|---|---|
| PUB-01 | Il publish single-file `linux-x64` si compila e la CLI risponde con `FakeClaude` | E | `Publish_linux_smoke` | [ ] |
+45
View File
@@ -0,0 +1,45 @@
# ADR-0005 — Windows: eseguibile senza finestra di console
- **Stato**: Proposta
- **Data**: 2026-10-15
- **Collegato a**: [ADR-0001](0001-gui-multipiattaforma-avalonia.md) (GUI e piattaforme)
## Contesto
Su Windows l'eseguibile è di tipo "console" (`OutputType` `Exe`): con il doppio clic, oltre alla finestra della GUI si apre anche un terminale vuoto che resta aperto finché l'app gira. Il tipo console serve alla CLI (`agent-wiki-ui.exe "prompt"`), perché da terminale `cmd` e PowerShell aspettano la fine del programma, mostrano l'output e danno l'exit code. Un eseguibile "GUI" non ha console, ma allora la CLI perde queste proprietà. Su Linux il problema non esiste: nessuna finestra extra.
## Criteri di decisione
1. Doppio clic: solo la finestra della GUI.
2. La CLI deve continuare a mostrare l'output nel terminale da cui parte, anche con reindirizzamenti (`> file`, `| altro`).
3. Un solo file da distribuire, come per Linux.
4. Nessun cambiamento per Linux.
## Opzioni considerate
| Opzione | Esito | Motivo |
|---|---|---|
| Lasciare il tipo console e nascondere la finestra all'avvio (`FreeConsole`) | Scartata | La finestra compare comunque per un istante; con Windows Terminal come terminale predefinito può restare una scheda. |
| Due file: `agent-wiki-ui.exe` (senza console) e `agent-wiki-ui-cli.exe` (con console) | Alternativa valida | Nessuna perdita nella CLI (exit code corretto ovunque), ma due file da distribuire e da spiegare. Da riprendere se l'exit code della CLI diventa importante in Windows. |
| **Un solo `.exe` senza console; la CLI riaggancia il terminale padre** | **Scelta** | Un file, doppio clic pulito, output visibile nel terminale. |
## Decisione
- Il progetto usa `OutputType` **`WinExe`** (sottosistema Windows). Su Linux non cambia nulla.
- Con **argomenti** (modalità CLI) su Windows, `Core/ConsoleHost.cs` chiama `AttachConsole(ATTACH_PARENT_PROCESS)`: se parte da `cmd`, PowerShell o Windows Terminal l'app usa quel terminale. Se l'output standard non è già valido (non è reindirizzato) lo collega alla console (`CONOUT$`); se è un file o una pipe ereditati li lascia stare, così `> file` e `|` funzionano. Il motore avviato dopo eredita gli stessi handle.
- Senza terminale padre (doppio clic, avvio da un altro programma) l'attacco fallisce in silenzio e l'app prosegue.
- Senza argomenti (GUI) non si tocca la console.
## Conseguenze
**Positive**: il doppio clic mostra solo la finestra; un unico file; output e reindirizzamenti della CLI funzionano.
**Negative / costi — comportamento della CLI su Windows**:
- `cmd` e PowerShell **non aspettano** la fine di un programma a sottosistema Windows: il prompt torna subito e l'output compare dopo, mescolato al prompt.
- L'**exit code** non arriva a `%ERRORLEVEL%` né a `$LASTEXITCODE` in uso interattivo. Arriva se il chiamante aspetta il processo: `start /wait agent-wiki-ui.exe "prompt"` in `cmd`, `Start-Process -Wait -NoNewWindow` o `& .\agent-wiki-ui.exe "prompt" | Out-Host` in PowerShell, script e programmi che attendono il processo figlio. In pipeline (`| Out-Host`, `| more`) PowerShell attende.
- Su Linux e macOS il comportamento della CLI resta quello di sempre (exit code propagato, streaming).
- Il criterio di accettazione dell'MVP sull'exit code vale quindi, su Windows, solo se il chiamante attende il processo.
## Da verificare
- [ ] Doppio clic su Windows nativo: nessuna finestra di console.
- [ ] Da `cmd`, PowerShell e Windows Terminal: output visibile, reindirizzamento su file e pipe, exit code con `start /wait` e con `Start-Process -Wait`.
- [ ] Output corretto quando il processo è avviato da un altro programma senza terminale.
- [ ] Il sottosistema dell'eseguibile pubblicato risulta "Windows GUI" (controllato sull'intestazione PE).
## Riferimenti
- Passi: [ROADMAP.md](../ROADMAP.md), Fase 5.
- Righe di test: [TESTING.md](../TESTING.md), righe WIN.