Merge branch 'claudedo/387-unit-branch-teil-3-firmen-modus-fetch-pu'

This commit is contained in:
mika kuns
2026-10-01 12:30:13 +02:00
40 changed files with 2857 additions and 47 deletions
+49 -3
View File
@@ -18,6 +18,7 @@ using ClaudeDo.Worker.Report;
using ClaudeDo.Worker.Report.Interfaces;
using ClaudeDo.Worker.Skills;
using ClaudeDo.Worker.State;
using ClaudeDo.Worker.AzureDevOps;
using ClaudeDo.Worker.Tickets;
using ClaudeDo.Worker.Usage;
using ClaudeDo.Worker.Usage.Interfaces;
@@ -76,6 +77,8 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
private readonly HandlerRoundState? _roundState;
private readonly ConnectedClientTracker? _clientTracker;
private readonly RunningOperationRegistry? _operations;
private readonly AzureDevOpsPatStore? _azdoPat;
private readonly AzureDevOpsClient? _azdo;
public WorkerHub(
QueueService queue,
@@ -118,7 +121,9 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
HandlerRestartCoordinator? handlerRestart = null,
HandlerRoundState? roundState = null,
ConnectedClientTracker? clientTracker = null,
RunningOperationRegistry? operations = null)
RunningOperationRegistry? operations = null,
AzureDevOpsPatStore? azdoPat = null,
AzureDevOpsClient? azdo = null)
{
_queue = queue;
_waker = waker;
@@ -161,6 +166,8 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
_roundState = roundState;
_clientTracker = clientTracker;
_operations = operations;
_azdoPat = azdoPat;
_azdo = azdo;
}
// Tracks connected UI clients so an out-of-band caller (external MCP's start_list_handler)
@@ -509,7 +516,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
=> HubGuard(async () =>
{
var t = await _mergeService.GetTargetsAsync(taskId, CancellationToken.None);
return new MergeTargetsDto(t.DefaultBranch, t.LocalBranches, t.DefaultCommitMessage, t.TargetDirty);
return new MergeTargetsDto(t.DefaultBranch, t.LocalBranches, t.DefaultCommitMessage, t.TargetDirty, t.IsCompanyRepo);
});
public Task<MergePreviewDto> PreviewMerge(string taskId, string targetBranch)
@@ -721,7 +728,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
var r = await _mergeService.ApproveAndMergeAsync(taskId, targetBranch ?? "", CancellationToken.None, autostash);
if (r.Status == TaskMergeService.StatusBlocked)
throw new HubException(r.ErrorMessage ?? "approve failed");
return new MergeResultDto(r.Status, r.ConflictFiles, r.ErrorMessage);
return new MergeResultDto(r.Status, r.ConflictFiles, r.ErrorMessage, r.PullRequestUrl);
});
public async Task RejectReviewToQueue(string taskId, string feedback)
@@ -1428,6 +1435,45 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
}
}
public AzureDevOpsSettingsDto GetAzureDevOpsSettings() => new(_azdoPat?.Store.Exists() == true);
public void SetAzureDevOpsToken(string token)
{
if (_azdoPat is null) return;
if (string.IsNullOrWhiteSpace(token)) _azdoPat.Store.Clear();
else _azdoPat.Store.Save(token.Trim());
}
public void ClearAzureDevOpsToken() => _azdoPat?.Store.Clear();
/// <summary>Reads the first company repo's ADO repository (default branch). Errors are answers, not throws — same reason as TestTicketConnection.</summary>
public async Task<AzureDevOpsConnectionDto> TestAzureDevOpsConnection()
{
if (_azdo is null) return new AzureDevOpsConnectionDto(false, null, null, "Azure DevOps ist im Worker nicht registriert.");
try
{
var git = _git ?? new Data.Git.GitService();
List<string> dirs;
await using (var ctx = await _dbFactory.CreateDbContextAsync(Context.ConnectionAborted))
dirs = await ctx.Lists.AsNoTracking().Where(l => l.WorkingDir != null).Select(l => l.WorkingDir!).ToListAsync(Context.ConnectionAborted);
foreach (var dir in dirs)
{
if (!Directory.Exists(dir)) continue;
var remote = await git.GetRemoteUrlAsync(dir, "origin", Context.ConnectionAborted);
if (!Git.CompanyRepo.Matches(remote, _cfg.CompanyRemotePattern) || AzureDevOpsClient.ParseRemote(remote) is not { } repo)
continue;
var branch = await _azdo.GetDefaultBranchAsync(repo, Context.ConnectionAborted);
return new AzureDevOpsConnectionDto(true, repo.Repo, branch, null);
}
return new AzureDevOpsConnectionDto(false, null, null, "Keine Liste zeigt auf ein Firmen-Repo (origin mit " + _cfg.CompanyRemotePattern + ").");
}
catch (Exception ex)
{
return new AzureDevOpsConnectionDto(false, null, null, ex.Message);
}
}
public async Task<List<TicketProjectDto>> GetTicketProjects()
{
var client = _ticketClients.Create();