Skip to content

Conversation

@AmelBawa-msft
Copy link

@AmelBawa-msft AmelBawa-msft commented Feb 6, 2026

Summary of the Pull Request

⚠️ The code changes in this PR are still in a construction phase, but the current quality is sufficient to unblock the team while new functionalities are being implemented.

🙌 Demo

[Window 1]
wslc container --help
wslc container run --help
wslc container run -it --name demo ubuntu:latest /bin/bash

[Window 2]
wslc container exec demo ls -lt
wslc container list --help
wslc container list
wslc container list -aq
wslc container inspect demo
wslc container kill demo

[Window 1]
# Verify container is not attached anymore
wslc container delete demo
wslc container list -a

🦞 Full implementation

Run --help for each command and subcommand for the full list of supported options.

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

@AmelBawa-msft AmelBawa-msft requested a review from a team as a code owner February 6, 2026 19:19
Copilot AI review requested due to automatic review settings February 6, 2026 19:19
options.CpuCount = 4;
options.MemoryMb = 2048;
options.BootTimeoutMs = 30 * 1000;
options.StoragePath = dataFolder.c_str();
Copy link
Member

Choose a reason for hiding this comment

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

Dangling pointer to local; a suggestion on a pattern to fix it: https://github.com/microsoft/WSL/compare/user/amelbawa/init...JohnMcPMS:amir-suggest?expand=1

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an initial command/subcommand framework for the wslc CLI and refactors prior monolithic logic into command + service/model components to support image, container, and shell operations.

Changes:

  • Replaced the old top-level verb handling with an ICommand-based dispatcher (image, container, shell) and per-subcommand implementations.
  • Added services/models for sessions, images, containers, console attach/stdio wiring, and table output.
  • Updated build wiring for the new wslc sources/headers and tweaked the root vswhere detection logic.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 35 comments.

Show a summary per file
File Description
src/windows/wslc/main.cpp Routes CLI execution through a new RootCommand dispatcher.
src/windows/wslc/ICommand.h / .cpp Adds a command interface + shared parsing/help utilities.
src/windows/wslc/ShellCommand.h / .cpp Implements wslc shell list/attach.
src/windows/wslc/ShellService.h / .cpp Adds session listing and attach logic for shell sessions.
src/windows/wslc/ImageCommand.h / .cpp Implements wslc image list/pull.
src/windows/wslc/ImageService.h / .cpp Adds image list/pull operations via WSLA APIs.
src/windows/wslc/ImageModel.h Defines image info model + serialization.
src/windows/wslc/ContainerCommand.h / .cpp Implements wslc container subcommands (run/create/start/stop/kill/delete/list/exec/inspect).
src/windows/wslc/ContainerService.h / .cpp Adds container lifecycle/exec/inspect operations.
src/windows/wslc/ContainerModel.h Defines container option/result/info models + serialization.
src/windows/wslc/ConsoleService.h / .cpp Centralizes stdio fd building and console attach/relay logic.
src/windows/wslc/ConsoleModel.h Defines console attach options.
src/windows/wslc/SessionService.h / .cpp Adds a session creation helper.
src/windows/wslc/SessionModel.h / .cpp Defines session wrapper and default session settings.
src/windows/wslc/Utils.h / .cpp Moves pull/progress logic and terminal cursor RAII helper.
src/windows/wslc/TableOutput.h Adds a simple table printer for CLI output.
src/windows/wslc/CMakeLists.txt Adds new command/service/model sources and headers to the build.
localization/strings/en-US/Resources.resw Updates MessageWslcUsage (but currently mismatched with new command layout).
CMakeLists.txt Modifies Visual Studio discovery behavior via vswhere.

Comment on lines +7 to +8
#define CMD_ARG_REQUIRED(arg, msg) if (arg.empty()) { wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }
#define CMD_ARG_ARRAY_REQUIRED(argArray, msg) if (argArray.empty()) { wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

CMD_ARG_REQUIRED/CMD_ARG_ARRAY_REQUIRED depend on a wslutil namespace alias being defined in every .cpp that uses them, which is brittle and easy to break. Prefer referencing wsl::windows::common::wslutil::PrintMessage directly in the macros (or move these helpers into a .cpp).

Suggested change
#define CMD_ARG_REQUIRED(arg, msg) if (arg.empty()) { wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }
#define CMD_ARG_ARRAY_REQUIRED(argArray, msg) if (argArray.empty()) { wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }
#define CMD_ARG_REQUIRED(arg, msg) if (arg.empty()) { wsl::windows::common::wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }
#define CMD_ARG_ARRAY_REQUIRED(argArray, msg) if (argArray.empty()) { wsl::windows::common::wslutil::PrintMessage(msg, stderr); PrintHelp(); return E_INVALIDARG; }

Copilot uses AI. Check for mistakes.
Comment on lines +208 to +212
private:
bool m_all;
std::string m_format;
bool m_quiet;
};
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

m_all/m_quiet are not initialized; if the flags are omitted, the values can be indeterminate. Default-initialize them to false (e.g., bool m_all{}; bool m_quiet{};).

Copilot uses AI. Check for mistakes.
wsl::windows::common::security::ConfigureForCOMImpersonation(sessionManager.get());

wil::unique_cotaskmem_array_ptr<WSLA_SESSION_INFORMATION> sessions;
(sessionManager->ListSessions(&sessions, sessions.size_address<ULONG>()));
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

ListSessions's HRESULT is ignored here. This should be THROW_IF_FAILED(...) (or otherwise handled), otherwise failures will be silently ignored and sessions may be in an unexpected state.

Suggested change
(sessionManager->ListSessions(&sessions, sessions.size_address<ULONG>()));
THROW_IF_FAILED(sessionManager->ListSessions(&sessions, sessions.size_address<ULONG>()));

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +110
CMD_IF_HELP_PRINT_HELP();
auto containersToKill = Arguments();
auto session = m_sessionService.CreateSession();
wslc::services::ContainerService containerService;
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

If --all is not set and no container IDs are provided, this command becomes a no-op and returns success. Please validate that at least one ID is provided when m_all is false and return a non-zero error code otherwise.

Copilot uses AI. Check for mistakes.

protected:
virtual int ExecuteInternal(std::wstring_view commandLine, int parserOffset = 0) = 0;
bool m_help;
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

m_help is not initialized. Default-initialize it (e.g., bool m_help{};) so CMD_IF_HELP_PRINT_HELP() cannot read an indeterminate value if parsing fails or is bypassed.

Suggested change
bool m_help;
bool m_help{};

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +126
wslc::services::SessionService sessionService;
auto session = sessionService.CreateSession();

wslc::services::ImageService imageService;
Callback callback;
imageService.Pull(session, Image, &callback);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

PullImpl creates a new session (sessionService.CreateSession()) instead of using the Session parameter that callers pass in. This breaks the expectation that pulls happen within the caller-provided session; please use the passed-in session (or remove the parameter and update call sites).

Suggested change
wslc::services::SessionService sessionService;
auto session = sessionService.CreateSession();
wslc::services::ImageService imageService;
Callback callback;
imageService.Pull(session, Image, &callback);
wslc::services::ImageService imageService;
Callback callback;
imageService.Pull(Session, Image, &callback);

Copilot uses AI. Check for mistakes.
SessionInformation info;
info.CreatorPid = current.CreatorPid;
info.SessionId = current.SessionId;
info.DisplayName = current.DisplayName;
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

current.DisplayName can be null (the previous implementation explicitly handled null). Assigning a null wchar_t* into std::wstring is undefined behavior. Please guard against null and use an empty string when it is not provided.

Suggested change
info.DisplayName = current.DisplayName;
info.DisplayName = current.DisplayName ? current.DisplayName : L"";

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +15
options.MemoryMb = 2048;
options.BootTimeoutMs = 30 * 1000;
options.StoragePath = dataFolder.c_str();
options.MaximumStorageSizeMb = 10000; // 10GB.
options.NetworkingMode = WSLANetworkingModeNAT;
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

options.StoragePath is set from dataFolder.c_str(), but dataFolder is a local variable and its storage is freed when Default() returns, leaving a dangling pointer in the returned settings. The settings object needs to own the backing string (e.g., keep a std::wstring buffer inside SessionOptions).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants