Skip to content

Commit 5264cb5

Browse files
sharpninjaCopilot
andcommitted
Implement configuration workflow and desktop improvements
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 89a130d commit 5264cb5

40 files changed

+2478
-142
lines changed

McpServerManager.sln

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.VsExtension.McpTo
4747
EndProject
4848
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9897A8EA-E873-9B68-C2F6-10D3BFE97FAA}"
4949
EndProject
50-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.Common.Copilot.Tests", "lib\McpServer\tests\McpServer.Common.Copilot.Tests\McpServer.Common.Copilot.Tests.csproj", "{8FD37703-A43A-452E-B1DF-C51C14EC787F}"
51-
EndProject
5250
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McpServer.Common.Copilot", "lib\McpServer\src\McpServer.Common.Copilot\McpServer.Common.Copilot.csproj", "{6F5701FC-F0DF-415C-9484-13EFD36E11CB}"
5351
EndProject
5452
Global
@@ -253,18 +251,6 @@ Global
253251
{576EC5F4-1C16-4796-9CC0-3DD4EF119243}.Release|x64.Build.0 = Release|Any CPU
254252
{576EC5F4-1C16-4796-9CC0-3DD4EF119243}.Release|x86.ActiveCfg = Release|Any CPU
255253
{576EC5F4-1C16-4796-9CC0-3DD4EF119243}.Release|x86.Build.0 = Release|Any CPU
256-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
257-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|Any CPU.Build.0 = Debug|Any CPU
258-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|x64.ActiveCfg = Debug|x64
259-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|x64.Build.0 = Debug|x64
260-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|x86.ActiveCfg = Debug|x86
261-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Debug|x86.Build.0 = Debug|x86
262-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|Any CPU.ActiveCfg = Release|Any CPU
263-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|Any CPU.Build.0 = Release|Any CPU
264-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|x64.ActiveCfg = Release|x64
265-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|x64.Build.0 = Release|x64
266-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|x86.ActiveCfg = Release|x86
267-
{8FD37703-A43A-452E-B1DF-C51C14EC787F}.Release|x86.Build.0 = Release|x86
268254
{6F5701FC-F0DF-415C-9484-13EFD36E11CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
269255
{6F5701FC-F0DF-415C-9484-13EFD36E11CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
270256
{6F5701FC-F0DF-415C-9484-13EFD36E11CB}.Debug|x64.ActiveCfg = Debug|x64
@@ -301,7 +287,6 @@ Global
301287
{BE32426E-CF8B-456A-9ECF-C6B0B86D9E06} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
302288
{576EC5F4-1C16-4796-9CC0-3DD4EF119243} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
303289
{9897A8EA-E873-9B68-C2F6-10D3BFE97FAA} = {AC2490A8-6721-B82B-8F37-115021953299}
304-
{8FD37703-A43A-452E-B1DF-C51C14EC787F} = {9897A8EA-E873-9B68-C2F6-10D3BFE97FAA}
305290
{6F5701FC-F0DF-415C-9484-13EFD36E11CB} = {6AF42076-EE0C-549E-06B8-456F4C7181C1}
306291
EndGlobalSection
307292
EndGlobal

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,22 @@ dotnet run
5353

5454
## Deployment automation
5555

56-
Use NUKE from the repo root as the authoritative build/deploy entry point.
56+
Use NUKE from the repo root as the authoritative build/deploy entry point for local automation and CI.
5757

5858
```powershell
5959
.\build.ps1
60-
.\build.ps1 --target DeployAll
61-
.\build.ps1 --target DeployAll --deploy-selection Director,WebUi,DesktopMsix
62-
.\build.ps1 --target DeployAll --what-if
63-
.\build.ps1 --target DeployAll --configuration Debug --deploy-selection Director,WebUi
60+
.\build.ps1 DeployAll
61+
.\build.ps1 DeployAll --deploy-selection Director,WebUi,DesktopMsix
62+
.\build.ps1 DeployAll --what-if
63+
.\build.ps1 DeployAll --configuration Debug --deploy-selection Director,WebUi
6464
.\build.ps1 BuildAndInstallVsix --what-if
6565
```
6666

67+
```bash
68+
bash ./build.sh VersionInfo --json-output-path artifacts/version.json
69+
bash ./build.sh BuildDesktopDeb --package-version <semver>
70+
```
71+
6772
Current target names:
6873
- `Director`
6974
- `WebUi`
@@ -76,13 +81,19 @@ Behavior notes:
7681
- `build.ps1` and `build.sh` are the primary entry points; they invoke `build\Build.csproj` with the repo root wired up for NUKE.
7782
- When invoked with no arguments, the root wrappers forward `--help` so you see NUKE help instead of accidentally running a default target.
7883
- For convenience, the wrappers treat the first bare argument as `--target`, so commands like `.\build.ps1 BuildAndInstallVsix --what-if` work without spelling out `--target`.
84+
- `.github\workflows\build-android.yml` is intentionally thin: the workflow restores tools and runner prerequisites, then delegates versioning, packaging, release, F-Droid, and Pages assembly to NUKE targets.
7985
- The build is best-effort for deploy-all: unavailable targets are skipped and reported in the final summary.
8086
- `--what-if` is the standard dry-run mechanism for NUKE-backed targets.
81-
- `DesktopMsix` deployment auto-elevates only the certificate trust/install step through `gsudo`, avoiding elevated NUKE re-entry log-file conflicts; otherwise the build fails with guidance to install `gsudo` or rerun from an elevated PowerShell session.
87+
- `DesktopMsix` deployment auto-elevates only the certificate trust step through `gsudo`, then installs the package back in the invoking user context to ensure the app registers for the actual desktop user.
8288
- `DesktopDeb` installation on Windows launches an interactive WSL `sudo` prompt so the user can enter their password when package installation is requested.
8389
- Legacy files under `scripts\` now act as compatibility wrappers so existing commands continue to work while NUKE owns the orchestration logic.
8490
- For independent target execution, import `scripts\DeployAllTargets.psm1` and call the exported compatibility functions directly, for example `Invoke-DeployDirectorTool -Configuration Debug -WhatIf`.
8591

92+
Validation commands:
93+
- `dotnet build build\Build.csproj -nologo`
94+
- `dotnet build src\McpServerManager.Desktop\McpServerManager.Desktop.csproj -nologo`
95+
- `Invoke-Pester -Path scripts\DeployAllTargets.Tests.ps1 -Output Detailed -CI`
96+
8697
### WSL with WSLg
8798

8899
On WSL with WSLg enabled (Windows 11), the app window should appear on the Windows desktop. If it doesn’t:

build/Build.MsixPackaging.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -353,45 +353,44 @@ private string BuildDesktopMsixWithElevation()
353353
{
354354
if (CommandExists("gsudo"))
355355
{
356-
Warn("[WhatIf] Elevate the MSIX certificate trust/install step through gsudo.");
356+
Warn("[WhatIf] Elevate the MSIX certificate trust step through gsudo, then install the package in the invoking user context.");
357357
}
358358
else
359359
{
360-
Warn("[WhatIf] MSIX installation would require elevation, and gsudo was not found in PATH.");
360+
Warn("[WhatIf] MSIX certificate trust would require elevation, and gsudo was not found in PATH.");
361361
}
362362

363363
return BuildDesktopMsixCoreNative(installAfterBuild: false);
364364
}
365365

366366
if (!CommandExists("gsudo"))
367367
{
368-
throw new InvalidOperationException("MSIX installation requires elevation, but gsudo was not found in PATH. Install gsudo or rerun this command from an elevated PowerShell session.");
368+
throw new InvalidOperationException("MSIX certificate trust requires elevation, but gsudo was not found in PATH. Install gsudo or rerun this command from an elevated PowerShell session.");
369369
}
370370

371371
var packagingContext = ResolveDesktopMsixPackagingContext();
372372
var msixPath = BuildDesktopMsixCoreNative(installAfterBuild: false);
373-
InstallMsixPackageWithGsudo(packagingContext.Config.PackageName, msixPath, packagingContext.CertificatePath);
373+
TrustMsixCertificateWithGsudo(packagingContext.CertificatePath);
374+
InstallMsixPackage(packagingContext.Config.PackageName, msixPath);
374375
return msixPath;
375376
}
376377

377378
[SupportedOSPlatform("windows")]
378-
private void InstallMsixPackageWithGsudo(string packageName, string msixPath, string certificatePath)
379+
private void TrustMsixCertificateWithGsudo(string certificatePath)
379380
{
380381
var command = string.Join(
381382
Environment.NewLine,
382383
new[]
383384
{
385+
"$ErrorActionPreference = 'Stop'",
384386
$"$certPath = '{QuotePowerShellLiteral(certificatePath)}'",
385-
$"$msixPath = '{QuotePowerShellLiteral(msixPath)}'",
386-
$"$packageName = '{QuotePowerShellLiteral(packageName)}'",
387387
"if (-not (Test-Path -LiteralPath $certPath)) { throw \"Signing certificate not found at $certPath\" }",
388-
"if (-not (Test-Path -LiteralPath $msixPath)) { throw \"MSIX package not found at $msixPath\" }",
389388
"$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $certPath",
390389
"$trustedCertificate = Get-ChildItem Cert:\\LocalMachine\\Root | Where-Object { $_.Thumbprint -eq $certificate.Thumbprint } | Select-Object -First 1",
391-
"if ($null -eq $trustedCertificate) { Import-Certificate -FilePath $certPath -CertStoreLocation 'Cert:\\LocalMachine\\Root' | Out-Null }",
392-
"$existingPackage = Get-AppxPackage -Name $packageName -ErrorAction SilentlyContinue",
393-
"if ($null -ne $existingPackage) { Remove-AppxPackage -Package $existingPackage.PackageFullName }",
394-
"Add-AppxPackage -Path $msixPath"
390+
"if ($null -eq $trustedCertificate) {",
391+
" $imported = Import-Certificate -FilePath $certPath -CertStoreLocation 'Cert:\\LocalMachine\\Root'",
392+
" if ($null -eq $imported) { throw \"Certificate import did not return a result for $certPath\" }",
393+
"}"
395394
});
396395

397396
var result = InvokeProcess(
@@ -413,7 +412,7 @@ private void InstallMsixPackageWithGsudo(string packageName, string msixPath, st
413412

414413
if (result.ExitCode != 0)
415414
{
416-
throw new InvalidOperationException($"gsudo failed to elevate MSIX installation (exit code {result.ExitCode}).{Environment.NewLine}{result.GetCombinedOutput()}");
415+
throw new InvalidOperationException($"gsudo failed to elevate MSIX certificate trust (exit code {result.ExitCode}).{Environment.NewLine}{result.GetCombinedOutput()}");
417416
}
418417
}
419418

@@ -819,9 +818,12 @@ private void InstallMsixPackage(string packageName, string msixPath)
819818
Environment.NewLine,
820819
new[]
821820
{
821+
"$ErrorActionPreference = 'Stop'",
822822
$"$existing = Get-AppxPackage -Name '{QuotePowerShellLiteral(packageName)}' -ErrorAction SilentlyContinue",
823-
"if ($null -ne $existing) { Remove-AppxPackage -Package $existing.PackageFullName }",
824-
$"Add-AppxPackage -Path '{QuotePowerShellLiteral(msixPath)}'"
823+
"if ($null -ne $existing) { Remove-AppxPackage -Package $existing.PackageFullName -ErrorAction Stop }",
824+
$"Add-AppxPackage -Path '{QuotePowerShellLiteral(msixPath)}' -ErrorAction Stop",
825+
$"$installed = Get-AppxPackage -Name '{QuotePowerShellLiteral(packageName)}' -ErrorAction Stop",
826+
"if ($null -eq $installed) { throw \"Package registration was not visible after Add-AppxPackage completed.\" }"
825827
});
826828
InvokePowerShellCommand(command, true);
827829
}

docs/todo.yaml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -854,12 +854,25 @@ mvp-mcp:
854854
director:
855855
medium-priority:
856856
- id: DIR-UI-001
857-
title: '[NEEDS PLAN] Reorder the tabs so that global config tabse are at the end.'
857+
title: Reorder the tabs so that non-workspace tabs are at the end.
858+
note: Implementation and bookkeeping refreshed on 2026-03-11 after DIR-UI-001 planning and code changes.
858859
done: false
859860
description:
860-
- Place global config tabs (non-Workspace specific) at the end of the tabs.
861+
- Move the Director non-workspace tabs (Health, Workspaces, Policy, Logs, and Config) to the end of the tab strip.
862+
- Keep workspace-scoped and workspace-aware tabs first after the existing authorization and availability filtering.
863+
remaining: Implementation is complete, but targeted validation and build-tool redeploy are blocked by unrelated McpServer.Director package restore/version issues (missing package versions plus NU1602/NU1605/NU1608 restore-as-error conflicts).
861864
technical-details:
862-
- '-'
865+
- Add TabPlacementGroup metadata to TabRegistration in McpServer.UI.Core/Navigation/ITabRegistry.cs.
866+
- Apply a stable GetVisibleTabRegistrations helper in MainScreen so filtering happens before placement ordering.
867+
- Cover admin, agent-manager, and viewer ordering cases in focused Director tests.
863868
implementation-tasks:
864-
- task: '[ ]'
869+
- task: Add placement metadata to the shared Director tab registration model
870+
done: true
871+
- task: Mark the non-workspace Director tabs as trailing in MainScreen
872+
done: true
873+
- task: Add focused tab-ordering tests for the Director screen
874+
done: true
875+
- task: Resolve unrelated McpServer.Director package restore/version failures and rerun targeted validation
876+
done: false
877+
- task: Redeploy Director through build.ps1 UpdateDirectorTool after restore issues are fixed
865878
done: false

lib/McpServer

Submodule McpServer updated 164 files

nupkg/SharpNinja.McpServer.Director.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
33
<metadata>
44
<id>SharpNinja.McpServer.Director</id>
5-
<version>0.5.1-22</version>
5+
<version>0.5.1-30</version>
66
<authors>SharpNinja</authors>
77
<description>CLI management tool for McpServer. Provides workspace management, agent orchestration, compliance policy editing, Keycloak OIDC auth, and an interactive Terminal.Gui TUI with 7 tabbed screens. 18 CLI commands via System.CommandLine.</description>
88
<packageTypes>

nupkg/SharpNinja.McpServer.Web.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
33
<metadata>
44
<id>SharpNinja.McpServer.Web</id>
5-
<version>0.5.1-22</version>
5+
<version>0.5.1-30</version>
66
<authors>SharpNinja</authors>
77
<description>SharpNinja.McpServer.Web</description>
88
<packageTypes>

src/McpServer.Director/Auth/DirectorAuthorizationPolicyService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ internal sealed class DirectorAuthorizationPolicyService : IAuthorizationPolicyS
2929
[McpArea.Diagnostic] = McpRoles.Viewer,
3030
[McpArea.AuthConfig] = McpRoles.Viewer,
3131
[McpArea.Templates] = McpRoles.Viewer,
32+
[McpArea.Configuration] = McpRoles.Admin,
3233
};
3334

3435
private static readonly IReadOnlyDictionary<string, string> s_actionRoles =
@@ -125,6 +126,8 @@ internal sealed class DirectorAuthorizationPolicyService : IAuthorizationPolicyS
125126
[McpActionKeys.VoiceTranscript] = McpRoles.Viewer,
126127
[McpActionKeys.VoiceDeleteSession] = McpRoles.Viewer,
127128
[McpActionKeys.EventsSubscribe] = McpRoles.Viewer,
129+
[McpActionKeys.ConfigurationGet] = McpRoles.Admin,
130+
[McpActionKeys.ConfigurationPatch] = McpRoles.Admin,
128131
};
129132

130133
/// <summary>Initializes a new instance of the policy service.</summary>

0 commit comments

Comments
 (0)