using System.Text.Json; using ProjectQuint.Probes; var json = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; try { var action = args.Length == 0 ? "list" : args[0]; var options = new Dictionary(StringComparer.Ordinal); string? output = null; for (var index = 1; index < args.Length; index += 2) { if (index + 1 >= args.Length) throw new ArgumentException("Every option requires a value."); if (args[index] == "--output" && output == null) output = args[index + 1]; else if (args[index] is "--notes" or "--seed" or "--fps" or "--iterations" && int.TryParse(args[index + 1], out var value) && options.TryAdd(args[index], value)) continue; else throw new ArgumentException("Unknown, duplicated or invalid option."); } var notes = options.GetValueOrDefault("--notes", 10_000); var seed = options.GetValueOrDefault("--seed", 42); var fps = options.GetValueOrDefault("--fps", 240); var iterations = options.GetValueOrDefault("--iterations", 20); if (seed < 0) throw new ArgumentException("Seed must be nonnegative."); object report; switch (action) { case "list": if (options.Count != 0 || output != null) throw new ArgumentException("The list command accepts no options."); report = new { schemaVersion = 1, component = "headless-core", commands = new[] { "list", "replay", "benchmark", "test (wrapper)" }, input = "seeded synthetic four-lane notes; no music or external library", options = new[] { "--notes", "--seed", "--fps", "--iterations (benchmark)", "--output" }, }; break; case "replay": if (options.ContainsKey("--iterations")) throw new ArgumentException("Iterations applies only to benchmarks."); var workload = SyntheticWorkload.Create(notes, (uint)seed); report = new { schemaVersion = 1, complete = true, notes, seed, frameRate = fps, eventCount = workload.Events.Length, result = ReplayRunner.Run(workload, fps), }; break; case "benchmark": report = CoreBenchmark.Run(notes, (uint)seed, fps, iterations, checkpoint => { Console.Error.WriteLine($"benchmark {checkpoint.Samples.Length}/{iterations}"); if (output != null) Save(output, checkpoint); }); break; default: throw new ArgumentException("Unknown command. Use list, replay, benchmark or test."); } if (output != null) Save(output, report); Console.WriteLine(JsonSerializer.Serialize(report, json)); return 0; } catch (Exception error) { // Paths in I/O exceptions can identify the local machine; keep structured failures generic. Console.Error.WriteLine(JsonSerializer.Serialize(new { error = error.GetType().Name, detail = error is ArgumentException ? error.Message : "The probe failed; no complete result was produced.", })); return 1; } void Save(string path, object report) { var destination = Path.GetFullPath(path); Directory.CreateDirectory(Path.GetDirectoryName(destination)!); var temporary = destination + ".tmp"; File.WriteAllText(temporary, JsonSerializer.Serialize(report, json) + "\n"); File.Move(temporary, destination, overwrite: true); }