feat(review): submit interactive (ConPTY) work for review

An embedded ConPTY session leaves its worktree changed but never touches
task status, so hand-driven work had no path into the review/merge flow.

Add SubmitTaskForReview: commit the worktree (same auto-commit as a headless
run), then transition Idle/Failed -> WaitingForReview via the new
TaskStateService.SubmitInteractiveForReviewAsync. Approve then merges it.

Surfaces: a 'Submit for review' button in the detail work console (shown for
an Idle/Failed task with a worktree) and on the ConPTY Command Center pane
header (task-based panes; closes the pane on success). Tests cover the new
transition (Idle/Failed accepted, Running/Queued/Done/Review rejected).
This commit is contained in:
mika kuns
2026-07-24 13:05:22 +02:00
parent 34b17537fc
commit 109a35c505
15 changed files with 178 additions and 3 deletions
@@ -87,6 +87,38 @@ public sealed class ReviewTransitionTests : IDisposable
Assert.Equal(TaskStatus.Queued, (await GetTaskAsync(id)).Status);
}
// ─── SubmitInteractiveForReviewAsync ──────────────────────────────────
[Theory]
[InlineData(TaskStatus.Idle)]
[InlineData(TaskStatus.Failed)]
public async Task SubmitInteractiveForReviewAsync_FromIdleOrFailed_TransitionsToWaitingForReview(TaskStatus from)
{
var id = await SeedTaskAsync(from);
var result = await _sut.SubmitInteractiveForReviewAsync(id, DateTime.UtcNow, default);
Assert.True(result.Ok);
var t = await GetTaskAsync(id);
Assert.Equal(TaskStatus.WaitingForReview, t.Status);
Assert.NotNull(t.FinishedAt);
}
[Theory]
[InlineData(TaskStatus.Running)]
[InlineData(TaskStatus.Queued)]
[InlineData(TaskStatus.Done)]
[InlineData(TaskStatus.WaitingForReview)]
public async Task SubmitInteractiveForReviewAsync_FromOtherStates_Rejects(TaskStatus from)
{
var id = await SeedTaskAsync(from);
var result = await _sut.SubmitInteractiveForReviewAsync(id, DateTime.UtcNow, default);
Assert.False(result.Ok);
Assert.Equal(from, (await GetTaskAsync(id)).Status);
}
// ─── ApproveReviewAsync ───────────────────────────────────────────────
[Fact]