|
|
|
|
@@ -8,56 +8,61 @@ MVVM with CommunityToolkit.Mvvm source generators:
|
|
|
|
|
- `[ObservableProperty]` for bindable properties
|
|
|
|
|
- `[RelayCommand]` for commands (supports async and CanExecute)
|
|
|
|
|
- All ViewModels inherit `ViewModelBase` (extends `ObservableObject`)
|
|
|
|
|
- All views use compiled bindings (`x:DataType`)
|
|
|
|
|
|
|
|
|
|
## Views
|
|
|
|
|
## Layout: Islands
|
|
|
|
|
|
|
|
|
|
- **MainWindow** — 3-column DockPanel layout (lists | tasks | detail) with GridSplitter, status bar at bottom
|
|
|
|
|
- **TaskListView** — ListBox of tasks with add/edit/delete toolbar
|
|
|
|
|
- **TaskDetailView** — Task info, live log output, worktree section (merge/keep/discard)
|
|
|
|
|
- **TaskEditorView** — Modal dialog for task create/edit
|
|
|
|
|
- **ListEditorView** — Modal dialog for list create/edit
|
|
|
|
|
- **StatusBarView** — Connection status indicator, active task display
|
|
|
|
|
- **ListSettingsModalView** — edits list name, working dir, default commit type, and per-list Model/SystemPrompt/AgentPath/MaxTurns, each showing the inherited (global) value with a source-aware "inherited · Global / override" badge and a reset-to-inherited button; also deletes the list (and its tasks) via a confirmed "Delete list" button. Opened via context menu or gear button on a list row.
|
|
|
|
|
- **RepoImportModalView** — bulk-creates lists from git repos discovered under chosen parent folders. Opened via the folder button beside "New list" in the Lists island, or the "Add repos as lists…" Help-menu item. Repos already wired to a list show as disabled/"(already added)".
|
|
|
|
|
- **DetailsIslandView** — contains an "Agent settings (overrides)" expander with per-task Model/MaxTurns/AgentPath (override semantics, each showing the resolved inherited value as a placeholder plus a source-aware "inherited · List / inherited · Global / override" badge and reset button via the reusable `InheritedBadge` control + `InheritanceResolver`) and a SystemPrompt text box (additive — shows the inherited prompt as a "prepended automatically" note). Disabled while task is running. When notes mode is active (`IsNotesMode`), it hosts **NotesEditorView** instead of the task detail. When prep mode is active (`IsPrepMode`), it hosts the daily-prep panel (Plan day button, empty-state hint, embedded **SessionTerminalView**). The task header, metadata footer (delete/close), and **AgentStripView** are gated on `IsTaskDetailVisible` — they are hidden in both notes and prep mode.
|
|
|
|
|
- **WeeklyReportModalView** — opened from Help menu ("Wochenbericht…"); date-range pickers default to "since last standup weekday → today"; Generate/Regenerate button; renders markdown via MarkdownView; reports are cached per range.
|
|
|
|
|
- **NotesEditorView** — day navigator (prev/next/date-picker/Today), bullet add/edit/delete for daily notes.
|
|
|
|
|
- **SessionTerminalView** — reusable log terminal; exposes StyledProperties `Entries`, `Label`, `IsRunning`, `IsDone`, `IsFailed`. Used for both the task `Log` and the prep `PrepLog`.
|
|
|
|
|
- **SettingsModalView** — Prime Claude tab contains a `DailyPrepMaxTasks` numeric editor.
|
|
|
|
|
- **TasksIslandView** (MyDay header) — icon buttons visible only when `IsMyDayList`: broom icon = `ClearDayCommand`, stroked-sun icon ("Plan My Day") = `ShowPrepLogCommand`.
|
|
|
|
|
`MainWindow` hosts three "islands" (lists | tasks | details). There is no MainWindowViewModel, StatusBarView, or task/list editor modal — the root coordinator is **IslandsShellViewModel**, and task/list editing happens inline in the islands.
|
|
|
|
|
|
|
|
|
|
All views use compiled bindings (`x:DataType`).
|
|
|
|
|
```
|
|
|
|
|
ViewModels/
|
|
|
|
|
IslandsShellViewModel.cs — root coordinator
|
|
|
|
|
Islands/ — ListsIsland, TasksIsland, DetailsIsland, TaskRow, ListNavItem,
|
|
|
|
|
NotesEditor, MergePreviewPresenter
|
|
|
|
|
Modals/ — About, Diff, ListSettings, Merge, RepoImport, Settings (+ Settings/ tab VMs),
|
|
|
|
|
UnfinishedPlanning, WeeklyReport, WorkerConnection, Worktree,
|
|
|
|
|
WorktreesOverview, UnifiedDiffParser
|
|
|
|
|
Planning/ — PlanningDiffViewModel, ConflictResolutionViewModel
|
|
|
|
|
Conflicts/ — ConflictResolverViewModel
|
|
|
|
|
Views/ — mirrors the VM layout; Islands/Detail/ holds TaskHeaderBar,
|
|
|
|
|
DescriptionStepsCard, WorkConsole; plus AgentStripView, SessionTerminalView
|
|
|
|
|
Views/Controls/ — MarkdownView, ModalShell, ThemedDatePicker, DiffLinesView, InheritedBadge
|
|
|
|
|
Design/ — Tokens.axaml (design tokens; merged before styles) + IslandStyles.axaml
|
|
|
|
|
(component styles + the filled icon geometry library)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## ViewModels
|
|
|
|
|
|
|
|
|
|
- **MainWindowViewModel** — root coordinator; manages list collection, selected list, dialog creation via `Func<T>` factories
|
|
|
|
|
- **TaskListViewModel** — manages task collection for selected list; handles CRUD, "Run Now"
|
|
|
|
|
- **TaskDetailViewModel** — displays task details, streams live log, controls worktree operations
|
|
|
|
|
- **TaskItemViewModel** / **ListItemViewModel** — lightweight display VMs
|
|
|
|
|
- **TaskEditorViewModel** / **ListEditorViewModel** — dialog VMs with validation
|
|
|
|
|
- **StatusBarViewModel** — connection state and active tasks
|
|
|
|
|
- **WeeklyReportModalViewModel** — drives the weekly report modal
|
|
|
|
|
- **NotesEditorViewModel** — manages daily note bullet CRUD for the selected day
|
|
|
|
|
- **DetailsIslandViewModel** gains `IsNotesMode`, `ShowNotes()`, and hosts `NotesEditorViewModel`. Also gains daily-prep mode: `IsPrepMode`, `PrepLog` (`ObservableCollection<LogLineViewModel>`), `ShowPrep()`, `PlanDayCommand` (calls `RunDailyPrepNowAsync`), `ShowPrepEmptyState`, and computed `IsTaskDetailVisible` (= `!IsNotesMode && !IsPrepMode`). Subscribes to `PrepStartedEvent`, `PrepLineEvent`, `PrepFinishedEvent`; streams lines into `PrepLog` via `StreamLineFormatter` (same path as task logs). On open, if log is empty and no run is in progress, loads persisted last run via `GetLastPrepLogAsync`. The WorkConsole Session tab gains a mergeability indicator (`MergePreviewPresenter`) and a single-task Merge button; indicator is populated via `PreviewMergeAsync` and displayed for tasks in WaitingForReview.
|
|
|
|
|
- **TasksIslandViewModel** gains a pinned "Notes" pseudo-row (`ShowNotesRow`, `OpenNotesCommand`, `NotesRequested` event) that switches the Details island to notes mode. Also gains `IsMyDayList` (true when selected list is `smart:my-day`), `ShowPrepLogCommand` (raises `PrepRequested` event → shell calls `Details.ShowPrep()`), and `ClearDayCommand` (calls `ClearMyDayAsync`).
|
|
|
|
|
- **IslandsShellViewModel** — root coordinator; owns the three island VMs and the `WorkerClient`, wires cross-island events (selection, notes/prep mode, conflict resolution), owns connection state, the update banner, the inline worker-log strip, responsive-layout flags (`ShowLists`/`ShowDetails` by window width), `PrimeStatus` flash, and the modal openers (About, RepoImport, WeeklyReport, WorktreesOverview, WorkerConnection help) plus `RestartWorkerAsync`/`CheckForUpdatesAsync`. Hosts `UpdateCheckService`.
|
|
|
|
|
- **ListsIslandViewModel** — smart lists (My Day, Important, Planned, virtual queued/running/review), user lists, selection, list CRUD, drag-reorder, badge counts, opens list settings / repo import / worktrees overview, `OpenInExplorer`/`OpenInTerminal`.
|
|
|
|
|
- **TasksIslandViewModel** — open/overdue/completed groups for the selected list with hierarchy-aware regrouping; task CRUD, drag-reorder, toggle done/star, schedule, enqueue/dequeue, cancel; review actions (approve, reject-rerun, reject-park, cancel); planning session lifecycle (open/resume/discard/finalize, `QueuePlanningSubtasksAsync`); `RunInteractivelyAsync`, `RefineTask`; MyDay extras (`IsMyDayList`, `ClearDayCommand`, `ShowPrepLogCommand`) and the pinned Notes pseudo-row (`ShowNotesRow`, `OpenNotesCommand`). Raises `NotesRequested`/`PrepRequested` events consumed by the shell.
|
|
|
|
|
- **DetailsIslandViewModel** — the detail pane for a bound `TaskRowViewModel`. Live-log streaming (`Log` via `StreamLineFormatter`), debounced title/description editing, subtasks, merge-target selection + mergeability indicator (`MergePreviewPresenter` over `PreviewMergeAsync`, shown in WaitingForReview), session-outcome/roadblock split (splits `Result` at the roadblock marker into two cards), per-task agent-settings overrides (Model/MaxTurns/AgentPath with `InheritedBadge` + `InheritanceResolver`; SystemPrompt is additive), and a three-tab work console (`output`/`git`/`session`). Child surfacing: `ChildOutcomes` rows for any parent plus `ChildrenNeedingAttention`/`HasChildrenNeedingAttention` (children that failed, were cancelled, await review, or reported roadblocks) drive an attention band on the Session tab, which is only visible when `HasChildOutcomes`. `OpenDiffAsync` opens the diff modal from the live worktree or — after merge — by commit range; `ReviewCombinedDiffCommand` opens `PlanningDiffViewModel`. Modes: `IsNotesMode` (hosts `NotesEditorViewModel`), `IsPrepMode` (daily-prep panel: `PrepLog`, `PlanDayCommand` → `RunDailyPrepNowAsync`, persisted last run via `GetLastPrepLogAsync`), computed `IsTaskDetailVisible = !IsNotesMode && !IsPrepMode`. Helper rows (`ChildOutcomeRowViewModel`, `SubtaskRowViewModel`, `LogLineViewModel`) live in the same file.
|
|
|
|
|
- **TaskRowViewModel** / **ListNavItemViewModel** — lightweight display VMs (task row: status, planning phase, parent/blocked links, roadblock count, computed `IsDraft`/`IsPlanned`/`IsChild`/`IsPlanningParent`/`CanRefine`; list row: kind Smart/Virtual/User, count, icon/dot keys, drop hints).
|
|
|
|
|
- **NotesEditorViewModel** — day navigator + bullet CRUD for daily notes via `INotesApi`.
|
|
|
|
|
- **Modal VMs** — `SettingsModalViewModel` (four tabs: General, Worktrees, Files prompt-paths, Prime Claude incl. `DailyPrepMaxTasks` + prime-schedule rows), `ListSettingsModalViewModel` (name, working dir, commit type, per-list Model/SystemPrompt/AgentPath/MaxTurns with inherited-badge + reset, delete list), `RepoImportModalViewModel` (bulk-create lists from git repos found under chosen parents; already-wired repos disabled), `WeeklyReportModalViewModel` (range pickers default "since last standup weekday → today", cached per range, markdown via MarkdownView), `MergeModalViewModel` (single-task merge form, called from the diff modal), `WorktreesOverviewModalViewModel` (global/per-list worktree rows, batch merge + state ops), `UnfinishedPlanningModalViewModel` (Resume/FinalizeNow/Discard for a draft planning session), `WorkerConnectionModalViewModel` (offline help), `AboutModalViewModel`.
|
|
|
|
|
- **Diff stack** — `UnifiedDiffParser` (static; parses `git diff` output into `DiffFileViewModel`s, detecting added/deleted/renamed/binary files and per-line numbers; `Flatten` injects file-header rows for a combined single-pane view). `DiffModalViewModel` has two modes: live worktree (branch diff vs base, with a Merge action) and commit-range `base..head` (`FromCommitRange = true` — shows a merged task's diff after its worktree is gone; no merge action). The view renders a file list with binary/empty placeholders via `DiffLinesView`.
|
|
|
|
|
- **Planning/Conflicts** — `PlanningDiffViewModel` (per-subtask diffs via `GetPlanningAggregateAsync`, toggle to combined integration-branch diff, conflict warnings), `ConflictResolutionViewModel` (unit-merge conflict dialog: conflicted files, open in VS Code, continue/abort planning merge), `ConflictResolverViewModel` (in-app hunk-by-hunk resolver for single-task merges: start conflict merge, resolve hunks, write resolution, continue/abort).
|
|
|
|
|
|
|
|
|
|
## Services
|
|
|
|
|
|
|
|
|
|
- **WorkerClient** / **IWorkerClient** — SignalR client connecting to `http://127.0.0.1:47821/hub`. Auto-reconnect with exponential backoff. Methods: StartAsync, RunNowAsync, CancelTaskAsync, WakeQueueAsync, ContinueTaskAsync, ResetTaskAsync, GetAgentsAsync, UpdateAppSettingsAsync, UpdateListAsync, UpdateListConfigAsync, GetListConfigAsync, UpdateTaskAgentSettingsAsync, `ApproveReviewAsync(taskId, targetBranch) -> MergeResultDto`, `PreviewMergeAsync(taskId, targetBranch) -> MergePreviewDto`, `MergeTaskAsync`, `GetWeekReportAsync`, `GenerateWeekReportAsync`, `GetDailyNotesAsync`, `AddDailyNoteAsync`, `UpdateDailyNoteAsync`, `DeleteDailyNoteAsync`, `RunDailyPrepNowAsync`, `ClearMyDayAsync`, `GetLastPrepLogAsync`. Events: TaskStarted, TaskFinished, TaskMessage, TaskUpdated, WorktreeUpdated, ListUpdated, `PrepStartedEvent`, `PrepLineEvent`, `PrepFinishedEvent`
|
|
|
|
|
- **INotesApi** / **WorkerNotesApi** — thin wrapper over the daily-note WorkerClient methods (mirrors `IPrimeScheduleApi`). UI DTO: `DailyNoteDto(Id, Date, Text, SortOrder)`.
|
|
|
|
|
- **WorkerClient** / **IWorkerClient** — SignalR client connecting to `http://127.0.0.1:47821/hub`, auto-reconnect with exponential backoff. The surface tracks `WorkerHub` (see `src/ClaudeDo.Worker/CLAUDE.md` for the canonical method/event list); groups: task execution (RunNow/Cancel/Continue/Reset/SetTaskStatus), review (`ApproveReviewAsync(taskId, targetBranch) -> MergeResultDto`, reject-to-queue/idle, cancel review, `PreviewMergeAsync -> MergePreviewDto`), planning sessions (start/resume/discard/finalize, queue subtasks, pending draft count, interactive terminal, refine), planning aggregate/integration-branch diffs, unit-merge continue/abort, single-task conflict resolving (start/get-conflicts/write-resolution/continue/abort), worktrees (overview, set state, force remove, cleanup, reset all), agents, app settings, lists/config, weekly report, daily notes, daily prep (`RunDailyPrepNowAsync`, `ClearMyDayAsync`, `GetLastPrepLogAsync`), prime schedules. Events mirror `HubBroadcaster` (task/worktree/list/run updates, prep events, planning-merge events, refine events, worker log). Lifecycle (`StartAsync`/`StopAsync`) and a few admin methods live only on the concrete `WorkerClient`.
|
|
|
|
|
- **INotesApi** / **WorkerNotesApi** — daily-note CRUD (`ListAsync(day)`, `AddAsync`, `UpdateAsync`, `DeleteAsync`); UI DTO `DailyNoteDto(Id, Date, Text, SortOrder)`.
|
|
|
|
|
- **IPrimeScheduleApi** — prime-schedule CRUD (`ListAsync`, `UpsertAsync`, `DeleteAsync`).
|
|
|
|
|
- **UpdateCheckService** — polls releases, exposes `LastCheckStatus`/`LatestVersion`/`CheckNowAsync` (feeds the shell's update banner).
|
|
|
|
|
- **InheritanceResolver** — resolves the task → list → global override chain to `(value, source)` for the inherited badges.
|
|
|
|
|
- **RepoScanner**, **InstallArtifactLocator**/**InstallerLocator**/**WorkerLocator**, **ForegroundHelper** (Win32 foreground before launching a terminal), **FocusClearing**.
|
|
|
|
|
|
|
|
|
|
## Converters
|
|
|
|
|
|
|
|
|
|
- **StatusColorConverter** — task status string -> color (Queued=Blue, Running=Orange, Done=Green, Failed=Red, Manual=Gray)
|
|
|
|
|
- **ConnectionColorConverter** — connection state -> color (Online=Green, Offline=Red)
|
|
|
|
|
`StatusColorConverter` (+ `ConnectionColorConverter` in the same file), `WorktreeStateColorConverter`, `WorkerLogLevelToBrushConverter`, `DotBrushConverter`, `EqStatusConverter`, `IconKeyConverter`, `CheckboxBorderConverter`, `StrikeIfTrueConverter`, `BoolToItalicConverter`, `BoolToDraftOpacityConverter`, `NotNullToBoolConverter`, `UpperCaseConverter`, `DateOnlyToDateTimeConverter`.
|
|
|
|
|
|
|
|
|
|
## Dialog Pattern
|
|
|
|
|
|
|
|
|
|
Editor dialogs use `TaskCompletionSource<bool>` — the dialog sets the result on save/cancel, and the caller awaits the TCS.
|
|
|
|
|
Modals use `TaskCompletionSource` results behind the reusable `ModalShell` control — the dialog sets the result on save/cancel, and the caller awaits the TCS.
|
|
|
|
|
|
|
|
|
|
## Notes
|
|
|
|
|
|
|
|
|
|
- Context menus are on both list items and task items
|
|
|
|
|
- Right-click selects the item before showing the context menu
|
|
|
|
|
- Context menus exist on both list rows and task rows; right-click selects before opening the menu
|
|
|
|
|
- "Run Now" CanExecute re-evaluates when worker connection state changes
|
|
|
|
|
- Icon gotcha: `PathIcon` fills geometry. Line-art/stroke icons must be defined as filled geometry or rendered as a stroked `Path` (e.g. `Icon.PlanDay` via the `Path.plan-icon` style); a pure stroke path used with `PathIcon` is invisible.
|
|
|
|
|
- `SessionTerminalView` is the reusable log terminal (StyledProperties `Entries`, `Label`, `IsRunning`, `IsDone`, `IsFailed`) used for both the task `Log` and the prep `PrepLog`.
|
|
|
|
|
|