Skip to content

CLI: Global option scopes for nested commands (related to compose support) - #41546

Merged
David Bennett (dkbennett) merged 24 commits into
masterfrom
user/dkbennett/globaloptionrefactor
Sep 16, 2026
Merged

David Bennett (dkbennett) merged 24 commits into
masterfrom
user/dkbennett/globaloptionrefactor

Conversation

@dkbennett

@dkbennett David Bennett (dkbennett) commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

Summary of the Pull Request

Adds command-scoped global options to the WSLC CLI.

Global options are accepted after the command that declares them and are inherited by its descendants:

wslc --session foo compose --progress plain up

The command model is now a persistent, lazily populated tree with stable parent references. CommandInvocation owns that tree and the lifecycle of one invocation, including the original arguments, parsing cursor, selected command, parsing, environment option application, execution, and error help. CLIExecutionContext remains separate and owns parsed values and execution services.

Commands declare command-local and global arguments separately through GetArguments() and GetGlobalArguments(). Global arguments retain their declaring command through Argument::GlobalOwner(), and Argument::Scope() derives whether an argument is global or command-local from that ownership. All parsed values share CLIExecutionContext::Args.

Argument source restrictions are represented by the composable argument::Flags bitmask in ArgumentOverrides. Flags::EnvironmentOnly arguments participate in environment loading and validation, but are excluded from command-line parsing and help. Environment bindings for ordinary arguments remain inert, so an argument must explicitly opt into environment-only behavior.

Help groups global options by their declaring command so users can see where each option must be specified:

Global Options for 'wslc':
Global Options for 'compose':

Clearer help for misplaced global arguments

This also improves errors for misplaced global arguments, particularly --session, by explaining where the option must appear in the command line. This addresses #41222.

image

PR Checklist

Detailed Description of the Pull Request / Additional comments

  • Adds global argument inheritance along the selected command path.
  • Requires global options to appear after their declaring command and before its subcommand.
  • Reports corrective placement guidance for misplaced ancestor globals; options from other branches remain unknown arguments.
  • Uses argument ownership consistently for scope, parsing, help grouping, and diagnostics.
  • Separates environment-only arguments from command-line arguments as an explicit argument property.
  • Simplifies the parser by removing environment-default replacement state now that argument sources do not overlap.
  • Applies environment options idempotently and resolves NO_COLOR before user-visible output.
  • Preserves lazy command creation when handling positional arguments and invalid options.

Validation Steps Performed

  • Built the complete x64 Debug configuration.
  • Passed all 472 focused WSLC CLI unit tests.
  • Passed all 64 tests selected by the *Help* filter.

Copilot AI lite review requested due to automatic review settings September 9, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The newly added localized strings include placeholder metadata that doesn’t match the number of {} inserts, which can break/impair localization tooling and should be corrected before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces a new command-line parsing pipeline for wslc that supports command-scoped “global” options across nested subcommands (to enable Compose-style syntax like wslc --session foo compose --progress plain up). It centralizes command resolution + scoped global parsing in a reusable parser and updates help/output and tests accordingly.

Changes:

  • Added CommandLineParser to resolve subcommands while parsing scoped global options into CLIExecutionContext::GlobalArgs.
  • Enhanced diagnostics/help to show scoped global options and emit targeted errors for misplaced global options.
  • Updated and expanded unit tests to cover scoped-global accumulation, placement errors, and command-tree invariants.
File summaries
File Description
test/windows/wslc/WSLCCLIExecutionUnitTests.cpp Adds scoped-global parser tests and switches the parsing matrix to use ParseCommandLine.
test/windows/wslc/WSLCCLICommandUnitTests.cpp Extends command validation to include global args; adds inherited-global collision/invariant checks.
src/windows/wslc/core/Main.cpp Replaces the previous multi-pass parsing pipeline with ParseCommandLine.
src/windows/wslc/core/Exceptions.h Extends ArgumentException to preserve an unknown-option token for higher-level diagnostics.
src/windows/wslc/core/CommandLineParser.h Declares the new scoped-global parsing and scope/introspection helpers.
src/windows/wslc/core/CommandLineParser.cpp Implements scoped-global parsing, scope/path discovery, and misplaced-global diagnostics.
src/windows/wslc/core/Command.h Updates the contract/comment for GetGlobalArguments() semantics.
src/windows/wslc/core/Command.cpp Updates help rendering to include scoped global options and a [global-options] usage placeholder.
src/windows/wslc/core/CLIExecutionContext.h Updates documentation to reflect that GlobalArgs are accumulated across scopes.
src/windows/wslc/commands/RootCommand.cpp Updates documentation comment for root global option positioning.
src/windows/wslc/arguments/ArgumentParser.cpp Tags invalid-name/alias errors with the unknown token for misplaced-global detection.
localization/strings/en-US/Resources.resw Adds new localized strings for misplaced scoped-global diagnostics and scoped-global help headings.
Review details

Suppressed comments (1)

localization/strings/en-US/Resources.resw:2226

  • This resource string has two "{}" placeholders but the only includes one {FixedPlaceholder="{}"}. For consistency with nearby strings (e.g., WSLCCLI_Usage), the comment should include two FixedPlaceholder entries.
  <data name="WSLCCLI_MisplacedGlobalOptionMultipleScopesError" xml:space="preserve">
    <value>Global option '{}' is not valid at this position. It is defined for these commands: {}. Specify it after the intended command and before its subcommand.</value>
    <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
  • Files reviewed: 12/12 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings September 9, 2026 18:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

src/windows/wslc/core/Command.cpp should include precomp.h first to match core directory conventions and ensure consistent PCH usage.

Review details

Suppressed comments (1)

src/windows/wslc/core/Command.cpp:21

  • src/windows/wslc/core/*.cpp files conventionally include precomp.h first; Command.cpp currently doesn’t, which can break PCH usage and makes include ordering inconsistent with the rest of the directory (e.g. Main.cpp, TableOutput.cpp). Please include precomp.h as the first include in this translation unit.
#include "Argument.h"
#include "Command.h"
#include "CommandLineParser.h"
#include "Invocation.h"
#include "ArgumentParser.h"
#include "RootCommand.h"
#include "TableOutput.h"

  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 9, 2026 18:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes the core CLI parsing behavior and error-reporting paths, so a final human review is warranted despite strong test coverage.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/windows/wslc/core/CommandLineParser.cpp:255

  • ParseCommandLine always builds globalScopes by traversing the entire command tree (GetGlobalArgumentScopes) even on successful parses. Because RootCommand::GetCommands() eagerly constructs many command objects, this adds avoidable overhead to every invocation when the scopes are only needed for misplaced-global diagnostics. Consider deferring scope collection until an unknown/misplaced option is detected.
    src/windows/wslc/core/CommandLineParser.cpp:79
  • CollectGlobalArgumentPath calls GetGlobalArguments() twice (once to check emptiness, again via MakeGlobalArgumentScope), which duplicates work and could be problematic if GetGlobalArguments() ever becomes non-trivial or order-dependent. Cache the vector once and move it into the scope.
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 9, 2026 18:48
@dkbennett
David Bennett (dkbennett) marked this pull request as ready for review September 9, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Main.cpp now duplicates root-scope environment option scanning with the new scoped parser, and this redundancy should be cleaned up to keep parsing responsibilities consistent and avoid unnecessary work.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/windows/wslc/core/Main.cpp:110

  • ParseCommandLine() now applies environment-backed defaults as each command scope is entered; with the current flow, the root scope gets scanned twice (once here and once inside ParseCommandLine), which is redundant work and splits the responsibility across two places. Consider restricting the pre-try scan to env-only arguments needed before any output (e.g. NO_COLOR) and letting ParseCommandLine handle env defaults for globals/scoped commands.
  • Files reviewed: 12/12 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 9, 2026 19:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes the core CLI parsing and help/diagnostics path in user-facing code, so it warrants final human review despite strong test coverage.

Review details
  • Files reviewed: 13/13 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

ggarzia-MSFT
ggarzia-MSFT previously approved these changes Sep 9, 2026
Comment thread src/windows/wslc/core/Main.cpp Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It substantially refactors core CLI parsing/control flow and command-tree ownership semantics, warranting careful human validation beyond the added tests.

Review details
  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Co-authored-by: Copilot <[email protected]>
Copilot-Session: b218715f-3b09-4fd3-ad77-a4ca9c74c2f7

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical session selection remains unimplemented, and command-local NO_COLOR environment handling can be ignored.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

src/windows/wslc/core/Main.cpp:97

  • This freezes NoColor before the selected command's environment-only arguments are loaded. If a command declares the new Flags::EnvironmentOnly binding for NoColor locally, GetValue records the default false as immutable; ParseCommandLine then cannot add the NO_COLOR value, and ApplyEnvironmentOptions catches that failure, so NO_COLOR is silently ignored for that command. Apply selected-command environment options before freezing terminal state (while still doing so before output).
  • Files reviewed: 43/43 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/windows/wslc/core/Invocation.cpp Resolved
Copilot AI review requested due to automatic review settings September 14, 2026 04:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Three moderate issues remain in forwarding, help filtering, and same-command global parsing.

Review details

Suppressed comments (3)

src/windows/wslc/arguments/ArgumentParser.cpp:207

  • This check runs before ProcessAnchoredPositionals, so an inherited global token after the image in a command with ForwardArgs is rejected instead of being forwarded. For example, the added ScopedGlobalArguments_GlobalTokenAfterRunImageIsCommandArgument case (run debian --session foo) reaches this branch: --session is the forwarded command token and foo should remain in ForwardArgs. Keep the inherited-option diagnostic for non-forwarding unlimited positionals, but let anchored forwarding paths proceed first.
    if (inheritedGlobalOption != nullptr)

src/windows/wslc/core/Command.cpp:352

  • GetGlobalArgumentsForPath uses its default Flags::All, so this vector still contains EnvironmentOnly arguments. OutputHelp passes every entry to AddArgumentRows, which makes root help advertise --no-color even though environment-only arguments are intended to be excluded from command-line help and parsing. Filter those arguments before building the scoped help sections (and add a regression assertion for the absence of this option).
    const auto globalArguments = GetGlobalArgumentsForPath(*this);

src/windows/wslc/core/Invocation.cpp:104

  • This two-pass flow makes same-command globals order-dependent. If a command-local option (including the synthetic --help) appears first, the global-only pass stops at it, and the final pass parses only command-local plus inherited globals—not the selected command's own globals—so compose --help --progress plain reports --progress as unknown even though it is after compose and before any subcommand. Parse both scopes together or otherwise preserve/reparse the current command's globals after local options.
  • Files reviewed: 43/43 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 14, 2026 06:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The critical dangling-reference issue in src/windows/wslc/core/Invocation.h must be fixed before approval.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 43/43 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/windows/wslc/core/Invocation.h Resolved
@dkbennett
David Bennett (dkbennett) marked this pull request as ready for review September 14, 2026 17:06
Copilot AI review requested due to automatic review settings September 16, 2026 00:01
@dkbennett
David Bennett (dkbennett) requested a review from a team as a code owner September 16, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad CLI parsing and command-tree refactor requires final human review.

Review details
  • Files reviewed: 42/42 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 16, 2026 16:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A moderate issue remains in environment option filtering; ordinary arguments must not be populated from environment bindings unless Flags::EnvironmentOnly is enforced.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 42/42 changed files
  • Comments generated: 1
  • Review effort level: Lite

@ggarzia-MSFT ggarzia-MSFT left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, minor nit that may need to wait until post-GA

// Build usage line with Write calls for each segment.
{
std::wstring usageText = Localization::WSLCCLI_Usage(s_ExecutableName, std::wstring_view{commandChain});
std::wstring usageText = Localization::WSLCCLI_Usage(commandInvocation, L"");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can change WSLCCLI_Usage string to only take one parameter now that commandInvocation contains the executable in it

@dkbennett
David Bennett (dkbennett) merged commit bf9b8aa into master Sep 16, 2026
12 checks passed
@dkbennett
David Bennett (dkbennett) deleted the user/dkbennett/globaloptionrefactor branch September 16, 2026 22:48
Blue (OneBlue) added a commit that referenced this pull request Sep 22, 2026
* Fix tracked routes being collapsed by incomplete comparison (#41393)

Mirrored route tracking used an incomplete comparator that considered only route class, destination address, and metric. Distinct routes with different prefix lengths or next hops could therefore be treated as equivalent and silently omitted.

The fix preserves the existing route-class ordering while using the complete EndpointRoute comparison for route identity. Regression tests cover prefix length, next hop, metric, exact duplicates, and dependency ordering.

* Add github issue suggestion in user visible error (#41432)

This PR adds a "search or file issue on github" suggestion in all user visible errors to:
Help users find solutions faster.
Collect more user reported issues to help reliability improvements.

This PR also updates all tests checking the error message to use a unified function for creating the expected error message.

* Match Docker output for prune operations and container inspection (#41430)

Cleanup various miscellaneous output divergences

Co-authored-by: Copilot <[email protected]>

* CLI: Mount PR followup & fix two docker parser bugs (#41436)

* Invalid the TestImageRegistry cache after running prune --all (#41442)

* Fix unit test build failure on arm64 (#41437)

* Solve various issues found by verifier (#41445)

* Save state

* Save state

* Save state

* Cleanup diff

* Add a command line option to run the tests under verifier  (#41440)

* Save state

* Save state

* Save state

* Add a /verifier option to run-tests.ps1 to run the test under verifier

* Localization change from build: 155859879 (#41450)

Co-authored-by: WSL localization <[email protected]>

* Fix various arm64 test failures (#41444)

* Fix various arm64 test failures

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix LF

* Format

* Cleanup diff

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

* Fix unity build ODR collisions on duplicate file-local constants (#41446)

* CLI: Align alias listing with docker, Apple and other CLIs (#41439)

* Align container list format with Docker specifications (#41375)

wslc: match column order, status text, and json shape for container list


Co-authored-by: Copilot <[email protected]>

* Localization change from build: 156161979 (#41479)

Co-authored-by: WSL localization <[email protected]>

* wslc: alias -f to --format on inspect commands for docker parity (#41463)

Co-authored-by: Copilot <[email protected]>

* CLI: Add explicit per-command argument overrides (#41478)

* archlinux: Release 2026.09.01.176721 (#41493)

This is an automated release [1].

[1] https://gitlab.archlinux.org/archlinux/archlinux-wsl/-/blob/main/.gitlab-ci.yml

* Fix WSLC parser unit test argument overrides (#41496)

Update the remaining parser test call site to use ArgumentOverrides after the Argument::Create API change.

Co-authored-by: Copilot <[email protected]>

Co-authored-by: Ben Hillis <[email protected]>
Copilot-Session: eb7946ff-cc0b-4ff1-a059-571334b1c988

* Fix systemd-tmpfiles failure on systemd v261+ with systemd boot disabled (#41491)

In systemd v261, the systemd's tmpfiles.d/x11.conf was changed from D! to D. systemd/systemd@5474cad.
This means the systemd-tmpfiles command will try to execute it when called out of the boot sequence. In the linked issue's case, it's called by the post install script by dpkg. This will fail as the wsl override is not in place when systemd is disabled.

This PR enables the wsl override file generation for all distros with wslg enabled, regardless of if the distro boots with systemd.

* Fix unvalidated TerminalProfileSize during distribution import (#41495)

* Fix unvalidated TerminalProfileSize when importing a distribution

_ProcessImportResultMessage constructed the terminal profile string_view
using the message-supplied TerminalProfileSize without validating it
against the received buffer length. Use the bounds-checked two-argument
span::subspan() overload (matching the existing ShortcutIconSize handling
a few lines above) so an inconsistent size value throws instead of
producing a string_view that runs past the end of the buffer.

Co-authored-by: Copilot <[email protected]>
Copilot-Session: 35281c30-3d08-4f05-8c84-2ce4711023d5

* format source

---------

Co-authored-by: Ben Hillis <[email protected]>
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 35281c30-3d08-4f05-8c84-2ce4711023d5

* Bump WSL DeviceHost to 1.2.62 (#41499)

* Bump WSL DeviceHost to 1.2.62

Co-authored-by: damanm24 <[email protected]>

* Correct WSL DeviceHost version to 1.2.62-0

Co-authored-by: damanm24 <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: damanm24 <[email protected]>

* Enable unity build repo-wide via WSL_UNITY_BATCH_SIZE (#41441)

Enable unity build repo-wide via WSL_UNITY_BATCH_SIZE

Co-authored-by: Copilot <[email protected]>

* Add wslc system info command (#41408)

* updated source code paths in the wslservice tab (#41509)

Co-authored-by: Tega Ajise <[email protected]>

* Harden Windows macros against dangling-else ambiguity (#41513)

* Harden Windows macros against dangling-else ambiguity

* Harden Windows macros against dangling-else ambiguity

* Fix dangling-else bugs in FAIL_FAST_IF and EMIT_USER_WARNING macros (#41504)

* Fix dangling-else bugs in FAIL_FAST_IF and EMIT_USER_WARNING macros  

Both macros were bare if-statements without do/while(0) guards, causing
the dangling else problem when used as a single statement under an if.

* Fix dangling-else bugs in FAIL_FAST_IF and EMIT_USER_WARNING macros

* harden EMIT_USER_WARNING macro on Windows against dangling-else

* Fix dangling-else bugs in FAIL_FAST_IF and EMIT_USER_WARNING macros

* Fix intermittent ImportDistroInvalidTar test failures (#41490)

* Fix test to be more resilient

* Make WSL1 more lenient, make WSL2 exact

* Wslc events (#40971)

* Revert "Mount plugin folders on behalf of the user owning the wsl session" (#41331) (#41515)

Temporarily reverting the identity-based plugin folder mount change
(both the WslCoreVm.cpp behavior change and the accompanying
MountFolderAccess test coverage) introduced in #41331.

This reverts commit 78b9cf2.

Co-authored-by: Ben Hillis <[email protected]>
Co-authored-by: Copilot <[email protected]>

* Add container restart runtime support (#41454)

* Fix p9 drvfs read only mount regression (#41487)

#41129 introduces a regression where the ";ro" option is passed to the host for p9 shares. However, that option is not supported by the p9 server and causes the mount to fail.

This PR removes the special handling of "ro" in the common parser. And use MountParseFlags to add the required virtio option.

* Fix WSLC Plan9 mount and image-build failures (#41535)

* Fix WSLC Plan9 mounts using a per-user server

* remove debug code

* wslc: add --size to inspect for docker parity (#41489)

Co-authored-by: Copilot <[email protected]>

* Bump actions/deploy-pages in the github-actions group (#41537)

Bumps the github-actions group with 1 update: [actions/deploy-pages](https://github.com/actions/deploy-pages).


Updates `actions/deploy-pages` from 5.0.0 to 5.0.1
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](actions/deploy-pages@cd2ce8f...368f825)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Add wslc container restart command (#41435)

* init: fix dhcpcd option name in bridged-mode config (#41538)

* init: fix dhcpcd option name in bridged-mode config

dhcpcd has no option named "broadcast"; option 28 is "broadcast_address".
dhcpcd 10 rejects the whole "option" line, so DNS servers, domain, search
list, hostname and MTU were never requested from the DHCP server, leaving
/mnt/wsl/resolv.conf without nameservers on servers that honour the PRL.

* init: apply clang-format to dhcpcd config string

The longer broadcast_address option name pushed the literal past the
130-column limit in .clang-format. Split it as clang-format does; the
concatenated value is unchanged.

* Update SLE15SP7 [QU5] (#41506)

* Host plugin Plan9 shares as the session user (#41548)

* Host plugin Plan9 shares as the session user

Use a dedicated per-user Plan9 server for plugin folder mounts so host filesystem permissions are preserved without relying on HCS-managed share identity.

Co-authored-by: Copilot <[email protected]>

Copilot-Session: c20b1da0-c613-489d-92a3-9c27527c0c54

* Simplify plugin Plan9 port plumbing

Use the fixed plugin port directly in mini_init and mirror the existing per-user Plan9 server lifecycle.

Co-authored-by: Copilot <[email protected]>

Copilot-Session: c20b1da0-c613-489d-92a3-9c27527c0c54

* Recreate stopped plugin Plan9 servers

Recreate the per-user server before adding a share when its process is no longer running.

Co-authored-by: Copilot <[email protected]>

Copilot-Session: c20b1da0-c613-489d-92a3-9c27527c0c54

---------

Co-authored-by: Ben Hillis <[email protected]>
Copilot-Session: c20b1da0-c613-489d-92a3-9c27527c0c54

* Fix virtiofs bind mounts exposing files as root-owned (#40719) (