using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Chessistics.Scripts.Automation;
///
/// Tiny helpers for the file-based IPC. All writes are atomic: write .tmp then rename.
///
internal static class IpcFiles
{
public const string InboxDir = "inbox";
public const string OutboxDir = "outbox";
public const string ScreensDir = "screens";
public const string ReadyFile = "ready.json";
public const string LogFile = "harness.log";
public static void EnsureDirs(string root)
{
Directory.CreateDirectory(root);
Directory.CreateDirectory(Path.Combine(root, InboxDir));
Directory.CreateDirectory(Path.Combine(root, OutboxDir));
Directory.CreateDirectory(Path.Combine(root, ScreensDir));
}
public static void AtomicWrite(string path, string contents)
{
var tmp = path + ".tmp";
File.WriteAllText(tmp, contents);
if (File.Exists(path)) File.Delete(path);
File.Move(tmp, path);
}
///
/// Return the oldest inbox file whose id hasn't been processed yet, or null.
/// Sorted by filename — agents should name files with a monotonic prefix for ordering.
///
public static string? NextInbox(string root, HashSet processed)
{
var inbox = Path.Combine(root, InboxDir);
if (!Directory.Exists(inbox)) return null;
var files = Directory.GetFiles(inbox, "*.json")
.Where(f => !f.EndsWith(".tmp.json", StringComparison.Ordinal))
.OrderBy(f => Path.GetFileName(f), StringComparer.Ordinal)
.ToList();
foreach (var f in files)
{
if (!processed.Contains(f))
return f;
}
return null;
}
public static string OutboxPath(string root, string id) => Path.Combine(root, OutboxDir, id + ".json");
public static string ScreenshotPath(string root, string name)
{
var safe = name.Replace('/', '_').Replace('\\', '_').Replace(':', '_');
if (!safe.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) safe += ".png";
return Path.Combine(root, ScreensDir, safe);
}
}