Skip to content

vscode-container-client: support the wslc 2.9.8+ JSON output formats - #604

Merged
Brandon Waterloo [MSFT] (bwateratmsft) merged 3 commits into
mainfrom
agents/fix-bug-602-wslc-versions
Sep 2, 2026
Merged

vscode-container-client: support the wslc 2.9.8+ JSON output formats#604
Brandon Waterloo [MSFT] (bwateratmsft) merged 3 commits into
mainfrom
agents/fix-bug-602-wslc-versions

Conversation

@bwateratmsft

@bwateratmsft Brandon Waterloo [MSFT] (bwateratmsft) commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

🤖

Summary

Fixes #602. When wslc is the configured runtime, the Images view failed with a Zod validation error (Id expected, Created expected) and reported "failed to connect".

wslc changed its --format json output twice. I checked every 2.9.x tag rather than just the endpoints, because the framing and the record shapes changed at different times:

Version Change
2.9.5 All list verbs: one pretty-printed JSON array → newline-delimited compact objects. Records unchanged.
2.9.8 images and network list records: native → Docker's all-string shape. volume/network prune: Deleted: <name> → header + bare names. Volume inspect gains Scope. network list/volume list gain --filter.
2.9.9 volume list record: native → Docker's all-string shape.

Two consequences worth noting: the legacy record band is 2.9.7 and earlier (not 2.9.4), and 2.9.5–2.9.7 pair the new framing with the old records — so neither framing nor record shape alone identifies a generation. list (containers) has kept its native record throughout, including in 2.9.9.

The schemas only knew the oldest shapes, so every record failed validation on 2.9.8+.

What changed

Rather than switching formats outright — which would break users on 2.9.3–2.9.7 — the schemas now accept both record generations via Zod unions, so a single build works against any release from 2.9.0 to 2.9.9.

  • WslcListImageRecord.ts — union of the 2.9.8+ Docker shape and the legacy shape, both normalized onto SharedListImageRecord. Added a <none> sentinel filter so untagged images stay unnamed rather than becoming <none>:<none>.
  • WslcListNetworkRecord.ts (new) — same treatment for network list.
  • WslcClient.ts — added --no-trunc to images, and broadened WslcPruneDeletedRegex to accept Docker's Deleted Volumes: / Deleted Networks: header form alongside the old Deleted: <name> lines. The class doc now carries the version table above.

The two image shapes are disjoint (ID/CreatedAt vs Id/Created), so a record belonging to neither generation is still rejected rather than silently parsing as an empty image — this keeps the existing "skips a malformed record in non-strict mode" behavior intact.

list (containers) and volume list needed no code change: the former is unchanged, and the latter already parsed through the existing tolerant shared schema. Regression tests lock both in, along with the 2.9.5–2.9.7 middle band.

Why --no-trunc

Without it, 2.9.9 returns a 12-character id with the sha256: prefix stripped:

$ wslc images --format json
{... "ID":"d529dd0c6e55" ...}

$ wslc images --no-trunc --format json
{... "ID":"sha256:d529dd0c6e5597ac7e4a3e2dea65c3fcc6173f4cae713c409265c1dd9914a11b" ...}

That would have silently corrupted image identity even after the schema fix. images has accepted --no-trunc since 2.9.0, so passing it unconditionally is safe on every release. Note network list has no --no-trunc before 2.9.8, so network ids remain truncated to 12 chars.

Verification

Verified end-to-end against both real binaries — 2.9.4 locally, then updated to the 2.9.9 pre-release (the version from the bug report) and re-verified. All list, inspect, and prune paths parse correctly on both: images, containers, networks, volumes, all four inspect types, client-side label filtering, and both prune verbs. Intermediate versions were verified from the wslc sources at each tag.

Testing against the real 2.9.9 binary corrected two details my initial fixtures had wrong, and the verbatim strings are now in the tests:

  • Network timestamps carry sub-second precision (2026-09-01 17:44:01.0498728 +0000 UTC).
  • Total reclaimed space: 0B has no space before the unit (2.9.8 switched FormatBytesFormatHumanReadableSize). This matters because the prune regex must not mistake that line for a deleted resource — there's now a "nothing deleted" case using the real no-op output.

Full workspace build, lint (--max-warnings 0), and 571 unit tests pass.

⚠️ The --filter canaries now fail on wslc 2.9.8+ — by design

WslcCanary.test.ts is unchanged by this PR, and running it against 2.9.9 produces two intentional failures:

list `--filter` support
  1) `wslc network list` still lacks --filter
  2) `wslc volume list` still lacks --filter

AssertionError: wslc network list now supports --filter;
push filtering server-side in WslcClient instead of matchesLabelFilters.

This is the canary doing its job: wslc 2.9.8 added --filter to network list / volume list, and the canary is telling us the client-side matchesLabelFilters workaround is now removable.

This PR deliberately does not act on that signal, because adopting --filter would break wslc 2.9.3–2.9.7, which reject unknown arguments outright. Doing it properly needs runtime version detection that the client doesn't have today — a larger change than this bug fix should carry. Flagging it for a follow-up decision on whether to add version detection or simply drop support for pre-2.9.8 wslc.

The other six canaries still pass, confirming events, info, container restart, --expose, --add-host, and --platform remain absent even in 2.9.9.

Also noted for future work: 2.9.9 added --mount and --ip to run. The existing --volume workaround was left alone as out of scope here.

Per repo policy, CHANGELOG.md and NOTICE.html were left untouched.

wslc 2.9.8 replaced the service's native `--format json` records with
Docker-compatible, all-string ones. `images` went from `Id` /
epoch-seconds `Created` / byte-count `Size` to `ID` / `CreatedAt` date
string / human-readable `Size`, and `network list` went from the
inspect-style shape to Docker's flat `network ls` shape. The schemas only
knew the old shapes, so every record failed Zod validation and the Images
view reported a connection failure.

Accept both wslc generations via unions rather than switching formats
outright, so the extension keeps working against 2.9.3/2.9.4 as well. The
two shapes are disjoint (`ID`/`CreatedAt` vs `Id`/`Created`), so records
belonging to neither are still rejected instead of silently parsing as
empty.

Also pass `--no-trunc` to `images`, since 2.9.8+ otherwise truncates the
id to 12 characters and strips the `sha256:` prefix, and broaden the
prune regex to accept Docker's `Deleted Volumes:`/`Deleted Networks:`
header form alongside the old `Deleted: <name>` lines.

Verified end-to-end against real wslc 2.9.4 and 2.9.9 binaries.

Fixes #602

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2d8021a7-70c7-4846-ba6e-b692dafd4eda
These canaries exist precisely to fail when wslc gains a capability the
client works around, so removing them because wslc 2.9.8+ added
`--filter` defeats their purpose. Restore them unchanged; the failure is
the signal working as intended.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2d8021a7-70c7-4846-ba6e-b692dafd4eda

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 new WslcListNetworkRecord.ts schema uses z.extend(...), which is likely not a valid Zod API and would break compilation.

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

Pull request overview

This PR updates the vscode-container-client WSLC runtime adapter to tolerate WSLC 2.9.8+ changes to --format json output (Docker-shaped records and newline-delimited JSON), while remaining compatible with older WSLC releases by accepting both generations of list record shapes via Zod unions.

Changes:

  • Extend WSLC list parsing to accept both legacy and Docker-shaped outputs for images and networks (including NDJSON output).
  • Add --no-trunc to wslc images to prevent truncated image IDs in newer WSLC versions.
  • Broaden WSLC prune parsing to accept both legacy Deleted: <name> lines and Docker-style Deleted <Resource>: header output; add regression tests for both.
File summaries
File Description
packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts Adds regression coverage for NDJSON output and Docker-shaped records for images/networks/volumes, and new prune output formats.
packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts Removes --filter canaries and replaces with a note explaining back-compat constraints.
packages/vscode-container-client/src/clients/WslcClient/WslcListNetworkRecord.ts Introduces a union schema to parse both legacy and Docker-shaped network list records and normalize to ListNetworkItem.
packages/vscode-container-client/src/clients/WslcClient/WslcListImageRecord.ts Updates image list schema to accept both WSLC generations, normalize to the shared shape, and treat <none> sentinels as missing data.
packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts Adds --no-trunc for image listing, updates list parsing comments, switches networks to the new list-record schema, and expands prune regex handling.
packages/vscode-container-client/src/clients/DockerClientBase/SharedListImageRecord.ts Updates docs to reflect that WSLC now has two generations mapped onto the shared image list schema.
packages/vscode-container-client/src/clients/DockerClientBase/SharedInspectNetworkRecord.ts Updates docs to reflect WSLC’s version-dependent network list output shape and the new fallback path.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Diffing 2.9.4 against 2.9.8 hid two intermediate releases' worth of
detail. Checking every 2.9.x tag shows the framing and the record shapes
changed at different times:

- 2.9.5 switched all list verbs from a pretty-printed JSON array to
  newline-delimited objects, leaving the records untouched.
- 2.9.8 replaced the `images` and `network list` records, moved
  volume/network prune to the header form, and added volume inspect
  `Scope`.
- 2.9.9 replaced the `volume list` record.

So the legacy record band is 2.9.7 and earlier, not 2.9.4, and 2.9.5
through 2.9.7 pair the new framing with the old records. Behavior is
unaffected -- the unions and `parseInspectJson` already accepted every
combination -- but the comments claimed otherwise. Adds a version table
to the client doc and a test for the previously uncovered middle band.

Also verified `images --no-trunc` has existed since 2.9.0, so passing it
unconditionally is safe on every release.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2d8021a7-70c7-4846-ba6e-b692dafd4eda
@bwateratmsft
Brandon Waterloo [MSFT] (bwateratmsft) merged commit 6dfbe16 into main Sep 2, 2026
2 checks passed
@bwateratmsft
Brandon Waterloo [MSFT] (bwateratmsft) deleted the agents/fix-bug-602-wslc-versions branch September 2, 2026 18:15
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.

WSLC: Images section showing failed to connect

3 participants