feat(daily-prep): stream prep output via PrepStarted/PrepLine/PrepFinished
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -54,4 +54,12 @@ public sealed class HubBroadcaster : IPrimeBroadcaster
|
||||
|
||||
Task IPrimeBroadcaster.PrimeFiredAsync(Guid scheduleId, bool success, string message, DateTimeOffset firedAt) =>
|
||||
PrimeFired(scheduleId, success, message, firedAt);
|
||||
|
||||
public Task PrepStarted() => _hub.Clients.All.SendAsync("PrepStarted");
|
||||
public Task PrepLine(string line) => _hub.Clients.All.SendAsync("PrepLine", line);
|
||||
public Task PrepFinished(bool success) => _hub.Clients.All.SendAsync("PrepFinished", success);
|
||||
|
||||
Task IPrimeBroadcaster.PrepStartedAsync() => PrepStarted();
|
||||
Task IPrimeBroadcaster.PrepLineAsync(string line) => PrepLine(line);
|
||||
Task IPrimeBroadcaster.PrepFinishedAsync(bool success) => PrepFinished(success);
|
||||
}
|
||||
|
||||
@@ -3,4 +3,7 @@ namespace ClaudeDo.Worker.Prime;
|
||||
public interface IPrimeBroadcaster
|
||||
{
|
||||
Task PrimeFiredAsync(Guid scheduleId, bool success, string message, DateTimeOffset firedAt);
|
||||
Task PrepStartedAsync();
|
||||
Task PrepLineAsync(string line);
|
||||
Task PrepFinishedAsync(bool success);
|
||||
}
|
||||
|
||||
@@ -14,18 +14,21 @@ public sealed class PrimeRunner : IPrimeRunner
|
||||
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
|
||||
private readonly IPrimeClock _clock;
|
||||
private readonly ILogger<PrimeRunner> _logger;
|
||||
private readonly IPrimeBroadcaster _broadcaster;
|
||||
private readonly SemaphoreSlim _gate = new(1, 1);
|
||||
|
||||
public PrimeRunner(
|
||||
IClaudeProcess claude,
|
||||
IDbContextFactory<ClaudeDoDbContext> dbFactory,
|
||||
IPrimeClock clock,
|
||||
ILogger<PrimeRunner> logger)
|
||||
ILogger<PrimeRunner> logger,
|
||||
IPrimeBroadcaster broadcaster)
|
||||
{
|
||||
_claude = claude;
|
||||
_dbFactory = dbFactory;
|
||||
_clock = clock;
|
||||
_logger = logger;
|
||||
_broadcaster = broadcaster;
|
||||
}
|
||||
|
||||
public async Task<PrimeRunOutcome> FireAsync(PrimeScheduleDto schedule, CancellationToken ct)
|
||||
@@ -33,8 +36,11 @@ public sealed class PrimeRunner : IPrimeRunner
|
||||
if (!await _gate.WaitAsync(0, ct))
|
||||
return new PrimeRunOutcome(false, "Daily prep already running");
|
||||
|
||||
var success = false;
|
||||
try
|
||||
{
|
||||
await _broadcaster.PrepStartedAsync();
|
||||
|
||||
var cwd = Paths.AppDataRoot();
|
||||
Directory.CreateDirectory(cwd);
|
||||
|
||||
@@ -56,10 +62,11 @@ public sealed class PrimeRunner : IPrimeRunner
|
||||
arguments: args,
|
||||
prompt: prompt,
|
||||
workingDirectory: cwd,
|
||||
onStdoutLine: _ => Task.CompletedTask,
|
||||
onStdoutLine: line => _broadcaster.PrepLineAsync(line),
|
||||
ct: timeoutCts.Token);
|
||||
|
||||
return result.IsSuccess
|
||||
success = result.IsSuccess;
|
||||
return success
|
||||
? new PrimeRunOutcome(true, "Daily prep complete")
|
||||
: new PrimeRunOutcome(false, $"exit code {result.ExitCode}");
|
||||
}
|
||||
@@ -74,6 +81,7 @@ public sealed class PrimeRunner : IPrimeRunner
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _broadcaster.PrepFinishedAsync(success);
|
||||
_gate.Release();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user