← All source files

V16 / 6df58cd3ed86

WorkspaceMutationExtensions.cs

Lilith/Core/Workspace/Extensions/WorkspaceMutationExtensions.cs

Unchanged from the preceding version
CS
using System.Text.Json;

namespace Lilith.Core.Workspace.Extensions;

internal static class WorkspaceMutationExtensions
{
    private static readonly JsonSerializerOptions Json = new() { WriteIndented = true };

    // Called only while the session holds its process gate and exclusive workspace lease.
    internal static async Task<WorkspaceResult> CommitMutationAsync(this WorkspaceRequest request, WorkspaceOptions options, string? proposalId)
    {
        // After approval validation, complete the short filesystem commit even if cancellation arrives.
        string operationId = proposalId ?? Guid.NewGuid().ToString("N");
        string receiptPath = options.GetMetadataPath("receipts", operationId) + ".json";
        if (File.Exists(receiptPath)) return JsonSerializer.Deserialize<WorkspaceResult>(File.ReadAllText(receiptPath))!;
        await (options.GetMetadataPath("journal", operationId) + ".json").WriteAtomicallyAsync(JsonSerializer.Serialize(new { request, Before = request.Snapshot(options), Status = "prepared", CreatedAt = DateTimeOffset.UtcNow }, Json), CancellationToken.None);
        string? binId = null;
        string target = request.Operation == "restore" ? options.ResolvePath(options.GetOriginalBinPath(request.BinId)) : options.ResolvePath(request.Path);
        switch (request.Operation)
        {
            case "project_update":
                await request.UpdateProjectAsync(options, target, operationId);
                break;
            case "project_create":
                await request.PublishProjectAsync(options, target, operationId);
                break;
            case "save":
                await target.WriteAtomicallyAsync(request.Content, CancellationToken.None);
                break;
            case "mkdir":
                Directory.CreateDirectory(target);
                break;
            case "move":
                target.MoveTo(options.ResolvePath(request.Destination));
                break;
            case "bin":
                binId = operationId;
                string folder = options.GetMetadataPath("bin", binId);
                Directory.CreateDirectory(folder);
                await Path.Combine(folder, "original.json").WriteAtomicallyAsync(JsonSerializer.Serialize(request), CancellationToken.None);
                await Path.Combine(folder, "deleted.json").WriteAtomicallyAsync(JsonSerializer.Serialize(new { OriginalPath = request.Path, DeletedAtUtc = DateTimeOffset.UtcNow }), CancellationToken.None);
                target.MoveTo(Path.Combine(folder, "item"));
                break;
            case "restore":
                Path.Combine(options.GetMetadataPath("bin", request.BinId), "item").MoveTo(target);
                break;
            default:
                throw new ArgumentException("Unknown workspace operation.");
        }
        string message = request.Operation == "project_create"
            ? "Project published. Source validation/build passed; the generated application has not been run."
            : $"Workspace {request.Operation} completed.";
        var result = new WorkspaceResult("completed", message, Data: new { operation_id = operationId, path = Path.GetRelativePath(options.RootDirectory, target).Replace('\\', '/'), destination = request.Destination, bin_id = binId });
        await receiptPath.WriteAtomicallyAsync(JsonSerializer.Serialize(result, Json), CancellationToken.None);
        if (proposalId is not null) File.Delete(options.GetMetadataPath("pending", proposalId) + ".json");
        return result;
    }

    internal static WorkspaceResult RejectProposal(this WorkspaceRequest request, WorkspaceOptions options)
    {
        string path = options.GetMetadataPath("pending", request.BinId) + ".json";
        if (!File.Exists(path)) throw new IOException("Proposal not found.");
        File.Delete(path);
        return new("completed", "Proposal rejected. No workspace data changed.");
    }
}