using System.Collections.ObjectModel;
using System.Windows.Input;
using AgentWikiUi.Core;
namespace AgentWikiUi.Gui;
class MessageVm(string role, string text, string author)
{
public string Role { get; } = role;
public string Text { get; } = text;
public string Author { get; } = author;
public bool IsUser => Role == "user";
public bool IsAi => Role == "ai";
public bool IsErr => Role == "err";
}
class ChatItem(string id, string title, DateTime updated, bool active, string engineName)
{
public string Id { get; } = id;
public string Title { get; } = title;
public string When { get; } = $"{engineName} · {updated:d MMM HH:mm}";
public bool IsActive { get; } = active;
}
/// Voce dell'interruttore CLI: un motore non installato è mostrato ma non selezionabile. Porta anche versione ed esito dell'ultimo aggiornamento.
class EngineChoice(Engine engine) : ObservableObject
{
string version = "";
string status = "";
bool statusIsError;
bool? available;
string? latest;
public Engine Engine { get; } = engine;
public bool Installed { get; } = engine.IsInstalled();
public string Name => Engine.Name;
public string Label => Installed ? Engine.Name : $"{Engine.Name} (non installato)";
public string Version { get => version; set => Set(ref version, value); }
public string Status { get => status; set { if (Set(ref status, value)) Raise(nameof(HasStatus)); } }
public bool HasStatus => status != "";
public bool StatusIsError { get => statusIsError; set => Set(ref statusIsError, value); }
/// Esito del controllo: true = c'è una versione nuova, false = aggiornato, null = non controllato o sconosciuto.
public bool? Available { get => available; private set { if (Set(ref available, value)) { Raise(nameof(UpdateAvailable)); Raise(nameof(CheckText)); } } }
public bool UpdateAvailable => available == true;
public string CheckText => available switch
{
true => $"Aggiornamento disponibile: {latest}",
false => "Aggiornato",
null => checkedOnce ? "Controllo non riuscito" : "",
};
bool checkedOnce;
public void SetCheck(bool? isAvailable, string? latestVersion)
{
latest = latestVersion; checkedOnce = true;
Raise(nameof(CheckText));
Available = isAvailable;
}
}
class MainViewModel : ObservableObject
{
static readonly ModelOption Default = new("Predefinito", "");
static readonly ModelOption Custom = new("Altro ID…", "__custom");
const string DefaultEffort = "Predefinito";
public ObservableCollection Messages { get; } = [];
public ObservableCollection Chats { get; } = [];
public EngineChoice[] EngineChoices { get; } = Engines.All.Select(e => new EngineChoice(e)).ToArray();
/// Righe della sezione Aggiornamenti: solo i CLI installati.
public EngineChoice[] InstalledEngines => EngineChoices.Where(c => c.Installed).ToArray();
/// Puntino sul pulsante Impostazioni quando almeno un CLI ha una versione nuova.
public bool AnyUpdateAvailable => EngineChoices.Any(c => c.UpdateAvailable);
public ICommand NewChatCommand => newChat;
public ICommand CopyCommand { get; }
public ICommand SendCommand { get; }
public ICommand OpenCommand { get; }
public ICommand DeleteCommand { get; }
public ICommand ToggleSidebarCommand { get; }
public ICommand UpdateCommand { get; }
/// Conferma di eliminazione, fornita dalla finestra.
public Func> ConfirmDelete { get; set; } = () => Task.FromResult(true);
/// Copia negli appunti, fornita dalla finestra.
public Func CopyText { get; set; } = _ => Task.CompletedTask;
/// Chiesto alla finestra di rimettere il fuoco sul campo messaggio.
public event Action? FocusInput;
// Una chat = un motore. chatId è il nome del file; sessionId è l'id del motore:
// per Claude Code lo sceglie l'app (= chatId), per Codex arriva dall'output dopo il primo messaggio.
string chatId = Guid.NewGuid().ToString();
string? sessionId;
bool started; // true dopo il primo messaggio riuscito: da lì in poi si riprende la sessione
List history = [];
EngineChoice selectedEngine;
ModelOption[] modelChoices = [];
string[] effortChoices = [];
string input = "";
bool busy, updating, sidebarOpen = true;
ModelOption selectedModel = Default;
string customModel = "";
string selectedEffort = DefaultEffort;
readonly RelayCommand