feat(mcp): add save_finding to the external server

This commit is contained in:
mika kuns
2026-08-10 10:19:45 +02:00
parent 9a09dd6186
commit 2d4288abca
4 changed files with 93 additions and 4 deletions
+10 -3
View File
@@ -13,7 +13,7 @@ public static class GitExcludeWriter
/// <summary>Idempotent — an already-present line is left alone.</summary>
public static async Task AppendLineAsync(string workingDir, string excludeLine, CancellationToken ct)
{
var relativeExcludePath = await RunGitCaptureAsync(workingDir, ["rev-parse", "--git-path", "info/exclude"], ct);
var relativeExcludePath = await RevParseAsync(workingDir, ["rev-parse", "--git-path", "info/exclude"], ct);
var excludeFile = Path.IsPathRooted(relativeExcludePath)
? relativeExcludePath
: Path.GetFullPath(Path.Combine(workingDir, relativeExcludePath));
@@ -32,7 +32,13 @@ public static class GitExcludeWriter
await File.AppendAllTextAsync(excludeFile, excludeLine + Environment.NewLine, ct);
}
private static async Task<string> RunGitCaptureAsync(string workingDir, IEnumerable<string> args, CancellationToken ct)
/// <summary>
/// Runs a `git` invocation and captures stdout. Named for its most common caller
/// (rev-parse), but shared plumbing for any short git query that needs one line of output —
/// non-zero exit throws <see cref="InvalidOperationException"/>. Shared by AppendLineAsync
/// above and by GitHead.ShortAsync.
/// </summary>
internal static async Task<string> RevParseAsync(string workingDir, IEnumerable<string> args, CancellationToken ct)
{
var psi = new ProcessStartInfo
{
@@ -67,7 +73,8 @@ public static class GitExcludeWriter
ct.ThrowIfCancellationRequested();
if (proc.ExitCode != 0)
throw new InvalidOperationException($"git rev-parse --git-path failed (exit {proc.ExitCode}): {stderr.TrimEnd()}");
throw new InvalidOperationException(
$"git {string.Join(' ', args)} failed (exit {proc.ExitCode}): {stderr.TrimEnd()}");
return stdout.TrimEnd('\r', '\n');
}
+21
View File
@@ -0,0 +1,21 @@
namespace ClaudeDo.Worker.Git;
/// <summary>Short HEAD of a checkout, stamped into a finding's frontmatter so staleness is visible.</summary>
public static class GitHead
{
/// <summary>
/// Never throws — a fresh repo with no commits yet, or a working dir that is not a git repo
/// at all, must not block a finding save. Callers get "unknown" instead.
/// </summary>
public static async Task<string> ShortAsync(string workingDir, CancellationToken ct)
{
try
{
return await GitExcludeWriter.RevParseAsync(workingDir, ["rev-parse", "--short", "HEAD"], ct);
}
catch (InvalidOperationException)
{
return "unknown";
}
}
}