diff --git a/docs/open.md b/docs/open.md index d462a007..2f5f3fa0 100644 --- a/docs/open.md +++ b/docs/open.md @@ -37,7 +37,6 @@ Kein Code-Aufwand, nur Durchspielen mit explizit notiertem Pass-Kriterium. Der G ## Offene Code-Punkte - **Status-Bar Live-Update:** Prüfen, ob `RunNow`-Enable/Disable pro Task-Row bei Connection-Change sauber re-evaluiert. Connection-Status lebt in `IslandsShellViewModel` / `WorkerConnectionModalViewModel` (es gibt keinen `StatusBarViewModel` mehr). Erst messen, dann ggf. fixen. Klein. -- **`AgentMcpTools` liegt in `LifecycleMcpTools.cs`** — beim Suchen irreführend; in eigene Datei verschieben. Ein-Minuten-Fix, lohnt keinen Agent-Lauf — beim nächsten Worker-Touch mitnehmen. ## Nachklapp Refactoring-/Bug-Runde (2026-06-09/10) diff --git a/src/ClaudeDo.Data/Git/GitService.cs b/src/ClaudeDo.Data/Git/GitService.cs index 372b56dd..e4f28966 100644 --- a/src/ClaudeDo.Data/Git/GitService.cs +++ b/src/ClaudeDo.Data/Git/GitService.cs @@ -343,13 +343,6 @@ public sealed class GitService .Count(s => s.Length > 0); } - public async Task MergeFfOnlyAsync(string repoDir, string branchName, CancellationToken ct = default) - { - var (exitCode, _, stderr) = await RunGitAsync(repoDir, ["merge", "--ff-only", branchName], ct); - if (exitCode != 0) - throw new InvalidOperationException($"Fast-forward merge of '{branchName}' failed. Manual merge required. git stderr: {stderr}"); - } - private static async Task<(int ExitCode, string Stdout, string Stderr)> RunGitAsync( string workDir, IEnumerable args, CancellationToken ct, string? stdinData = null, bool trimOutput = true) { diff --git a/src/ClaudeDo.Worker/CLAUDE.md b/src/ClaudeDo.Worker/CLAUDE.md index 3d38a61a..0819e3bc 100644 --- a/src/ClaudeDo.Worker/CLAUDE.md +++ b/src/ClaudeDo.Worker/CLAUDE.md @@ -20,7 +20,7 @@ Worker/ Logging/ — LogRingBuffer (30-min in-memory log window) + BroadcastLogSink (Serilog sink → footer + overlay) Report/ — ClaudeHistoryReader, WeekReportPromptBuilder, WeekReportService; interfaces in Report/Interfaces/ Prime/ — daily-prep ("Prime Claude"): PrimeScheduler (BackgroundService), PrimeRunner (runs the daily prep), DailyPrepPrompt (fixed prompt + CLI args + LogPath() helper), NextDueCalculator, PrimeScheduleSignal; interfaces in Prime/Interfaces/ (IPrimeRunner, IPrimeClock, IPrimeScheduleSignal, IPrimeBroadcaster) - Online/ — optional Online Inbox sync: OnlineInboxConfig (config record), Dtos (RemoteList/RemoteTask/MirrorTask), IOnlineInboxApi, OnlineInboxApiClient (typed HttpClient, bearer auth, HTTPS guard), OnlineTokenStore (DPAPI refresh-token store, Windows-only), StaticTokenAuthProvider (default/test IOnlineAuthProvider), ZitadelAuthProvider (stub — TODO(online-inbox) Phase 2), OnlineSyncService (BackgroundService: reconcile loop), OnlineBacklog (Idle-backlog filter/query); interface in Online/Interfaces/ (IOnlineAuthProvider) + Online/ — optional Online Inbox sync: OnlineInboxConfig (config record), Dtos (RemoteList/RemoteTask/MirrorTask), IOnlineInboxApi, OnlineInboxApiClient (typed HttpClient, bearer auth, HTTPS guard), OnlineTokenStore (DPAPI refresh-token store, Windows-only), StaticTokenAuthProvider (default/test IOnlineAuthProvider), ZitadelAuthProvider (OIDC discovery + refresh-token flow), OnlineSyncService (BackgroundService: reconcile loop), OnlineBacklog (Idle-backlog filter/query); interface in Online/Interfaces/ (IOnlineAuthProvider) ``` Interfaces (e.g. `IQueueWaker`, `IPrimeClock`, `ITaskStateService`) live in an `Interfaces/` subfolder within their area; the namespace stays the area namespace. @@ -38,7 +38,7 @@ Interfaces (e.g. `IQueueWaker`, `IPrimeClock`, `ITaskStateService`) live in an ` - `ListMcpTools` — `CreateList`, `UpdateList`, `DeleteList` - `ConfigMcpTools` — `GetListConfig`, `SetListConfig`, `GetTaskConfig`, `SetTaskConfig` - `RunHistoryMcpTools` — `ListRuns`, `GetRun`, `GetTaskLog` (latest run's log, tail-capped at 256 KB) - - `AgentMcpTools` — `ListAgents` (class lives in `LifecycleMcpTools.cs`) + - `AgentMcpTools` — `ListAgents` - `LifecycleMcpTools` — `ResetFailedTask` - `AppSettingsMcpTools` — `GetAppSettings` (read-only) - `AttachmentMcpTools` — `AddTaskAttachment(taskId, fileName, textContent?|base64Content?)`, `ListTaskAttachments`, `RemoveTaskAttachment`. Re-attaching the same fileName overwrites; add/remove refuse on a Running task. @@ -177,7 +177,7 @@ Loaded from `~/.todo-app/worker.config.json`: - `enabled` (bool, default false) — when false the entire `Online/` stack is not registered - `api_base_url` (string) — must be HTTPS or loopback; validated at startup when enabled - `poll_interval_seconds` (int, default 60) - - `zitadel.authority`, `zitadel.client_id`, `zitadel.scopes` (Phase 2; not used until ZitadelAuthProvider is wired) + - `zitadel.authority`, `zitadel.client_id`, `zitadel.scopes` — used by `ZitadelAuthProvider` (OIDC discovery + refresh-token flow) - The refresh token is NOT in this file — stored encrypted via DPAPI at `~/.todo-app/online-inbox.token` Per-list config (`list_config` in DB) provides defaults for `model`, `system_prompt`, `agent_path`; tasks can override each individually. Task-generating MCP tools (`AddTask`, planning `CreateChildTask`, `SuggestImprovement`) accept an optional `model` (alias-validated via `ModelRegistry.NormalizeAlias` — `haiku`/`sonnet`/`opus`, blank = inherit) so Claude assigns the cheapest capable model at creation time; the planning/system/improvement prompts instruct it to do so (`ModelRegistry.ByCostAscending` = the cost order). diff --git a/src/ClaudeDo.Worker/External/AgentMcpTools.cs b/src/ClaudeDo.Worker/External/AgentMcpTools.cs new file mode 100644 index 00000000..80509602 --- /dev/null +++ b/src/ClaudeDo.Worker/External/AgentMcpTools.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; +using ClaudeDo.Data.Models; +using ClaudeDo.Worker.Agents; +using ModelContextProtocol.Server; + +namespace ClaudeDo.Worker.External; + +[McpServerToolType] +public sealed class AgentMcpTools +{ + private readonly AgentFileService _agents; + + public AgentMcpTools(AgentFileService agents) => _agents = agents; + + [McpServerTool, Description("List available agent definition files (name, description, path) for use as a task's agent path.")] + public async Task> ListAgents(CancellationToken cancellationToken) + => await _agents.ScanAsync(cancellationToken); +} diff --git a/src/ClaudeDo.Worker/External/LifecycleMcpTools.cs b/src/ClaudeDo.Worker/External/LifecycleMcpTools.cs index 33cad9d8..5fe23389 100644 --- a/src/ClaudeDo.Worker/External/LifecycleMcpTools.cs +++ b/src/ClaudeDo.Worker/External/LifecycleMcpTools.cs @@ -1,25 +1,11 @@ using System.ComponentModel; -using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; -using ClaudeDo.Worker.Agents; using ClaudeDo.Worker.Lifecycle; using ModelContextProtocol.Server; using TaskStatus = ClaudeDo.Data.Models.TaskStatus; namespace ClaudeDo.Worker.External; -[McpServerToolType] -public sealed class AgentMcpTools -{ - private readonly AgentFileService _agents; - - public AgentMcpTools(AgentFileService agents) => _agents = agents; - - [McpServerTool, Description("List available agent definition files (name, description, path) for use as a task's agent path.")] - public async Task> ListAgents(CancellationToken cancellationToken) - => await _agents.ScanAsync(cancellationToken); -} - [McpServerToolType] public sealed class LifecycleMcpTools {