Add runner.csx script
This commit is contained in:
154
docs/runner.csx
Normal file
154
docs/runner.csx
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env dotnet-script
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// ── Ctrl+C: kill active process and exit cleanly ──────────────────────────────
|
||||
var cts = new CancellationTokenSource();
|
||||
Process? activeProcess = null;
|
||||
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
e.Cancel = true;
|
||||
Console.WriteLine("\n[runner] Interrupted — shutting down...");
|
||||
cts.Cancel();
|
||||
try { activeProcess?.Kill(entireProcessTree: true); } catch { }
|
||||
};
|
||||
|
||||
// ── Paths ─────────────────────────────────────────────────────────────────────
|
||||
var repoRoot = Directory.GetCurrentDirectory();
|
||||
var tasksFile = Path.Combine(repoRoot, "Docs", "Tasks.md");
|
||||
|
||||
if (!File.Exists(tasksFile))
|
||||
{
|
||||
Console.Error.WriteLine($"[runner] ERROR: Tasks.md not found at {tasksFile}");
|
||||
Console.Error.WriteLine("[runner] Run this script from the repository root.");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// ── Read & split by "---" separator lines ────────────────────────────────────
|
||||
var content = File.ReadAllText(tasksFile);
|
||||
var items = Regex
|
||||
.Split(content, @"\r?\n---\r?\n")
|
||||
.Select(s => s.Trim())
|
||||
.Where(s => s.Length > 0)
|
||||
.ToList();
|
||||
|
||||
Console.WriteLine($"[runner] Found {items.Count} section(s) in Tasks.md");
|
||||
|
||||
// ── Helper: run copilot and stream output, return full output ─────────────────
|
||||
async Task<string> RunCopilot(IEnumerable<string> extraArgs, string prompt)
|
||||
{
|
||||
var output = new StringBuilder();
|
||||
|
||||
var argList = new List<string> { "launch", "copilot", "--model", "minimax-m2.7:cloud", "--yes", "--", "--allow-all-tools" };
|
||||
argList.AddRange(extraArgs);
|
||||
argList.Add("-p");
|
||||
argList.Add(prompt);
|
||||
|
||||
var psi = new ProcessStartInfo("ollama")
|
||||
{
|
||||
WorkingDirectory = repoRoot,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
};
|
||||
foreach (var a in argList)
|
||||
psi.ArgumentList.Add(a);
|
||||
|
||||
activeProcess = new Process { StartInfo = psi };
|
||||
|
||||
activeProcess.OutputDataReceived += (_, e) =>
|
||||
{
|
||||
if (e.Data is null) return;
|
||||
Console.WriteLine(e.Data);
|
||||
output.AppendLine(e.Data);
|
||||
};
|
||||
activeProcess.ErrorDataReceived += (_, e) =>
|
||||
{
|
||||
if (e.Data is null) return;
|
||||
Console.Error.WriteLine(e.Data);
|
||||
output.AppendLine(e.Data);
|
||||
};
|
||||
|
||||
activeProcess.Start();
|
||||
activeProcess.BeginOutputReadLine();
|
||||
activeProcess.BeginErrorReadLine();
|
||||
|
||||
await activeProcess.WaitForExitAsync(cts.Token);
|
||||
activeProcess = null;
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
// ── Main loop ─────────────────────────────────────────────────────────────────
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
if (cts.IsCancellationRequested) break;
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("[runner] ══════════════════════════════════════════════");
|
||||
Console.WriteLine($"[runner] Task:\n{item}");
|
||||
Console.WriteLine("[runner] ══════════════════════════════════════════════");
|
||||
Console.WriteLine();
|
||||
|
||||
// Step 1 — run the task prompt
|
||||
await RunCopilot(Enumerable.Empty<string>(), $"/caveman full");
|
||||
await RunCopilot(new[] { "--continue" }, $"read ./Docs/instructions.md. {item}");
|
||||
if (cts.IsCancellationRequested) break;
|
||||
|
||||
// Step 2 — confirm completion in the same chat session
|
||||
Console.WriteLine("\n[runner] Asking for task confirmation...\n");
|
||||
var confirmation = await RunCopilot(
|
||||
new[] { "--continue" },
|
||||
"are you sure tasks is done. reply with yes"
|
||||
);
|
||||
if (cts.IsCancellationRequested) break;
|
||||
|
||||
// Step 3 — check for "yes" in the reply, with retry logic for issue resolution
|
||||
int maxRetries = 3;
|
||||
int retryCount = 0;
|
||||
bool taskConfirmed = confirmation.Contains("yes", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
while (!taskConfirmed && retryCount < maxRetries)
|
||||
{
|
||||
retryCount++;
|
||||
Console.WriteLine($"\n[runner] Attempt {retryCount}/{maxRetries}: Resolving remaining issues and running tests...\n");
|
||||
|
||||
confirmation = await RunCopilot(
|
||||
new[] { "--continue" },
|
||||
"resolve any remaining issues, make sure all tests are running and pass. then confirm with yes if done"
|
||||
);
|
||||
if (cts.IsCancellationRequested) break;
|
||||
|
||||
taskConfirmed = confirmation.Contains("yes", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (!taskConfirmed)
|
||||
{
|
||||
Console.WriteLine($"\n[runner] Task not confirmed as done after {maxRetries} attempts. Stopping.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Step 4 — commit the work
|
||||
Console.WriteLine("\n[runner] Task confirmed. Making git commit...\n");
|
||||
|
||||
await RunCopilot(Enumerable.Empty<string>(), $"/caveman full");
|
||||
await RunCopilot(new[] { "--continue" }, "make git commit");
|
||||
if (cts.IsCancellationRequested) break;
|
||||
|
||||
// Step 5 — remove completed task from Tasks.md
|
||||
var remaining = items.Skip(i + 1).ToList();
|
||||
File.WriteAllText(tasksFile, string.Join("\n\n---\n\n", remaining));
|
||||
Console.WriteLine("[runner] Removed completed task from Tasks.md");
|
||||
}
|
||||
|
||||
Console.WriteLine("\n[runner] Finished.");
|
||||
Reference in New Issue
Block a user