1
0

initial commit

This commit is contained in:
2026-03-04 07:59:35 +01:00
commit 3ceb0e4884
27 changed files with 2280 additions and 0 deletions

14
Commands/ClearCommand.cs Normal file
View File

@@ -0,0 +1,14 @@
using Spectre.Console;
namespace AnchorCli.Commands;
public class ClearCommand : ICommand
{
public string Name => "clear";
public string Description => "Clear the terminal screen";
public Task ExecuteAsync(string[] args, CancellationToken ct)
{
AnsiConsole.Clear();
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,31 @@
using Spectre.Console;
namespace AnchorCli.Commands;
public class CommandDispatcher
{
private readonly CommandRegistry _registry;
public CommandDispatcher(CommandRegistry registry)
{
_registry = registry;
}
public async Task<bool> TryExecuteAsync(string input, CancellationToken ct)
{
if (!input.StartsWith('/')) return false;
var parts = input[1..].Split(' ', 2);
var commandName = parts[0];
var args = parts.Length > 1 ? new[] { parts[1] } : Array.Empty<string>();
var command = _registry.GetCommand(commandName);
if (command == null)
{
AnsiConsole.MarkupLine($"[red]Unknown command: /{commandName}[/]");
return true;
}
await command.ExecuteAsync(args, ct);
return true;
}
}

View File

@@ -0,0 +1,18 @@
namespace AnchorCli.Commands;
public class CommandRegistry
{
private readonly Dictionary<string, ICommand> _commands = new(StringComparer.OrdinalIgnoreCase);
public void Register(ICommand command)
{
_commands[command.Name] = command;
}
public ICommand? GetCommand(string name)
{
return _commands.TryGetValue(name, out var cmd) ? cmd : null;
}
public IEnumerable<ICommand> GetAllCommands() => _commands.Values;
}

View File

@@ -0,0 +1,38 @@
using Microsoft.Extensions.AI;
using Spectre.Console;
namespace AnchorCli.Commands;
internal class CompactCommand(ContextCompactor compactor, List<ChatMessage> history) : ICommand
{
public string Name => "compact";
public string Description => "Manually compact conversation history via LLM summarization";
public async Task ExecuteAsync(string[] args, CancellationToken ct)
{
if (history.Count < 5)
{
AnsiConsole.MarkupLine("[dim grey]Nothing to compact (too few messages).[/]");
return;
}
AnsiConsole.MarkupLine("[yellow]⚠ Manually compacting conversation history...[/]");
bool compacted = await AnsiConsole.Status()
.Spinner(Spinner.Known.BouncingBar)
.SpinnerStyle(Style.Parse("yellow"))
.StartAsync("Compacting context...", async ctx =>
await compactor.TryCompactAsync(history, ct));
if (compacted)
{
AnsiConsole.MarkupLine(
$"[green]✓ Context compacted ({history.Count} messages remaining)[/]");
}
else
{
AnsiConsole.MarkupLine(
"[dim grey] (compaction skipped — not enough history to compress)[/]");
}
}
}

15
Commands/ExitCommand.cs Normal file
View File

@@ -0,0 +1,15 @@
using Spectre.Console;
namespace AnchorCli.Commands;
public class ExitCommand : ICommand
{
public string Name => "exit";
public string Description => "Exit the application";
public Task ExecuteAsync(string[] args, CancellationToken ct)
{
AnsiConsole.MarkupLine("[green]Goodbye![/]");
Environment.Exit(0);
return Task.CompletedTask;
}
}

33
Commands/HelpCommand.cs Normal file
View File

@@ -0,0 +1,33 @@
using Spectre.Console;
using System.Linq;
namespace AnchorCli.Commands;
public class HelpCommand : ICommand
{
private readonly CommandRegistry _registry;
public string Name => "help";
public string Description => "Show available commands";
public HelpCommand(CommandRegistry registry)
{
_registry = registry;
}
public Task ExecuteAsync(string[] args, CancellationToken ct)
{
AnsiConsole.MarkupLine("[cyan]Available commands:[/]");
var table = new Table();
table.AddColumn("Command");
table.AddColumn("Description");
foreach (var cmd in _registry.GetAllCommands().OrderBy(c => c.Name))
{
table.AddRow($"[bold]{cmd.Name}[/]", cmd.Description);
}
AnsiConsole.Write(table);
return Task.CompletedTask;
}
}

8
Commands/ICommand.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace AnchorCli.Commands;
public interface ICommand
{
string Name { get; }
string Description { get; }
Task ExecuteAsync(string[] args, CancellationToken ct);
}

34
Commands/StatusCommand.cs Normal file
View File

@@ -0,0 +1,34 @@
using Spectre.Console;
namespace AnchorCli.Commands;
public class StatusCommand : ICommand
{
private readonly string _model;
private readonly string _endpoint;
public StatusCommand(string model, string endpoint)
{
_model = model;
_endpoint = endpoint;
}
public string Name => "status";
public string Description => "Show current settings (model, endpoint, working directory)";
public Task ExecuteAsync(string[] args, CancellationToken ct)
{
var table = new Table()
.Border(TableBorder.Rounded)
.BorderColor(Color.Grey)
.AddColumn(new TableColumn("[dim]Setting[/]").NoWrap())
.AddColumn(new TableColumn("[dim]Value[/]"));
table.AddRow("[grey]Model[/]", $"[cyan]{Markup.Escape(_model)}[/]");
table.AddRow("[grey]Endpoint[/]", $"[blue]{Markup.Escape(_endpoint)}[/]");
table.AddRow("[grey]CWD[/]", $"[green]{Markup.Escape(Environment.CurrentDirectory)}[/]");
AnsiConsole.Write(table);
AnsiConsole.WriteLine();
return Task.CompletedTask;
}
}