Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ submodule.
- **More ways for agents to collaborate.** Agents can ask for an immediate answer or a background reply, send information, request a read-only review, hand off work, and update or cancel individual jobs. Messages and results appear in expandable transcript entries that identify the agents involved. Background jobs use readable IDs such as `job1`, support bounded waits, and cancel when an associated agent closes. The existing `ask_agent` tool remains available alongside `ask_agent_and_wait`.

### Changed
- **Organize Desktop source by feature.** Group Controls and Services into feature folders and MainWindow partial files by responsibility. Keep XAML and code-behind together, update test-project source links, and add folder guides. Existing namespaces, control identities, and application behavior remain unchanged.
- **Two levels of tabs with matching scroll spacing.** Workspace tabs sit above agent tabs. Split and New agent stay beside the agents they control in the selected workspace. Both rows reserve space beneath their tabs for horizontal scrollbars, and agent mentions show the workspace name alongside the project folder.
- **Separate Files and Agents mentions.** Typing `@` opens Files first; press Tab to switch to Agents and back. Gold headers explain the switch. Agent rows show name and project folder, files retain explicit paths when names collide, and quoted paths/names support spaces.
- **Responsive file tagging on large projects.** Reuse the CLI's asynchronous file index, early root listing, shared scan/cache, query debounce, and filesystem watcher. Closing the picker keeps indexing in progress. Build result rows off the UI thread, replace the list in one batch, preserve selection across updates, ignore stale lookups, and show loading/indexing feedback. End drill-down when a selected folder is empty, and dispose file watchers when the tab closes.
Expand Down Expand Up @@ -634,7 +635,7 @@ are visible until you actually open a second tab.
typing never waits on file IO and 60 logs aren't re-read per keystroke. Each scan carries a
generation stamp so a slower earlier scan can't overwrite a later keystroke's results, and queries
under two characters don't trigger one at all. Matching and snippet extraction live in
`Services/ConversationSearch.cs`, kept pure and unit tested (+24 tests).
`Services/Sessions/ConversationSearch.cs`, kept pure and unit tested (+24 tests).
- **Snapshots panel — grouping, search, and a cleaner import.** Snapshot cards now group by the
project they were taken in (freshest project first), a search box filters by title/recap/model/
project, and Import closes the panel and focuses the chat so the "context armed" confirmation is
Expand Down Expand Up @@ -667,7 +668,7 @@ are visible until you actually open a second tab.
of them. Panes are ordinary agent views moved between grid cells via `Grid.SetColumn`/`Grid.SetRow`
— never re-parented — so every WebView and its live transcript survives the switch; the row and
column tracks are rebuilt in code per pane count, and track definitions plus dividers are the only
things that change. Geometry and divider math live in `Services/PaneLayout.cs`, free of WinUI types
things that change. Geometry and divider math live in `Services/Workspaces/PaneLayout.cs`, free of WinUI types
and unit tested. The split bar uses chips with `MenuFlyout` pickers rather than `ComboBox`es,
which sidesteps the `COMException 0x80070490` that rebuilding ComboBox item containers triggers.
Named *split view* rather than *compare* because comparing two models on one prompt is only one of
Expand Down
22 changes: 15 additions & 7 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,27 @@ compile independently of the CLI's originals):
| Desktop port | CLI original |
|---|---|
| `ViewModels/ChatController.cs` | `Components/App.razor` interactive loop |
| `Services/WinUiApprovalService.cs` | `Services/Approval/DiffApprovalHandler.cs` |
| `Services/TranscriptHtmlBuilder.cs` | `MarkdownHtmlRenderer` / `OperationDisplayRenderer` |
| `Services/Approval/WinUiApprovalService.cs` | `Services/Approval/DiffApprovalHandler.cs` |
| `Services/Rendering/TranscriptHtmlBuilder.cs` | `MarkdownHtmlRenderer` / `OperationDisplayRenderer` |

The harness is safe to instantiate once per agent — its statics are pure functions and readonly
`Regex`, and `AIService` takes every collaborator by constructor. Rolling the pin forward, watch
for that changing.

## Source organization

The window XAML and its code-behind live under `MainWindow/`. Partial files are grouped into Agents, Navigation, Panels, Settings, and Shared; see the [window guide](../src/MandoCode.Desktop/MainWindow/README.md). They retain the same namespaces and still form the same window.

Desktop controls are grouped by feature under `Controls/`; keep each control's XAML, code-behind, and partial files together. See the [control guide](../src/MandoCode.Desktop/Controls/README.md).

Services follow the same feature-folder convention; see the [service guide](../src/MandoCode.Desktop/Services/README.md). Source folders do not change the existing namespaces or XAML class names. The unit-test and browser smoke-test projects link selected service source files directly, so file moves must update those compile paths.

## Layer map

| Layer | CLI (MandoCode) | Desktop (this app) |
|---|---|---|
| Orchestrator | `Components/App.razor` interactive loop | `ViewModels/ChatController.cs` (faithful port), one per agent |
| Approvals | `DiffApprovalHandler` (Spectre panels) | `Services/WinUiApprovalService.cs` + each agent's own XAML overlay (same labels, bypass state, `DiffApprovalResult` contract) |
| Approvals | `DiffApprovalHandler` (Spectre panels) | `Services/Approval/WinUiApprovalService.cs` + each agent's own XAML overlay (same labels, bypass state, `DiffApprovalResult` contract) |
| Transcript | ANSI scrollback + Spectre renderables | WebView2 + `TranscriptHtmlBuilder` (Markdig HTML, themed) |
| Busy/spinner | `SpinnerService` (ANSI) | `BusyStateService` → ProgressRing |
| Onboarding | `OnboardingFlow` terminal prompts | In-chat guided wizard (auto on first launch, `/setup` after) + Settings page |
Expand All @@ -56,7 +64,7 @@ progress events, `DiffService` diff models.

## Agents

Each tab is an independent agent. `Services/AgentSession.cs` hand-constructs one agent's object
Each tab is an independent agent. `Services/Sessions/AgentSession.cs` hand-constructs one agent's object
graph; `SessionManager` owns the set of them. The split matters:

| Per agent | App-wide |
Expand Down Expand Up @@ -102,7 +110,7 @@ Panes are ordinary agent views moved between grid cells with `Grid.SetColumn`/`G
whole reason the tab surface is built the way it is (see below). The row and column tracks are
rebuilt in code per pane count, interleaving a divider track between adjacent panes; track
definitions and dividers are the only things that change, so no agent view ever leaves the tree.
The geometry and divider math live in `Services/PaneLayout.cs`, kept free of WinUI types so they're
The geometry and divider math live in `Services/Workspaces/PaneLayout.cs`, kept free of WinUI types so they're
unit tested directly.

The split bar uses chips with `MenuFlyout` pickers rather than `ComboBox`es on purpose: rebuilding
Expand Down Expand Up @@ -205,7 +213,7 @@ about the pad: every note's title and first line, plus the full text of whatever
currently matching, and the bar states what it was given (`12 notes listed · 3 read in full`) because
a capped read that looks total is the one thing an "ask about all my notes" box must not do.

`Services/NoteAssistant.cs` builds a bare Ollama kernel with **no plugins, filters, or tools** — the
`Services/Notes/NoteAssistant.cs` builds a bare Ollama kernel with **no plugins, filters, or tools** — the
same shape as `SnapshotEnhancer`. That's the design, not an optimization: with no file tools, "nothing
writes your note but you" is true by construction rather than by policy, and no approval machinery is
needed because the only route from a reply into a note is a button you pressed. It also isn't an
Expand All @@ -218,7 +226,7 @@ The editor is not the only thing that writes these files, and doesn't assume it
`FileSystemWatcher` compares the file against what the editor last wrote: identical means the write
was ours; changed-while-clean is adopted silently; changed-while-you-were-typing raises a conflict you
resolve — *use the version on disk* or *keep what I typed*. A note deleted from under unsaved edits
offers to save it back. `Services/NoteText.cs` handles the newline round trip, because a WinUI
offers to save it back. `Services/Notes/NoteText.cs` handles the newline round trip, because a WinUI
`TextBox` normalizes every newline to a bare CR — write that straight back out and a Notepad-authored
CRLF note becomes one endless line. Both of those are why `NoteStore`, `NoteEntry`, and `NoteText` are
WinUI-free with an injectable pad root: the tests drive them against real temp folders.
Expand Down
10 changes: 5 additions & 5 deletions src/MandoCode.Desktop.BrowserSmokeTests/BrowserSmokeTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3719.77" />
<Compile Include="..\MandoCode.Desktop\Services\DesktopPreviewScripts.cs" Link="DesktopPreviewScripts.cs" />
<Compile Include="..\MandoCode.Desktop\Services\BrowserFrames.cs" Link="BrowserFrames.cs" />
<Compile Include="..\MandoCode.Desktop\Services\DesktopPreviewTools.cs" Link="DesktopPreviewTools.cs" />
<Compile Include="..\MandoCode.Desktop\Services\DesktopPreviewKeys.cs" Link="DesktopPreviewKeys.cs" />
<Compile Include="..\..\MandoCode\src\MandoCode\Services\ProjectRootAccessor.cs" Link="ProjectRootAccessor.cs" />
<Compile Include="..\MandoCode.Desktop\Services\Browser\DesktopPreviewScripts.cs" Link="DesktopPreviewScripts.cs" />
<Compile Include="..\MandoCode.Desktop\Services\Browser\BrowserFrames.cs" Link="BrowserFrames.cs" />
<Compile Include="..\MandoCode.Desktop\Services\Browser\DesktopPreviewTools.cs" Link="DesktopPreviewTools.cs" />
<Compile Include="..\MandoCode.Desktop\Services\Browser\DesktopPreviewKeys.cs" Link="DesktopPreviewKeys.cs" />
<Compile Include="..\..\MandoCode\src\MandoCode\Services\Project\ProjectRootAccessor.cs" Link="ProjectRootAccessor.cs" />
<Content Include="fixtures\*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<!-- WebView2 includes its WPF adapter unconditionally; this harness uses WinForms only. -->
Expand Down
Loading
Loading