using NozCli.Core.Client; using NozCli.Core.Config; using NozCli.Core.Models; using Spectre.Console; namespace NozCli.Repl; public static class ReplSession { public static async Task RunAsync(LocalConfig config) { using var api = new NozApiClient(config); ServerCapabilities caps = default!; await AnsiConsole.Status().StartAsync("Connecting…", async _ => caps = await api.GetConfigAsync()); AnsiConsole.MarkupLine($"[bold green]noz[/] [dim]· {caps.Server}[/]"); AnsiConsole.MarkupLine($"[dim]push={caps.AllowPush} delete={caps.AllowDelete} vault={caps.AllowVault}[/]\n"); var ctx = new ReplContext(api); var registry = new CommandRegistry(); var input = new ReplInput(registry); await AnsiConsole.Status().StartAsync("Loading notes…", async _ => ctx.NoteCache = await api.GetNotesAsync()); AnsiConsole.MarkupLine($"[dim]● {ctx.NoteCache.Count} notes cached[/]\n"); input.SetContext(ctx); while (ctx.Running) { var prompt = $"[bold cyan]{ctx.CurrentPath}[/] [dim]»[/] "; var line = input.Read(prompt); if (line is null) break; // Ctrl-C / Ctrl-D var parts = line.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) continue; var name = parts[0]; var args = parts[1..]; if (name is "exit" or "quit" or "q") { AnsiConsole.MarkupLine("[dim]Bye.[/]"); break; } var cmd = registry.Find(name); if (cmd is null) { AnsiConsole.MarkupLine($"[red]Unknown command:[/] {name} [dim](type 'help')[/]"); continue; } try { await cmd.ExecuteAsync(args, ctx); } catch (HttpRequestException ex) { AnsiConsole.MarkupLine($"[red]Server error:[/] {ex.Message}"); } catch (Exception ex) { AnsiConsole.MarkupLine($"[red]Error:[/] {ex.Message}"); } } } }