Commit 892d84e
Release: UI improvements, deb packaging, MSIX pipeline fixes (#17)
* test: Phase 3d — mobile handler unit tests (8 handlers, 22 tests)
- MobileHandlerTests.cs: tests for all 8 mobile CQRS handlers
(ConnectMobileSession, DisconnectMobileSession, CreateMobileSession,
TerminateMobileSession, SendMobileMessage, SendMobileAttachment,
ArchiveMobileMessage, UsePromptTemplate)
- Fix CS0104 ambiguity in McpRegistryPageViewModelTests: use
LogicRequests alias to disambiguate DeleteMcpServerRequest vs
RemoteAgent.Proto.DeleteMcpServerRequest
- Fix CS8601 in ConnectMobileSessionHandler: null-coalesce host
assignment (workspace.Host = host ?? "")
- Fix ConnectMobileSessionHandler: remove NotifyConnectionStateChanged
from catch block to prevent status overwrite on connection failure
- Fix xUnit1031: make Disconnect test async, await handler result
App.Tests: 67 -> 89 (+22)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: mark FR-12.12 Done, update test count to 240, mark all todos complete
- requirements-completion-summary.md: FR-12.12 Pending → Done
(AppLoggerProvider, InMemoryAppLogStore, AppLogViewModel,
ClearAppLogHandler, SaveAppLogHandler all implemented)
- requirements-completion-summary.md: TR-18.4 test count 218 → 240
(89 App.Tests + 151 Desktop.UiTests)
- implementation-plan-todo.md: mark all 318 remaining items [x]
(all phases 0–4 are complete)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add session handoff 2026-02-19T00-04-44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add DocFX API+testing reference; add XML docs to all test classes
- Split DocFX metadata into 4 entries (net10.0 src, net9.0 Desktop, net10.0 tests, net9.0 Desktop.UiTests)
- Added docs/api/index.md, docs/api-tests/index.md landing pages
- Added docs/filterConfig.yml (exclude System/Microsoft namespaces)
- Updated docs/toc.yml with API Reference and Testing API Reference sections
- Added /// <summary> + [Trait] attributes to all Desktop.UiTests handler tests (32 files)
- Added /// <summary> + [Trait] to App.Tests test classes (7 files)
- Added /// <summary> to SharedHandlerTestStubs.cs, InMemoryServerRegistrationStore.cs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: rebuild README; fix broken doc links
- Rewrote README.md: full architecture overview, CQRS pattern, sub-VM
decomposition, Management App Log, project structure, protocol tables,
build scripts, test counts (240), CI/CD, F-Droid install, contributing
- Fixed broken /README.md link in implementing-cli-agents.md (use GitHub URL)
- Fixed broken ../SESSION_HANDOFF link in implementation-plan-mvvm-cqrs-refactor.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: fix all 505 broken DocFX breadcrumb links
Add namespace stub YAMLs for intermediate namespaces that DocFX does
not auto-generate (no types directly in them). Stubs added to both
api/ and api-tests/ so relative breadcrumb links resolve correctly
in each section.
api/: RemoteAgent, RemoteAgent.App, RemoteAgent.Plugins (3 files)
api-tests/: RemoteAgent, RemoteAgent.App, RemoteAgent.Desktop,
RemoteAgent.Service (4 files)
Site now has 422 models and 0 broken links (was 505 broken).
DuplicateUids warnings (5) are non-fatal and expected for shared
namespace names across api/ and api-tests/ sections.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix obsolete MAUI Page method calls in MauiPlatformServices
* [WIP] Add direct FR/TR annotations for test methods (#16)
* Initial plan
* Add requirements traceability matrix generation script
Co-authored-by: sharpninja <16146732+sharpninja@users.noreply.github.com>
* Add FR/TR annotations to test classes and fix script AWK logic
Co-authored-by: sharpninja <16146732+sharpninja@users.noreply.github.com>
* Fix requirements matrix generation script to find all test files
Co-authored-by: sharpninja <16146732+sharpninja@users.noreply.github.com>
* Add requirements traceability documentation to CONTRIBUTING.md
Co-authored-by: sharpninja <16146732+sharpninja@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sharpninja <16146732+sharpninja@users.noreply.github.com>
* fix: MSIX versioning, single-file self-contained packaging, and version bump script
- Use SemVer (not MajorMinorPatch) from GitVersion in build-msix workflow
so pre-release tags (e.g. -develop.1) appear in the MSIX filename
- Set next-version to 0.1.0 in GitVersion.yml
- package-msix.ps1: default SelfContained to true, add PublishSingleFile
and IncludeNativeLibrariesForSelfExtract flags for single-file builds
- package-msix.ps1: fall back to next-version from GitVersion.yml instead
of hardcoded 1.0.0 when no -Version param, local tool, or git tag found
- Add scripts/bump-minor-version.sh to increment minor version in GitVersion.yml
- Desktop csproj: add RollForward=LatestPatch so installed 9.0.x patch
runtime is accepted without requiring exact 9.0.0
- build-msix.ps1: display generated MSIX path on completion
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: read GitVersion.yml before git describe in version fallback
git describe was finding v1.0.0-* tags and the regex was stripping
the pre-release suffix, producing 1.0.0. GitVersion.yml is the
authoritative source and should be checked first.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: add version source diagnostic logging to package-msix.ps1
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: print calculated version at end of package-msix.ps1
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: pause after manifest write to show version provenance and manifest content
Adds a review step after AppxManifest.xml is written showing:
- SemVer and MSIX Identity version used
- Full manifest content
Pauses for confirmation unless -Force is passed (CI always uses -Force).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: auto-detect unsigned MSIX and pass -AllowUnsigned in install script
Uses Get-AuthenticodeSignature to check whether the package is signed
before calling Add-AppxPackage, so unsigned dev builds install without
needing manual -AllowUnsigned.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: auto-sign unsigned MSIX with dev cert instead of using -AllowUnsigned
-AllowUnsigned requires Developer Mode on the machine (0x80073D2C).
The install script now:
- Detects unsigned packages via Get-AuthenticodeSignature
- Locates signtool.exe from the Windows SDK
- Creates or reuses a self-signed cert (CN=RemoteAgent Dev)
- Trusts the cert in Cert:\LocalMachine\Root
- Signs the MSIX in-place before calling Add-AppxPackage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add -Clean flag to package-msix.ps1
Runs dotnet clean on each project before publishing when -Clean is
specified. Cleans service, Ollama plugin, and desktop projects
according to the -ServiceOnly/-DesktopOnly flags.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: navigate to Sessions view after successful connection
After StartSessionAsync succeeds, set SelectedManagementSection to
'Sessions' so the chat view is shown instead of leaving the Server
Setup panel visible and overlapping the session view.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: stop service before MSIX update to avoid locked-file deployment failure
Add-AppxPackage -ForceUpdateFromAnyVersion fails if RemoteAgentService
is running when the update is applied. Stop the service first so the
MSIX engine can replace the service binary.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: close desktop app before MSIX update to resolve 0x80073D02
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: remove --configfile from dotnet clean (unsupported flag)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: restore packages after dotnet clean before publish
dotnet clean removes obj/ asset files so the implicit restore inside
dotnet publish cannot resolve packages. Add explicit dotnet restore
with the NuGet config after cleaning each project.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: replace dotnet clean with direct bin/obj deletion in -Clean
dotnet clean cannot use --configfile so it fails to resolve package
targets when globalPackagesFolder is repo-relative (.nuget/packages).
Directly removing bin/ and obj/ directories is simpler and reliable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add -Install flag to package-msix.ps1
Calls install-remote-agent.ps1 after packaging completes.
Passes -MsixPath and -CertPath (if a dev cert was generated).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use Directory.Delete for robust bin/obj removal in -Clean
Remove-Item -Recurse -Force can fail with 'directory not empty'
on Windows for certain nested paths. System.IO.Directory::Delete
with recursive=true is more reliable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add -BumpMajor/-BumpMinor/-BumpPatch flags to package-msix.ps1
Increments the corresponding semver component in GitVersion.yml
next-version before the build runs, so the new version is picked
up immediately by the version-detection fallback chain.
The three flags are mutually exclusive.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: MsixTools PowerShell module with YAML-driven config
- scripts/MsixTools/MsixTools.psm1 — reusable module with four
exported functions: Read-MsixConfig, New-MsixPackage,
Install-MsixPackage, Uninstall-MsixPackage
- scripts/MsixTools/MsixTools.psd1 — module manifest (PS 7.0+)
- msix.yml — workspace-level YAML config (package, service, desktop,
plugins, build, output, icons sections)
- package-msix.ps1 — now a thin wrapper; bump/validate logic stays
here, build logic delegated to New-MsixPackage
- install-remote-agent.ps1 — now a thin wrapper around
Install-MsixPackage / Uninstall-MsixPackage
Fixes 0x80073CFB: Install-MsixPackage now removes any existing package
before Add-AppxPackage instead of using -ForceUpdateFromAnyVersion,
which blocks same-version reinstalls with changed contents.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: resolve OutDir to absolute path before icon generation
System.Drawing.Bitmap.Save() is a .NET method that ignores
PowerShell's working directory and fails with relative paths.
Resolving OutDir to an absolute path early ensures all derived
paths (msix-layout/Assets/*) are also absolute.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: resolve WorkspaceRoot to absolute path at function entry
[System.IO.Path]::GetFullPath() resolves relative to .NET's CWD
which can differ from PowerShell's $PWD. Using PS's own session-state
path resolver ensures WorkspaceRoot (and all derived paths: OutDir,
project paths, icons) are always absolute, fixing Bitmap.Save failure
when -WorkspaceRoot . is passed.
After pulling, reload the module before calling directly:
Import-Module .\scripts\MsixTools\MsixTools.psd1 -Force
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use Convert-Path to establish absolute WorkspaceRoot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add -NoBuild flag; make -Clean and -NoBuild mutually exclusive
-NoBuild skips dotnet publish and uses existing artifacts/publish-*
output. Fails fast with a clear error if expected output is missing.
-Clean and -NoBuild are validated as mutually exclusive in both the
module and the wrapper script.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: remove inline MsixTools (replaced by submodule)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: add MsixTools as git submodule
https://github.com/sharpninja/MsixTools
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: wrapper scripts are now zero-logic param forwarders
All version-bump validation and logic moved into New-MsixPackage in
the MsixTools module. Wrapper scripts contain only param declarations
and a single module function call. Submodule updated to latest.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: update MsixTools submodule to include bump params
Points to commit with -BumpMajor/-BumpMinor/-BumpPatch added to
New-MsixPackage; all version logic now lives in the module.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: update MsixTools submodule (add MCP server)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use Segoe MDL2 Assets for icons and Segoe UI as base font on Windows
On Windows, resolve IconFontFamily to 'Segoe MDL2 Assets' and
AppFontFamily to 'Segoe UI' at app startup. Falls back to
FontFamily.Default on other platforms.
- App.axaml.cs: set font resources after XAML load based on OS
- MainWindow.axaml: apply AppFontFamily to Window, add fa|FontIcon
style with IconFontFamily
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refactor copy-status-log to follow CQRS pattern with tests
- Add IClipboardService abstraction and AvaloniaClipboardService impl
- Add CopyStatusLogRequest + CopyStatusLogHandler (formats entries
oldest-first as markdown with yyyy-MM-dd HH:mm:ss timestamps)
- Register IClipboardService and CopyStatusLogHandler in DI
- Refactor MainWindowViewModel: remove direct clipboard/StringBuilder
code; dispatch CopyStatusLogRequest via IRequestDispatcher
- Add NullClipboardService and CapturingClipboardService stubs
- Add CopyStatusLogHandlerTests (7 tests; all passing)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add directive: UI buttons require CQRS handler + complete tests
Document the rule in both docs/REPOSITORY_RULES.md (canonical) and
.github/copilot-instructions.md (agent-facing summary):
- Every Desktop UI button must be backed by a *Request/*Handler pair
- Handler dispatched via IRequestDispatcher in the ViewModel
- *HandlerTests.cs covering success, failure, and edge cases required
- Null* stubs for new infrastructure interfaces in SharedHandlerTestStubs
- CopyStatusLogHandler cited as reference implementation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Open Logs Folder button to App Log section (CQRS + tests)
- IFolderOpenerService + SystemFolderOpenerService (cross-platform)
- OpenLogsFolderRequest + OpenLogsFolderHandler (validates path exists)
- AppLogViewModel: logsFolder param, OpenLogsFolderCommand
- App.axaml.cs: register IFolderOpenerService, OpenLogsFolderHandler,
AppLogViewModel factory (passes dataDir)
- MainWindow.axaml: Open Logs Folder button in App Log section
- 6 handler tests; NullFolderOpenerService / CapturingFolderOpenerService stubs
- SharedHandlerTestStubs.CreateAppLog updated with default logsFolder param
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Extract navigation panels to UserControls with IsVisible bindings
- 13 panel UserControls in src/RemoteAgent.Desktop/Views/Panels/:
ServerSetupPanel, SessionsPanel, LocalServerPanel, OpenSessionsPanel,
StructuredLogsPanel, SecurityPanel, HistoryPanel, AuthUsersPanel,
PluginsPanel, McpPanel, PromptsPanel, AppLogPanel, SettingsPanel
- MainWindow.axaml: add panels:* namespace; replace ContentPresenter with
a Grid hosting all panels bound via Is*SectionSelected (IsVisible).
All panels are always in the logical tree — no dynamic switching needed.
- Add FindControlDeep<T> extension (TestHelpers/ControlExtensions.cs) that
traverses the full logical tree across UserControl NameScope boundaries.
- Update MainWindowUiTests to use FindControlDeep for panel-scoped controls.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Windows port: bind to 5243 (not 5244) on Windows
appsettings.json PlatformUrls:Windows was set to 5244, but all clients
(LocalServerManager, ServerRegistration default, MainWindowViewModel
edit port, mobile ConnectMobileSessionHandler / UsePromptTemplateHandler,
and the pairing QR-code deep link) hard-code 5243 as the default port.
- appsettings.json: Windows -> http://0.0.0.0:5243
- Program.cs /pair/key: remove Windows-specific 5244 fallback; use 5243
unconditionally for non-HTTPS when the port is absent from the Host header.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Windows port binding: use ConfigureKestrel instead of UseUrls
Root cause: launchSettings.json applicationUrl: "http://0.0.0.0:5243" is
converted to ASPNETCORE_URLS by dotnet run (including run-service-local.ps1).
ASPNETCORE_URLS has higher priority than UseUrls(), so the Windows-specific
port 5244 was silently overridden to 5243.
Fix: replace UseUrls() with WebHost.ConfigureKestrel() + ListenAnyIP().
An explicit Kestrel Listen* call has the highest priority in ASP.NET Core's
URL resolution chain and is not overridable by ASPNETCORE_URLS.
Also:
- Restore appsettings.json PlatformUrls:Windows back to 5244
- Restore /pair/key pairing fallback port (Windows=5244, Linux=5243)
- Add Http1AndHttp2 protocol constraint on the explicit endpoint (was
previously set via Kestrel:EndpointDefaults in appsettings.json, which
would be ignored once an explicit endpoint is registered)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Open Logs Folder button to status log viewer; icon-only buttons
- Status log header: add Open Logs Folder button (AppLog.OpenLogsFolderCommand,
x:Name=StatusLogOpenLogsFolderButton, folder-open glyph )
- Status log header: Close button now icon-only (), no text label
- Status log header: Copy as Markdown button now icon-only (), no text
- AppLogPanel: Open Logs Folder button now icon-only (), no text
- MainWindowUiTests: assert StatusLogOpenLogsFolderButton is present
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Build MSIX: upgrade gittools/actions to v3 for GitVersion 6.x
gittools/actions/gitversion/setup@v1 only accepts versions >=5.2.0 <6.1.0.
The versionSpec '6.x' resolves to 6.6.0, which falls outside that range.
v3 of the action supports GitVersion 6.x.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add .deb build job and GitHub Release to pipeline
- Add build-deb job (ubuntu-latest): checkout, .NET 10+9, GitVersion v3/6.x,
runs scripts/package-deb.sh, uploads remote-agent-deb-* artifact
- Expose SemVer + MajorMinorPatch outputs from both build jobs
- Add release job (push-only, needs both build jobs):
- Downloads MSIX and .deb artifacts
- Creates GitHub Release with gh CLI (--prerelease on non-main branches)
- Idempotent: deletes existing release for the tag before recreating
- Attaches *.msix, *.deb, and *.cer (if signed) as release assets
- Add scripts/package-deb.sh to path triggers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: commit working tree changes before PR
- GitVersion.yml: bump next-version to 0.1.3
- Program.cs: log actual listening URLs on startup
- package-deb.sh: add remote-agent-ctl management script installation
- docs/faq.md: update docs
- scripts/bump-patch-version.sh, monitor-service-windows.ps1, remote-agent-ctl.sh: add untracked scripts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: expose DbPath on ILocalStorage; log connection details on open
- ILocalStorage: add DbPath property (exposes the LiteDB file path)
- LiteDbLocalStorage: implement DbPath => _dbPath
- AgentGatewayService: log connection_opened event with session log,
structured log, and database paths for diagnostics
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add Windows Event Log as ILogger provider
- ConfigureWindowsEventLog() annotated [SupportedOSPlatform("windows")]
calls builder.Logging.AddEventLog with SourceName = "Remote Agent Service"
- Called from Main() behind OperatingSystem.IsWindows() guard
- appsettings.json: add EventLog log-level section (Information+ for default,
Warning for Microsoft.AspNetCore) so all ILogger calls appear in Event Viewer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: versioned Windows service display name
- msix.yml: add service.displayName = 'Remote Agent Service'
- MsixTools submodule: combined MSIX packages now generate a dedicated
Application entry for the service so services.msc shows
'Remote Agent Service <SemVer>' instead of the desktop app name
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: session handoff 2026-02-19T18-35-50-0600
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: checkout submodules in build-msix CI job
MsixTools is a git submodule (scripts/MsixTools/). Without
submodules: recursive in the checkout step the directory is
empty and Import-Module fails with 'no valid module file found'.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use Http2 (h2c) for cleartext gRPC endpoint
Http1AndHttp2 over cleartext requires TLS-based ALPN to negotiate the
protocol version, producing:
'HTTP/2 is not enabled... TLS is not enabled. HTTP/2 requires TLS
application protocol negotiation. Connections will use HTTP/1.1.'
This is a local gRPC service without TLS; the correct protocol is
Http2 (h2c — HTTP/2 cleartext). All gRPC clients already use
GrpcChannelOptions with no TLS (Grpc.Net.Client default for http://).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: replace port Entry with Picker on mobile; default to 5244
- MainPageViewModel: DefaultPort changed to "5244" (Windows service port);
add static AvailablePorts = ["5244", "5243"] for Picker ItemsSource
- MainPage.xaml: xmlns:vm added; both port Entry controls replaced with
Picker bound to MainPageViewModel.AvailablePorts / Port
(connect card + persistent top-bar; WidthRequest=90 on the bar picker)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: centralize service port in ServiceDefaults; enforce port picker with tests
- Add ServiceDefaults.cs (platform-aware: 5244 Windows, 5243 Linux)
- Replace hardcoded 5243 literals in all desktop ViewModels and infrastructure
- Add PortPickerViewModelTests.cs (11 unit tests) enforcing:
AvailablePorts = ["5244", "5243"], default Port = "5244"
- Expose MobileHandlerTests.CreateDefaultViewModel() (internal) for reuse
- Update MobileConnectionUiTests.cs: fix default port assertion (5243→5244),
add Picker class check, add drop-down items verification
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use Http1AndHttp2 + h2c switch to allow gRPC and REST on same port
Service: revert Kestrel from Http2-only to Http1AndHttp2 so REST endpoints
(/api/sessions/capacity, /pair/key, etc.) continue to accept HTTP/1.1 while
gRPC clients use HTTP/2 cleartext (h2c prior knowledge).
Desktop + Mobile: set AppContext switch
System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport = true
before any gRPC channel is created, enabling h2c connections to the
Http1AndHttp2 Kestrel endpoint without TLS.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: set Kestrel EndpointDefaults to Http1AndHttp2 in appsettings.json
The config key overrode the Program.cs ConfigureKestrel call, keeping the
endpoint on Http2-only and causing HTTP_1_1_REQUIRED errors on gRPC connects.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: migrate 13 management REST endpoints to gRPC; revert to Http2-only
Add 13 RPCs to AgentGateway.proto and implement in AgentGatewayService:
CheckSessionCapacity, ListOpenSessions, ListAbandonedSessions,
TerminateSession, ListConnectedPeers, ListConnectionHistory,
ListBannedPeers, BanPeer, UnbanPeer, ListAuthUsers,
ListPermissionRoles, UpsertAuthUser, DeleteAuthUser
Rewrite ServerCapacityClient to use GrpcChannel for all 13 calls.
Remove the 13 REST MapGet/Post/Delete registrations from Program.cs.
Regenerate AgentGateway.cs + AgentGatewayGrpc.cs from proto.
Revert to Http2-only (appsettings.json + Program.cs).
Remove AppContext.SetSwitch h2c lines from Desktop and Mobile.
Pairing endpoints (/, /pair, /pair/key) remain as REST on Http1AndHttp2
is no longer needed since the desktop management client is now pure gRPC.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: use shared app logo in desktop window and MSIX
Generate appicon.png (256/48/32/16px) from the same SVG source used by
the mobile app (appicon.svg is identical in both projects).
- Register all four sizes as AvaloniaResource in RemoteAgent.Desktop.csproj
- Set Icon="avares://RemoteAgent.Desktop/Assets/AppIcon/appicon.png" on
MainWindow so the taskbar, Alt-Tab, and title bar all show the logo
- msix.yml already references appicon.svg (same as mobile) — no change needed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: end server session when closing a tab
TerminateDesktopSessionHandler now calls TerminateSessionAsync on the
server (via IServerCapacityClient gRPC) before disconnecting locally,
so the server immediately cleans up the session rather than waiting for
an idle/timeout.
- Inject IServerCapacityClient into TerminateDesktopSessionHandler
- Call TerminateSessionAsync (best-effort) when session.IsConnected
and workspace has a valid port; local cleanup always proceeds even
if the server call fails
- Add LastTerminatedSessionId tracking to StubCapacityClient
- Add two new tests: server RPC is invoked, server failure still removes
locally (166 tests total, all passing)
- Fix stale TerminateDesktopSessionHandler() instantiation in
MainWindowUiTests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: wire MessageReceived/ConnectionStateChanged before connecting session
CreateDesktopSessionHandler was calling session.SessionClient.ConnectAsync
without first subscribing to MessageReceived and ConnectionStateChanged.
Messages from the server arrived in the ReceiveLoop and were silently
dropped because no handler was registered.
Root cause: ConnectSessionAsync (the only method that did the wiring) was
unreachable dead code — NewSessionAsync dispatched to the CQRS handler
which bypassed it entirely.
Fix:
- Extract event registration into ServerWorkspaceViewModel.RegisterSessionEvents()
and cleanup into UnregisterSessionEvents()
- ConnectSessionAsync delegates to RegisterSessionEvents (dead code path
is now consistent)
- CreateDesktopSessionHandler calls RegisterSessionEvents BEFORE ConnectAsync
so no early server messages (e.g. SessionStarted event) are lost
- TerminateDesktopSessionHandler calls UnregisterSessionEvents on teardown
Tests:
- FakeAgentSession.MessageReceived is now a real subscribable event
- FakeAgentSession.SimulateMessage fires MessageReceived to test wiring
- StubSessionFactory.LastFakeSession exposes the last created session client
- New test: HandleAsync_ShouldRegisterSessionEventsBeforeConnect verifies
that a synthetic server message reaches session.Messages (167 tests pass)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: session handoff 2026-02-19T21-06-54-0600
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: bump next-version to 0.1.12
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: serialise Connect writes via Channel<ServerMessage>; remove dead code
- Replace all direct responseStream.WriteAsync calls inside requestTask
and StreamReaderToResponse with Channel<ServerMessage>.Writer.TryWrite
- Add single drain loop (Task.Run) as the sole writer to responseStream;
cancels cts on write failure to trigger clean disconnect cleanup
- Change StreamReaderToResponse signature to accept ChannelWriter<ServerMessage>
instead of IServerStreamWriter<ServerMessage>
- Wrap stdout/stderr/requestTask awaiting in try/finally so outChannel is
always completed even on unexpected exceptions
- Remove ConnectSessionAsync dead code from ServerWorkspaceViewModel;
its logic lives in RegisterSessionEvents + CreateDesktopSessionHandler
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add camera QR scan pairing flow with ZXing.Net.Maui and Android deep link support
- Add IQrCodeScanner and IDeepLinkService interfaces to App.Logic
- Add ScanQrCodeRequest + ScanQrCodeHandler (camera or deep-link bypass)
* dual-mode: invokes ZXing camera scanner or parses RawUri directly
* saves host/port/apiKey to IAppPreferences on success
* internal static ParseAndApply + ParseQuery for full unit testability
- Add QrScannerPage (ZXing CameraBarcodeReaderView) + code-behind (TCS pattern)
- Add MauiQrCodeScanner: requests CAMERA permission, pushes QrScannerPage modally
- Add DeepLinkService: thread-safe singleton, queues URI if no subscriber yet
- Wire .UseBarcodeReader() in MauiProgram; register IDeepLinkService, IQrCodeScanner
- Add CAMERA permission + uses-feature to AndroidManifest.xml
- Add [IntentFilter] for remoteagent://pair scheme on MainActivity; dispatch via IDeepLinkService
- Add ScanQrCode button to MainPage.xaml connection view
- Add ApiKey + PrefApiKey + ScanQrCodeCommand + deep-link subscription to MainPageViewModel
- Pass workspace.ApiKey in ConnectMobileSessionHandler.ConnectAsync
- Add 7 ScanQrCodeHandlerTests covering all handler paths
- Add NullDeepLinkService stub + update CreateWorkspace in MobileHandlerTests
All 108 App.Tests + 167 Desktop.UiTests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: replace obsolete Frame with Border in QrScannerPage; fix nullable sender in event handlers
Frame is obsolete as of .NET 9 — replaced with Border using StrokeShape=RoundRectangle.
Event handler sender parameters changed to object? to match EventHandler<T> delegate signatures
(TreatWarningsAsErrors=true treats CS0618/CS8622 as errors).
All 108 App.Tests + 27 Service.Tests + 167 Desktop.UiTests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix MSIX CI: exit 0 to prevent LASTEXITCODE leak from native commands
After New-MsixPackage runs dotnet/makeappx/signtool, the $LASTEXITCODE
from the last native command can be non-zero even on success. GitHub
Actions' pwsh runner checks $LASTEXITCODE after the script exits, so
adding explicit 'exit 0' prevents false failure reports.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Merge Build MSIX workflow into Build and Deploy pipeline
Move build-msix and build-deb jobs from the standalone build-msix.yml
into build-deploy.yml so all packaging happens in one unified pipeline.
- Add build-msix job (windows-latest, .NET 10+9, package-msix.ps1)
- Add build-deb job (ubuntu-latest, .NET 10+9, package-deb.sh)
- Both jobs depend on detect + build, sharing the semver output
- release-beta now depends on build-msix and build-deb, downloads
MSIX and DEB artifacts, and includes them in the beta release
- Delete the now-redundant build-msix.yml workflow
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: serve /pair web UI on dedicated HTTP/1+2 port (1+gRPC port)
Kestrel now listens on two ports:
- Primary gRPC port (5244/5243): HTTP/2 only, for gRPC traffic
- Web pairing port (15244/15243): HTTP/1+2, for browser /pair flow
/pair, POST /pair, and /pair/key endpoints are restricted to the
web port via RequireHost so no HTTP/1.1 traffic can reach the gRPC
listener. webPort=0 default keeps integration tests unaffected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: SetPairingUsers — PS script + Desktop toolbar + gRPC RPC
Part 1: Add scripts/set-pairing-user.ps1
- Accepts -Username, -Password, -Replace params
- Finds appsettings.json via SC query / default path / repo fallback
- Computes SHA-256 password hash; upserts or replaces PairingUsers array
- Restarts RemoteAgentService (non-fatal if not found)
Part 2: Full-stack SetPairingUsers feature
- Proto: add SetPairingUsers RPC + PairingUserEntry/Request/Response messages
- Service: override SetPairingUsers in AgentGatewayService (reads/writes appsettings.json)
- Desktop client: add SetPairingUsersAsync to IServerCapacityClient + ServerCapacityClient
- Dialog: IPairingUserDialog, PairingUserDialog.axaml, PairingUserDialogViewModel, AvaloniaPairingUserDialog
- CQRS: SetPairingUserRequest + SetPairingUserHandler
- ViewModels: HasConnectedSession on ServerWorkspaceViewModel; SetPairingUserCommand on MainWindowViewModel
- UI: SetPairingUserButton in MainWindow toolbar (enabled when HasConnectedSession)
- DI: register SetPairingUserHandler + IPairingUserDialog in App.axaml.cs
- Tests: SetPairingUserHandlerTests (5 tests); stubs updated in SharedHandlerTestStubs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix: use IOptionsMonitor so /pair reloads after SetPairingUsers writes appsettings.json
IOptions<AgentOptions> is a startup snapshot; switching to IOptionsMonitor<AgentOptions>
means options.CurrentValue reflects the file that SetPairingUsers just wrote, without
requiring a service restart.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Feat: generate and return API key when saving pairing user
SetPairingUsers RPC now generates a cryptographically random 32-byte
API key, saves it as Agent.ApiKey in appsettings.json alongside the
pairing user, and returns it in SetPairingUsersResponse.GeneratedApiKey.
The desktop handler applies the returned key to Workspace.ApiKey so
subsequent gRPC calls (capacity check, session creation) use it
immediately without requiring a manual reconnect.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix: forward ApiKey to server info and capacity checks in ConnectMobileSessionHandler
Without this, a service configured with Agent:ApiKey returns 401 on
GetServerInfoAsync and GetSessionCapacityAsync, causing the mobile app
to show 'Could not verify server session capacity'.
Added regression test that asserts the key reaches both API calls.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix: use Shell.Current.Navigation + MainThread for QR scanner modal push
page.Navigation.PushModalAsync on a ContentPage inside a MAUI Shell can
silently no-op on Android when the page isn't the active navigation host.
Switch to Shell.Current.Navigation which always routes through the Shell's
own navigation controller. Also wrap in MainThread.InvokeOnMainThreadAsync
because Permissions.RequestAsync may resume on a thread-pool thread.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* UX: SelectableTextBlock everywhere in Avalonia; simplify mobile login UI; persist ApiKey on connect
- Replace all TextBlock with SelectableTextBlock in all 16 Avalonia .axaml files
so users can copy text from any label in the desktop app.
- Simplify mobile connection card to two buttons:
* 'Scan QR to Pair' — disabled when ApiKey is already stored
* 'Connect' — disabled until ApiKey is stored (requires QR scan first)
Remove New Session / Terminate Session / extra Connect buttons from pre-connect view.
- Add HasApiKey property to MainPageViewModel; update CanExecute for both commands.
- ConnectMobileSessionHandler now persists ApiKey alongside Host/Port on
successful connect so server details survive app restart as a complete set.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Style: global 4px margin on all interactive/display controls in Avalonia app
Single style rule in App.axaml targeting Button, TextBox, ComboBox, CheckBox,
ListBox, SelectableTextBlock, and TabControl so every control gets consistent
4px spacing without touching individual XAML files.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix: generate QR code server-side (embedded PNG) instead of CDN JS
The CDN qrcode.js script was blocked/unavailable so no QR was shown.
Switch to QRCoder (server-side) which generates the QR as a PNG and
embeds it as a data:image/png;base64 <img> tag — no external requests
needed, works in air-gapped / firewalled environments.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Replace QR camera scanner with server login webview for pairing
- Rename 'Scan QR to Pair' button to 'Login'
- Host setter calls ChangeCanExecute on ScanQrCodeCommand
- IQrCodeScanner.ScanAsync() now accepts loginUrl parameter
- ScanQrCodeHandler builds http://{host}:1{port}/pair URL and passes to scanner; validates host not empty
- MauiQrCodeScanner opens PairLoginPage (WebView) instead of camera; no camera permission needed
- PairLoginPage: WebView loads /pair login form; on navigate to /pair/key, JS extracts deep link from <a class='btn'> href; closes modal with result
- Remove QrScannerPage (camera scanner) and ZXing.Net.Maui.Controls dependency
- Add tests: HandleAsync_NoHost_ReturnsFail, HandleAsync_BuildsLoginUrlFromHostPort
- All 138 tests pass (111 App + 27 Service)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: update session handoff 2026-02-20
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add FR-17/18 and TR-19/20 for device pairing, API key management, and desktop UX
- FR-17: Device pairing flow (admin sets credentials, service generates API key, web login, deep link extraction)
- FR-18: Desktop UX refinements (SelectableTextBlock, 4px margin)
- TR-19: Pairing infrastructure (SetPairingUsers RPC, IOptionsMonitor, dual-port, QRCoder, PairLoginPage WebView, deep-link format)
- TR-20: Desktop UX technical (SelectableTextBlock replacement, global style)
- Updated completion summary: 80 FR + 124 TR, all Done
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Hardcode server connection mode on Android, remove mode selector dialog
Remove IConnectionModeSelector interface, MauiConnectionModeSelector class,
and all direct-mode code paths. Android always connects in server mode.
Remove ConnectionModeLabel from UI and associated ViewModel property.
Update all tests to reflect removal of mode selection.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Migrate GetSessionCapacityAsync to gRPC, remove dead HTTP helpers
Replace REST call to /api/sessions/capacity with gRPC CheckSessionCapacity.
Remove unused CreateHttpFailure, TryReadErrorDetailAsync, JsonOptions,
and System.Net.Http.Json / System.Text.Json imports. All ServerApiClient
methods now use gRPC exclusively.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Hide navigation until connection and session are established
Add IsConnected and ConnectionStateChanged to ISessionCommandBus.
AppShellViewModel exposes IsConnected, subscribes to state changes.
Flyout items (sessions, Start Session, Settings, Account) are hidden
until connected. MCP Registry tab hidden until connected.
Settings and Account pages also hidden from tab bar until connected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Hide connection card in chat view when already connected
The host/port/connect/disconnect card in the chat workspace is now
hidden once connected, giving more space to the chat messages.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add server profiles: save connection details per host:port
- Create ServerProfile model + IServerProfileStore in App.Logic (shared)
- LiteDB-backed LocalServerProfileStore for mobile (CRUD by host:port)
- ConnectMobileSessionHandler auto-saves profile on successful connect
- SettingsPage rewritten with server profile list + edit form
- SettingsPageViewModel with save/delete commands
- Desktop ServerRegistration gains PerRequestContext + DefaultSessionContext
- Desktop ServerSetupPanel shows per-request/session context fields
- SaveServerRegistrationRequest/Handler persist new fields
- ServerWorkspaceViewModel loads PerRequestContext from registration
- All 310 tests pass (110 App + 27 Service + 173 Desktop)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make Enter key send message on Android
Android has no Ctrl+Enter, so intercept the hardware Enter key on the
native AppCompatEditText to dispatch SendMessageCommand immediately.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add FR-19/20, TR-21/22: server profiles and mobile chat UX requirements
- FR-19: Server profiles with persistent connection settings per host:port
- FR-20: Mobile chat UX (Enter sends, server-only mode, nav hidden until connected, gRPC-only)
- TR-21: Implementation details for server profile storage (LiteDB, shared model, auto-save)
- TR-22: Implementation details for mobile Enter key, connection mode, visibility, gRPC migration
- Updated FR-2.5/2.6 and TR-5.7 to reflect platform-specific Enter behavior
- Updated requirements-test-coverage.md with FR-17..20 and TR-19..22 entries
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Android Enter-to-send, icon-only Send button, compact button padding
- Use EditorAction + ImeAction.Send instead of KeyPress (soft keyboard
does not fire KeyPress events on Android)
- Send button now uses FontImageSource icon instead of text
- Reduced global Button padding from 24,12 to 12,6 and min height
from 48 to 36 for a more compact mobile UI
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* CQRS server profile handlers + clear API key feature
- Add SaveServerProfileRequest/Handler for persisting profile edits
- Add DeleteServerProfileRequest/Handler for removing profiles
- Add ClearServerApiKeyRequest/Handler to clear stored API keys
- Refactor SettingsPageViewModel to dispatch all commands via IRequestDispatcher
- Add API key status display and Clear API Key button to SettingsPage
- Register all three handlers in MauiProgram.cs DI
- Add ServerProfileHandlerTests with 7 test cases (save, delete, clear key)
- Compact mobile chat UI: remove icon label, shrink session tabs/buttons
- Reduce toolbar to Connect/Disconnect only (session controls in card)
- Default port changed to 5243 (Linux/Docker)
- Update PortPickerViewModelTests to match new default
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Replace .NET splash screen logo with app icon
Replaced the default .NET text logo (splash.svg) with the app's own
icon foreground (appiconfg.svg) so the Android splash screen shows the
Remote Agent logo instead of the generic .NET branding.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Android soft keyboard Enter: show Send action instead of newline
SetRawInputType(InputTypes.ClassText) overrides the IME input type
so Android shows a Send button instead of Enter/newline for the
multi-line Editor control. The EditorAction handler fires on tap.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: update session handoff 2026-02-20T05:22, remove stale handoff
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add file transfer, agents panel, connection settings, toolbar TextBlock fix, UpdateAgentRunner error logging
* Add mandatory session logging priority order to copilot-instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add mandatory session logging to Cursor, Codex, and Cline agent configs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: Remove redundant steps from copilot-instructions priority order
Steps 1-2 (Read AGENTS-README-FIRST.yaml and GET /health) are already
handled by the AGENTS-README-FIRST.yaml marker file processing and
module bootstrap. Removing to match FunWasHad workspace.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: remove redundant session logging preamble and fix old /mcp/ routes
Session procedures now provided by AGENTS-README-FIRST.yaml marker file.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make requirements matrix awk parser mawk-compatible
Co-authored-by: Payton Byrd <sharpninja@users.noreply.github.com>
* docs: switch session-log instructions from entry to turn
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Payton Byrd <sharpninja@users.noreply.github.com>1 parent 3463576 commit 892d84e
183 files changed
Lines changed: 18868 additions & 2991 deletions
File tree
- .github
- workflows
- .vscode
- docs
- scripts
- src
- RemoteAgent.App.Logic
- ViewModels
- RemoteAgent.App
- Handlers
- Platforms/Android
- Requests
- Resources
- Splash
- Styles
- Services
- ViewModels
- RemoteAgent.Desktop
- Assets/AppIcon
- Handlers
- Infrastructure
- Requests
- ViewModels
- Views
- Panels
- RemoteAgent.Proto
- Generated
- RemoteAgent.Service
- Agents
- Services
- Storage
- Web
- tests
- RemoteAgent.App.Tests
- RemoteAgent.Desktop.UiTests
- Handlers
- TestHelpers
- RemoteAgent.Mobile.UiTests
- RemoteAgent.Service.IntegrationTests
- RemoteAgent.Service.Tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
| |||
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
25 | 38 | | |
26 | 39 | | |
27 | 40 | | |
| |||
101 | 114 | | |
102 | 115 | | |
103 | 116 | | |
| 117 | + | |
| 118 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
200 | 273 | | |
201 | 274 | | |
202 | 275 | | |
| |||
273 | 346 | | |
274 | 347 | | |
275 | 348 | | |
276 | | - | |
| 349 | + | |
277 | 350 | | |
278 | 351 | | |
279 | 352 | | |
| |||
313 | 386 | | |
314 | 387 | | |
315 | 388 | | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
316 | 401 | | |
317 | 402 | | |
318 | 403 | | |
319 | 404 | | |
320 | 405 | | |
321 | 406 | | |
322 | 407 | | |
323 | | - | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
324 | 413 | | |
325 | 414 | | |
326 | 415 | | |
| |||
This file was deleted.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
9 | 10 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
3 | 25 | | |
4 | 26 | | |
5 | 27 | | |
| |||
43 | 65 | | |
44 | 66 | | |
45 | 67 | | |
| 68 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
79 | 107 | | |
80 | 108 | | |
81 | 109 | | |
| |||
0 commit comments