extracted responsibilities from Program.cs (208→46 lines) and ReplLoop.cs (274→174 lines) into focused service classes: HeaderRenderer, SessionManager, ApplicationStartup, ResponseStreamer, SpinnerService, UsageDisplayer, and ContextCompactionService. Each class now has a single, well-defined responsibility, improving testability and maintainability.
84 lines
2.3 KiB
C#
84 lines
2.3 KiB
C#
using Spectre.Console;
|
|
|
|
namespace AnchorCli;
|
|
|
|
/// <summary>
|
|
/// Manages session persistence, including auto-load on startup and auto-save on exit.
|
|
/// </summary>
|
|
internal sealed class SessionManager
|
|
{
|
|
private readonly ChatSession _session;
|
|
private readonly string _sessionPath;
|
|
|
|
public SessionManager(ChatSession session, string sessionPath = ".anchor/session.json")
|
|
{
|
|
_session = session;
|
|
_sessionPath = sessionPath;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to load a session from disk. Returns true if successful.
|
|
/// </summary>
|
|
public async Task<bool> TryLoadAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
if (!File.Exists(_sessionPath))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
await _session.LoadAsync(_sessionPath, cancellationToken);
|
|
AnsiConsole.MarkupLine($"[dim grey]Auto-loaded previous session.[/]");
|
|
|
|
// Print the last message if there is one
|
|
if (_session.History.Count > 1)
|
|
{
|
|
var lastMessage = _session.History[^1];
|
|
var preview = lastMessage.Text.Length > 280
|
|
? lastMessage.Text[..277] + "..."
|
|
: lastMessage.Text;
|
|
AnsiConsole.MarkupLine($"[dim grey] Last message: {Markup.Escape(preview)}[/]");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
// Ignore load errors
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to save the session to disk. Returns true if successful.
|
|
/// </summary>
|
|
public async Task<bool> TrySaveAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var directory = Path.GetDirectoryName(_sessionPath);
|
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
await _session.SaveAsync(_sessionPath, cancellationToken);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
// Ignore save errors
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the session after an LLM turn completes.
|
|
/// </summary>
|
|
public async Task SaveAfterTurnAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
await TrySaveAsync(cancellationToken);
|
|
}
|
|
}
|