docker2wslc 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docker2wslc
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Translate Docker commands and Compose files to wslc, the native WSL container runtime
5
5
  Project-URL: Homepage, https://wslcontainers.com
6
6
  Project-URL: Documentation, https://wslcontainers.com/reference/cheatsheet/
@@ -46,13 +46,13 @@ pip install 'docker2wslc[yaml]' # + Compose analysis
46
46
 
47
47
  ```console
48
48
  $ docker2wslc convert docker run --gpus all --restart always -p 8080:80 nginx
49
- wslc run --device nvidia.com/gpu=all -p 8080:80 nginx
49
+ wslc run --gpus all -p 8080:80 nginx
50
50
 
51
51
  Migration notes
52
52
  WARN Restart policies are not implemented in the wslc preview. Flag dropped — use a
53
53
  Windows scheduled task or a wrapper script for auto-restart.
54
- INFO GPU access in wslc goes through the Container Device Interface. Use
55
- `--device nvidia.com/gpu=all` instead of `--gpus`.
54
+ INFO `--gpus` is native in wslc 2.9.4, but the host must actually have the GPU: on a
55
+ machine without one, `--gpus all` fails at container init with an ldconfig error.
56
56
  ```
57
57
 
58
58
  Commands come from arguments, a file, or stdin:
@@ -74,15 +74,18 @@ $ docker2wslc compose docker-compose.yml
74
74
 
75
75
  wslc volume create pgdata
76
76
  wslc network create backend
77
+ # start order matters: web -> db
77
78
 
78
79
  # service: web
79
80
  wslc run -d --name web -e NGINX_HOST=localhost -p 8080:80 --network backend nginx:alpine
81
+ ! networks: Bridge-only. Create with wslc network create before running.
80
82
  x depends_on: No dependency ordering. Start services in order yourself and add readiness waits.
81
83
  x restart: No restart policies in the wslc preview.
82
84
 
83
85
  # service: db
84
- wslc run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16-alpine
85
- x healthcheck: wslc has no healthcheck support; depends_on conditions relying on it cannot work.
86
+ wslc run -d --name db -v pgdata:/var/lib/postgresql/data --network backend --health-cmd 'pg_isready -U postgres' --health-interval 10s --health-retries 5 postgres:16-alpine
87
+ ! volumes: Named volumes must be created first with wslc volume create. Windows paths go over VirtioFS.
88
+ ! networks: Bridge-only. Create with wslc network create before running.
86
89
  ```
87
90
 
88
91
  ## Lint a repository
@@ -132,10 +135,10 @@ Worth knowing before you migrate. These are runtime limitations, not gaps in thi
132
135
  - **No Compose runtime** — translate services by hand, see the [migration guide](https://wslcontainers.com/guides/compose/)
133
136
  - **No restart policies** — use a scheduled task
134
137
  - **No `--platform`** — host architecture only
135
- - **No healthchecks** — so `depends_on` conditions cannot work
138
+ - **No `depends_on` gating** — health flags work (`--health-cmd` et al), but nothing waits on health state for you
136
139
  - **No Docker socket or Engine API** — [Testcontainers, Portainer and act cannot attach](https://wslcontainers.com/guides/testcontainers/)
137
140
  - **No buildx / bake** — single-platform `wslc build` only
138
- - **GPU via CDI** — `--device nvidia.com/gpu=all`, not `--gpus all`
141
+ - **GPU** — `--gpus all`, the same flag as Docker. It is `--device` that wslc lacks.
139
142
 
140
143
  CLI-driven tooling ports to wslc. API-driven tooling does not. That single distinction
141
144
  explains most migration surprises — including why
@@ -15,13 +15,13 @@ pip install 'docker2wslc[yaml]' # + Compose analysis
15
15
 
16
16
  ```console
17
17
  $ docker2wslc convert docker run --gpus all --restart always -p 8080:80 nginx
18
- wslc run --device nvidia.com/gpu=all -p 8080:80 nginx
18
+ wslc run --gpus all -p 8080:80 nginx
19
19
 
20
20
  Migration notes
21
21
  WARN Restart policies are not implemented in the wslc preview. Flag dropped — use a
22
22
  Windows scheduled task or a wrapper script for auto-restart.
23
- INFO GPU access in wslc goes through the Container Device Interface. Use
24
- `--device nvidia.com/gpu=all` instead of `--gpus`.
23
+ INFO `--gpus` is native in wslc 2.9.4, but the host must actually have the GPU: on a
24
+ machine without one, `--gpus all` fails at container init with an ldconfig error.
25
25
  ```
26
26
 
27
27
  Commands come from arguments, a file, or stdin:
@@ -43,15 +43,18 @@ $ docker2wslc compose docker-compose.yml
43
43
 
44
44
  wslc volume create pgdata
45
45
  wslc network create backend
46
+ # start order matters: web -> db
46
47
 
47
48
  # service: web
48
49
  wslc run -d --name web -e NGINX_HOST=localhost -p 8080:80 --network backend nginx:alpine
50
+ ! networks: Bridge-only. Create with wslc network create before running.
49
51
  x depends_on: No dependency ordering. Start services in order yourself and add readiness waits.
50
52
  x restart: No restart policies in the wslc preview.
51
53
 
52
54
  # service: db
53
- wslc run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16-alpine
54
- x healthcheck: wslc has no healthcheck support; depends_on conditions relying on it cannot work.
55
+ wslc run -d --name db -v pgdata:/var/lib/postgresql/data --network backend --health-cmd 'pg_isready -U postgres' --health-interval 10s --health-retries 5 postgres:16-alpine
56
+ ! volumes: Named volumes must be created first with wslc volume create. Windows paths go over VirtioFS.
57
+ ! networks: Bridge-only. Create with wslc network create before running.
55
58
  ```
56
59
 
57
60
  ## Lint a repository
@@ -101,10 +104,10 @@ Worth knowing before you migrate. These are runtime limitations, not gaps in thi
101
104
  - **No Compose runtime** — translate services by hand, see the [migration guide](https://wslcontainers.com/guides/compose/)
102
105
  - **No restart policies** — use a scheduled task
103
106
  - **No `--platform`** — host architecture only
104
- - **No healthchecks** — so `depends_on` conditions cannot work
107
+ - **No `depends_on` gating** — health flags work (`--health-cmd` et al), but nothing waits on health state for you
105
108
  - **No Docker socket or Engine API** — [Testcontainers, Portainer and act cannot attach](https://wslcontainers.com/guides/testcontainers/)
106
109
  - **No buildx / bake** — single-platform `wslc build` only
107
- - **GPU via CDI** — `--device nvidia.com/gpu=all`, not `--gpus all`
110
+ - **GPU** — `--gpus all`, the same flag as Docker. It is `--device` that wslc lacks.
108
111
 
109
112
  CLI-driven tooling ports to wslc. API-driven tooling does not. That single distinction
110
113
  explains most migration surprises — including why
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "docker2wslc"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "Translate Docker commands and Compose files to wslc, the native WSL container runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -4,7 +4,7 @@ wslc is the native Linux container runtime in the Windows Subsystem for Linux.
4
4
  Docs and an interactive converter: https://wslcontainers.com
5
5
  """
6
6
 
7
- __version__ = "0.1.0"
7
+ __version__ = "0.2.0"
8
8
 
9
9
  from .compose import ComposeReport, analyse
10
10
  from .translate import Note, Result, load_rules, translate, translate_line
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import re
5
6
  from dataclasses import dataclass, field
6
7
  from typing import Any
7
8
 
@@ -65,11 +66,62 @@ def _as_list(value: Any) -> list[str]:
65
66
  return [str(value)]
66
67
 
67
68
 
69
+ def _upper_size(value: Any) -> str:
70
+ """wslc rejects lowercase size units: 512m -> Invalid memory argument value."""
71
+ return re.sub(
72
+ r"^(\d+(?:\.\d+)?)\s*([kmgtKMGT])(b?|B?)$",
73
+ lambda m: m.group(1) + m.group(2).upper() + m.group(3).upper(),
74
+ str(value),
75
+ )
76
+
77
+
78
+ _UNIT_SECONDS = {"h": 3600, "m": 60, "s": 1, "ms": 0.001, "us": 0.000001}
79
+
80
+
81
+ def _stop_seconds(value: Any) -> str:
82
+ """--stop-timeout takes plain seconds; stop_grace_period is a Go duration.
83
+
84
+ Compose allows compound forms like `1m30s`, so a single-unit regex is not
85
+ enough -- `1m30s` must become 90, not pass through unchanged.
86
+ """
87
+ raw = str(value).strip()
88
+ if re.fullmatch(r"\d+", raw):
89
+ return raw
90
+ parts = re.findall(r"(\d+(?:\.\d+)?)(ms|us|h|m|s)", raw)
91
+ if not parts or "".join(n + u for n, u in parts) != raw:
92
+ return raw
93
+ total = sum(float(n) * _UNIT_SECONDS[u] for n, u in parts)
94
+ return str(round(total))
95
+
96
+
97
+ def _shell_quote(value: Any) -> str:
98
+ """Args are joined into one shell line, so whitespace must be quoted."""
99
+ s = str(value)
100
+ if s == "":
101
+ return "''"
102
+ if not re.search(r"""[\s"'$`\\|&;<>()*?!#~\[\]{}]""", s):
103
+ return s
104
+ return "'" + s.replace("'", "'\\''") + "'"
105
+
106
+
107
+ def _health_cmd(test: Any) -> str:
108
+ """Compose test: is a string, or a list led by CMD / CMD-SHELL / NONE."""
109
+ if not isinstance(test, list):
110
+ return str(test)
111
+ parts = [str(p) for p in test]
112
+ head = (parts[0] if parts else "").upper()
113
+ if head in ("CMD-SHELL", "CMD"):
114
+ return " ".join(parts[1:])
115
+ if head == "NONE":
116
+ return ""
117
+ return " ".join(parts)
118
+
119
+
68
120
  def _build_run(name: str, svc: dict[str, Any]) -> str:
69
121
  args: list[str] = ["wslc", "run", "-d", "--name", svc.get("container_name") or name]
70
122
 
71
123
  for env in _as_list(svc.get("environment")):
72
- args += ["-e", env]
124
+ args += ["-e", _shell_quote(env)]
73
125
  for env_file in _as_list(svc.get("env_file")):
74
126
  args += ["--env-file", env_file]
75
127
  for port in _as_list(svc.get("ports")):
@@ -78,14 +130,17 @@ def _build_run(name: str, svc: dict[str, Any]) -> str:
78
130
  args += ["-v", vol]
79
131
  for net in _as_list(svc.get("networks")):
80
132
  args += ["--network", net]
81
- for cap in _as_list(svc.get("cap_add")):
82
- args += ["--cap-add", cap]
83
- for dev in _as_list(svc.get("devices")):
84
- args += ["--device", dev]
133
+ # cap_add / cap_drop / devices / privileged / security_opt / expose are
134
+ # deliberately NOT emitted: wslc 2.9.4 has no such flags, so emitting them
135
+ # yields "Argument name was not recognized". They surface as findings.
85
136
  for label in _as_list(svc.get("labels")):
86
- args += ["--label", label]
137
+ args += ["--label", _shell_quote(label)]
87
138
  for tmp in _as_list(svc.get("tmpfs")):
88
139
  args += ["--tmpfs", tmp]
140
+ for dns in _as_list(svc.get("dns")):
141
+ args += ["--dns", str(dns)]
142
+ for ulimit in _as_list(svc.get("ulimits")):
143
+ args += ["--ulimit", _shell_quote(ulimit)]
89
144
 
90
145
  if svc.get("working_dir"):
91
146
  args += ["-w", str(svc["working_dir"])]
@@ -93,9 +148,37 @@ def _build_run(name: str, svc: dict[str, Any]) -> str:
93
148
  args += ["-u", str(svc["user"])]
94
149
  if svc.get("hostname"):
95
150
  args += ["--hostname", str(svc["hostname"])]
151
+ if svc.get("domainname"):
152
+ args += ["--domainname", str(svc["domainname"])]
153
+ if svc.get("shm_size"):
154
+ args += ["--shm-size", _upper_size(svc["shm_size"])]
155
+ if svc.get("mem_limit"):
156
+ args += ["-m", _upper_size(svc["mem_limit"])]
157
+ if svc.get("cpus"):
158
+ args += ["--cpus", str(svc["cpus"])]
159
+ if svc.get("stop_signal"):
160
+ args += ["--stop-signal", str(svc["stop_signal"])]
161
+ if svc.get("stop_grace_period"):
162
+ args += ["--stop-timeout", _stop_seconds(svc["stop_grace_period"])]
163
+ # healthcheck maps flag-for-flag onto wslc run --health-* (verified 2.9.4.0).
164
+ hc = svc.get("healthcheck")
165
+ if isinstance(hc, dict):
166
+ if hc.get("disable") in (True, "true"):
167
+ args.append("--no-healthcheck")
168
+ else:
169
+ if hc.get("test"):
170
+ args += ["--health-cmd", _shell_quote(_health_cmd(hc["test"]))]
171
+ if hc.get("interval"):
172
+ args += ["--health-interval", str(hc["interval"])]
173
+ if hc.get("retries"):
174
+ args += ["--health-retries", str(hc["retries"])]
175
+ if hc.get("timeout"):
176
+ args += ["--health-timeout", str(hc["timeout"])]
177
+ if hc.get("start_period"):
178
+ args += ["--health-start-period", str(hc["start_period"])]
96
179
  if svc.get("entrypoint"):
97
180
  ep = svc["entrypoint"]
98
- args += ["--entrypoint", ep if isinstance(ep, str) else " ".join(ep)]
181
+ args += ["--entrypoint", _shell_quote(ep if isinstance(ep, str) else " ".join(ep))]
99
182
  if svc.get("stdin_open"):
100
183
  args.append("-i")
101
184
  if svc.get("tty"):
@@ -0,0 +1,572 @@
1
+ {
2
+ "$comment": "Single source of truth for Docker -> wslc translation. Consumed by the Python package, the npm CLI, the MCP server and the VS Code extension. Do not fork this logic per language. Every claim here is verified against a real wslc on a windows-2025 runner; see `verification`.",
3
+ "schemaVersion": 2,
4
+ "wslcPreview": "2.9.4.0",
5
+ "identical": [
6
+ "run",
7
+ "build",
8
+ "pull",
9
+ "push",
10
+ "stop",
11
+ "start",
12
+ "exec",
13
+ "logs",
14
+ "inspect",
15
+ "stats",
16
+ "tag",
17
+ "login",
18
+ "logout",
19
+ "kill",
20
+ "save",
21
+ "load",
22
+ "attach",
23
+ "version"
24
+ ],
25
+ "renamed": {
26
+ "ps": "container list",
27
+ "images": "image list",
28
+ "rmi": "image remove",
29
+ "rm": "container remove",
30
+ "create": "container create",
31
+ "cp": "container cp"
32
+ },
33
+ "renamedFlags": {
34
+ "ps": {
35
+ "-a": "--all",
36
+ "--all": "--all",
37
+ "-q": "--quiet",
38
+ "--quiet": "--quiet"
39
+ },
40
+ "images": {
41
+ "-a": "--all",
42
+ "--all": "--all"
43
+ },
44
+ "rm": {
45
+ "-f": "--force",
46
+ "--force": "--force"
47
+ },
48
+ "rmi": {
49
+ "-f": "--force",
50
+ "--force": "--force"
51
+ }
52
+ },
53
+ "unsupported": {
54
+ "swarm": "Swarm orchestration has no wslc equivalent. Use Kubernetes or keep Docker for this workload.",
55
+ "service": "Swarm services are not supported by wslc.",
56
+ "stack": "Swarm stacks are not supported by wslc.",
57
+ "node": "Swarm node management is not supported by wslc.",
58
+ "secret": "Swarm secrets are not supported. Pass values with -e or mount a file.",
59
+ "config": "Swarm configs are not supported by wslc.",
60
+ "plugin": "Docker plugins are not supported by wslc.",
61
+ "context": "wslc has a single local runtime, so there are no contexts to switch.",
62
+ "buildx": "buildx / bake is not available. Use wslc build for single-platform images.",
63
+ "manifest": "Manifest lists cannot be created with wslc in the preview.",
64
+ "trust": "Docker Content Trust is Docker-specific and has no wslc equivalent.",
65
+ "checkpoint": "Checkpoint/restore is not implemented in wslc.",
66
+ "restart": "No restart command in wslc 2.9.4. Run `wslc stop <id>` then `wslc start <id>`.",
67
+ "pause": "Pause/unpause (SIGSTOP freezing) is not implemented in wslc 2.9.4.",
68
+ "unpause": "Pause/unpause is not implemented in wslc 2.9.4.",
69
+ "info": "No `system info`. `wslc system` only exposes `session`. Use `wslc version` for build info.",
70
+ "top": "No `top`. Use `wslc exec <id> ps aux` inside the container.",
71
+ "wait": "No `wait`. Poll `wslc container list` or run the container in the foreground without --detach.",
72
+ "port": "No `port` command. Published ports are shown in the PORTS column of `wslc container list`.",
73
+ "rename": "Containers cannot be renamed in wslc 2.9.4. Recreate with the desired --name.",
74
+ "diff": "No filesystem diff. `wslc export <id>` writes the container filesystem to a tar for inspection.",
75
+ "commit": "No commit. Use `wslc export` then `wslc import`, or build from a Dockerfile.",
76
+ "history": "wslc 2.9.4 has no image history. `wslc image inspect` shows config but not per-layer history.",
77
+ "search": "wslc 2.9.4 cannot search a registry. Browse Docker Hub / the registry web UI instead."
78
+ },
79
+ "flags": {
80
+ "--platform": {
81
+ "action": "drop",
82
+ "takesValue": true,
83
+ "severity": "warn",
84
+ "note": "`--platform` is dropped: wslc builds and runs for the host architecture only in the preview."
85
+ },
86
+ "--restart": {
87
+ "action": "drop",
88
+ "takesValue": true,
89
+ "severity": "warn",
90
+ "note": "Restart policies are not implemented in the wslc preview. Flag dropped — use a Windows scheduled task or a wrapper script for auto-restart."
91
+ },
92
+ "--gpus": {
93
+ "action": "keep",
94
+ "takesValue": true,
95
+ "severity": "info",
96
+ "note": "`--gpus` is native in wslc 2.9.4 (`--gpus all`). Do NOT rewrite it to `--device`: wslc has no --device flag. On a host without an NVIDIA GPU the run fails at container init with an ldconfig error.",
97
+ "noteAlways": "`--gpus` is native in wslc 2.9.4, but the host must actually have the GPU: on a machine without one, `--gpus all` fails at container init with an ldconfig error."
98
+ },
99
+ "--network": {
100
+ "action": "conditional",
101
+ "takesValue": true,
102
+ "whenValue": {
103
+ "host": {
104
+ "action": "error",
105
+ "severity": "error",
106
+ "note": "wslc rejects host networking outright: `host mode networking is not supported` (exit 1). It is not implicit and cannot be dropped silently. `--network none` works."
107
+ }
108
+ },
109
+ "severity": "info",
110
+ "note": "Custom networks are supported: create with `wslc network create`, then `wslc network connect`. `none` is valid; `host` is rejected."
111
+ },
112
+ "--volume": {
113
+ "action": "keep",
114
+ "takesValue": true,
115
+ "aliases": [
116
+ "-v",
117
+ "--mount"
118
+ ],
119
+ "severity": "info",
120
+ "noteWhenWindowsPath": "Windows host paths are shared over VirtioFS. Use forward slashes (`C:/work:/app`) and expect Linux-style permissions on the container side."
121
+ },
122
+ "--memory": {
123
+ "action": "keep",
124
+ "takesValue": true,
125
+ "severity": "info",
126
+ "note": "Supported (`-m`). Unit suffix must be UPPERCASE: `512M` works, `512m` is rejected with `Invalid memory argument value`. Plain byte counts also work. Expect a kernel warning that swap limits are unavailable.",
127
+ "requireValuePattern": "^[0-9]+([KMGT]|[KMGT]B)?$",
128
+ "noteWhenValueRejected": "wslc rejects lowercase size units: `--memory 512m` fails with `Invalid memory argument value`. Use an UPPERCASE suffix (512M, 1G) or a plain byte count.",
129
+ "aliases": [
130
+ "-m"
131
+ ],
132
+ "fixValueCase": "upperSizeSuffix",
133
+ "noteWhenValueFixed": "Rewrote the size to use an UPPERCASE unit suffix: wslc rejects lowercase units (`Invalid memory argument value`) while Docker accepts both."
134
+ },
135
+ "--shm-size": {
136
+ "action": "keep",
137
+ "takesValue": true,
138
+ "severity": "info",
139
+ "note": "Supported. Same uppercase-unit rule as --memory: `64M` works, `64m` is rejected.",
140
+ "requireValuePattern": "^[0-9]+([KMGT]|[KMGT]B)?$",
141
+ "noteWhenValueRejected": "wslc rejects lowercase size units: `--shm-size 64m` fails with `Invalid shm-size argument value`. Use an UPPERCASE suffix (64M, 1G).",
142
+ "fixValueCase": "upperSizeSuffix",
143
+ "noteWhenValueFixed": "Rewrote the size to use an UPPERCASE unit suffix: wslc rejects lowercase units (`Invalid shm-size argument value`) while Docker accepts both."
144
+ },
145
+ "--cpus": {
146
+ "action": "keep",
147
+ "takesValue": true,
148
+ "severity": "info",
149
+ "note": "Supported, accepts fractional values (0.5, 1, 2.5)."
150
+ },
151
+ "--ulimit": {
152
+ "action": "keep",
153
+ "takesValue": true,
154
+ "severity": "info",
155
+ "note": "Supported, e.g. `--ulimit nofile=1024:1024`."
156
+ },
157
+ "--stop-timeout": {
158
+ "action": "keep",
159
+ "takesValue": true,
160
+ "severity": "info",
161
+ "note": "Supported, seconds; -1 means no timeout."
162
+ },
163
+ "--health-cmd": {
164
+ "action": "keep",
165
+ "takesValue": true,
166
+ "severity": "info",
167
+ "note": "Supported. wslc has the full health-check family: --health-cmd, --health-interval, --health-retries, --health-start-period, --health-timeout, --no-healthcheck."
168
+ },
169
+ "--device": {
170
+ "action": "drop",
171
+ "takesValue": true,
172
+ "severity": "warn",
173
+ "note": "wslc 2.9.4 has no --device flag (`Argument name was not recognized`). For GPUs use --gpus."
174
+ },
175
+ "--publish": {
176
+ "action": "keep",
177
+ "takesValue": true,
178
+ "aliases": [
179
+ "-p"
180
+ ],
181
+ "severity": "info",
182
+ "note": "Supported (`-p`). `-P/--publish-all` publishes all exposed ports."
183
+ },
184
+ "--cap-add": {
185
+ "action": "drop",
186
+ "takesValue": true,
187
+ "severity": "warn",
188
+ "note": "wslc 2.9.4 has no --cap-add (`Argument name was not recognized`). There is no way to grant extra capabilities; --privileged and --security-opt are missing too."
189
+ },
190
+ "--cap-drop": {
191
+ "action": "drop",
192
+ "takesValue": true,
193
+ "severity": "warn",
194
+ "note": "wslc 2.9.4 has no --cap-drop (`Argument name was not recognized`)."
195
+ },
196
+ "--privileged": {
197
+ "action": "drop",
198
+ "takesValue": false,
199
+ "severity": "warn",
200
+ "note": "wslc 2.9.4 has no --privileged (`Argument name was not recognized`)."
201
+ },
202
+ "--security-opt": {
203
+ "action": "drop",
204
+ "takesValue": true,
205
+ "severity": "warn",
206
+ "note": "wslc 2.9.4 has no --security-opt (`Argument name was not recognized`)."
207
+ },
208
+ "--expose": {
209
+ "action": "drop",
210
+ "takesValue": true,
211
+ "severity": "warn",
212
+ "note": "wslc 2.9.4 has no --expose. Publish the port with -p, or use -P/--publish-all to publish every port the image exposes."
213
+ }
214
+ },
215
+ "compose": {
216
+ "supported": false,
217
+ "note": "wslc has no built-in Compose runtime. Translate each service into a wslc run call, or drive them from a PowerShell/bash script.",
218
+ "docsUrl": "https://wslcontainers.com/guides/compose/",
219
+ "keys": {
220
+ "image": {
221
+ "status": "ok",
222
+ "maps": "positional image argument"
223
+ },
224
+ "build": {
225
+ "status": "ok",
226
+ "maps": "wslc build -t <name>"
227
+ },
228
+ "command": {
229
+ "status": "ok",
230
+ "maps": "trailing command args"
231
+ },
232
+ "entrypoint": {
233
+ "status": "ok",
234
+ "maps": "--entrypoint"
235
+ },
236
+ "environment": {
237
+ "status": "ok",
238
+ "maps": "-e KEY=VALUE"
239
+ },
240
+ "env_file": {
241
+ "status": "ok",
242
+ "maps": "--env-file"
243
+ },
244
+ "ports": {
245
+ "status": "ok",
246
+ "maps": "-p HOST:CONTAINER"
247
+ },
248
+ "volumes": {
249
+ "status": "partial",
250
+ "maps": "-v",
251
+ "note": "Named volumes must be created first with wslc volume create. Windows paths go over VirtioFS."
252
+ },
253
+ "networks": {
254
+ "status": "partial",
255
+ "maps": "--network",
256
+ "note": "Bridge-only. Create with wslc network create before running."
257
+ },
258
+ "working_dir": {
259
+ "status": "ok",
260
+ "maps": "-w"
261
+ },
262
+ "user": {
263
+ "status": "ok",
264
+ "maps": "-u"
265
+ },
266
+ "hostname": {
267
+ "status": "ok",
268
+ "maps": "--hostname"
269
+ },
270
+ "container_name": {
271
+ "status": "ok",
272
+ "maps": "--name"
273
+ },
274
+ "labels": {
275
+ "status": "ok",
276
+ "maps": "--label"
277
+ },
278
+ "cap_add": {
279
+ "status": "missing",
280
+ "note": "wslc 2.9.4 has no --cap-add (`Argument name was not recognized`), and no --privileged or --security-opt either."
281
+ },
282
+ "devices": {
283
+ "status": "missing",
284
+ "note": "wslc 2.9.4 has no --device. GPUs go through --gpus; there is no generic device passthrough."
285
+ },
286
+ "tmpfs": {
287
+ "status": "ok",
288
+ "maps": "--tmpfs"
289
+ },
290
+ "stdin_open": {
291
+ "status": "ok",
292
+ "maps": "-i"
293
+ },
294
+ "tty": {
295
+ "status": "ok",
296
+ "maps": "-t"
297
+ },
298
+ "restart": {
299
+ "status": "missing",
300
+ "note": "No restart policies in the wslc preview."
301
+ },
302
+ "healthcheck": {
303
+ "status": "ok",
304
+ "maps": "--health-cmd / --health-interval / --health-retries / --health-timeout / --health-start-period",
305
+ "emit": "health",
306
+ "note": "wslc run implements all five health flags plus --no-healthcheck. Nothing reads the compose file, so the flags are emitted onto the run command for you. What is still missing is depends_on gating on health state."
307
+ },
308
+ "depends_on": {
309
+ "status": "missing",
310
+ "note": "No dependency ordering. Start services in order yourself and add readiness waits."
311
+ },
312
+ "deploy": {
313
+ "status": "missing",
314
+ "note": "Swarm-only section, ignored entirely."
315
+ },
316
+ "profiles": {
317
+ "status": "missing",
318
+ "note": "Compose-only concept."
319
+ },
320
+ "extends": {
321
+ "status": "missing",
322
+ "note": "Compose-only concept."
323
+ },
324
+ "configs": {
325
+ "status": "missing",
326
+ "note": "Swarm configs are unsupported; mount a file instead."
327
+ },
328
+ "secrets": {
329
+ "status": "missing",
330
+ "note": "Swarm secrets are unsupported; use -e or a mounted file."
331
+ },
332
+ "cap_drop": {
333
+ "status": "missing",
334
+ "note": "wslc 2.9.4 has no --cap-drop."
335
+ },
336
+ "expose": {
337
+ "status": "missing",
338
+ "note": "No --expose on wslc run. Publish with ports: (-p), or use -P to publish everything the image exposes."
339
+ },
340
+ "network_mode": {
341
+ "status": "missing",
342
+ "note": "network_mode: host is refused with `host mode networking is not supported`. Use a user-defined network plus published ports."
343
+ },
344
+ "privileged": {
345
+ "status": "missing",
346
+ "note": "No --privileged on wslc run."
347
+ },
348
+ "security_opt": {
349
+ "status": "missing",
350
+ "note": "No --security-opt on wslc run."
351
+ },
352
+ "shm_size": {
353
+ "status": "ok",
354
+ "maps": "--shm-size",
355
+ "note": "Unit suffix must be UPPERCASE (64M, not 64m)."
356
+ },
357
+ "mem_limit": {
358
+ "status": "ok",
359
+ "maps": "-m",
360
+ "note": "Unit suffix must be UPPERCASE (512M, not 512m)."
361
+ },
362
+ "dns": {
363
+ "status": "ok",
364
+ "maps": "--dns"
365
+ },
366
+ "ulimits": {
367
+ "status": "ok",
368
+ "maps": "--ulimit"
369
+ },
370
+ "domainname": {
371
+ "status": "ok",
372
+ "maps": "--domainname"
373
+ },
374
+ "stop_signal": {
375
+ "status": "ok",
376
+ "maps": "--stop-signal"
377
+ },
378
+ "stop_grace_period": {
379
+ "status": "ok",
380
+ "maps": "--stop-timeout",
381
+ "note": "Converted to whole seconds."
382
+ }
383
+ }
384
+ },
385
+ "devcontainer": {
386
+ "keys": {
387
+ "image": {
388
+ "status": "ok"
389
+ },
390
+ "build.dockerfile": {
391
+ "status": "ok"
392
+ },
393
+ "build.args": {
394
+ "status": "ok",
395
+ "maps": "--build-arg"
396
+ },
397
+ "build.platform": {
398
+ "status": "missing",
399
+ "note": "Host architecture only."
400
+ },
401
+ "workspaceMount": {
402
+ "status": "partial",
403
+ "note": "VirtioFS; use forward slashes for Windows paths."
404
+ },
405
+ "workspaceFolder": {
406
+ "status": "ok"
407
+ },
408
+ "containerEnv": {
409
+ "status": "ok",
410
+ "maps": "-e"
411
+ },
412
+ "remoteEnv": {
413
+ "status": "ok"
414
+ },
415
+ "forwardPorts": {
416
+ "status": "ok",
417
+ "maps": "-p"
418
+ },
419
+ "postCreateCommand": {
420
+ "status": "ok",
421
+ "maps": "wslc exec"
422
+ },
423
+ "postStartCommand": {
424
+ "status": "ok"
425
+ },
426
+ "postAttachCommand": {
427
+ "status": "ok"
428
+ },
429
+ "remoteUser": {
430
+ "status": "ok",
431
+ "maps": "-u"
432
+ },
433
+ "containerUser": {
434
+ "status": "ok"
435
+ },
436
+ "mounts": {
437
+ "status": "partial",
438
+ "note": "VirtioFS path rules apply."
439
+ },
440
+ "runArgs": {
441
+ "status": "partial",
442
+ "note": "Passed through verbatim; unsupported flags will fail at runtime."
443
+ },
444
+ "dockerComposeFile": {
445
+ "status": "missing",
446
+ "note": "No Compose runtime. Replace with a single image or build entry."
447
+ },
448
+ "features": {
449
+ "status": "missing",
450
+ "note": "Requires BuildKit metadata that wslc build does not emit."
451
+ },
452
+ "runServices": {
453
+ "status": "missing",
454
+ "note": "Compose-only key."
455
+ },
456
+ "shutdownAction": {
457
+ "status": "partial",
458
+ "note": "stopCompose is meaningless without Compose."
459
+ }
460
+ },
461
+ "requiredSetting": {
462
+ "key": "dev.containers.dockerPath",
463
+ "value": "wslc",
464
+ "note": "Point the Dev Containers extension at wslc. Prefer workspace scope over global."
465
+ }
466
+ },
467
+ "apiIncompatible": {
468
+ "note": "CLI-driven tooling ports to wslc. API-driven tooling cannot, because wslc is daemonless and exposes no Docker Engine API or socket.",
469
+ "tools": [
470
+ {
471
+ "name": "Testcontainers",
472
+ "via": "Engine API",
473
+ "works": false
474
+ },
475
+ {
476
+ "name": "Docker-in-Docker sidecars",
477
+ "via": "mounted socket",
478
+ "works": false
479
+ },
480
+ {
481
+ "name": "Portainer",
482
+ "via": "Engine API",
483
+ "works": false
484
+ },
485
+ {
486
+ "name": "Lazydocker",
487
+ "via": "Engine API",
488
+ "works": false
489
+ },
490
+ {
491
+ "name": "LocalStack (docker mode)",
492
+ "via": "Engine API",
493
+ "works": false
494
+ },
495
+ {
496
+ "name": "act",
497
+ "via": "Engine API",
498
+ "works": false
499
+ },
500
+ {
501
+ "name": "VS Code Dev Containers",
502
+ "via": "CLI binary",
503
+ "works": true
504
+ },
505
+ {
506
+ "name": "shell scripts calling docker",
507
+ "via": "CLI binary",
508
+ "works": true
509
+ }
510
+ ]
511
+ },
512
+ "links": {
513
+ "site": "https://wslcontainers.com",
514
+ "converter": "https://wslcontainers.com/",
515
+ "cheatsheet": "https://wslcontainers.com/reference/cheatsheet/",
516
+ "compose": "https://wslcontainers.com/guides/compose/",
517
+ "install": "https://wslcontainers.com/guides/install/",
518
+ "vsDocker": "https://wslcontainers.com/guides/vs-docker-desktop/",
519
+ "devcontainers": "https://wslcontainers.com/guides/vscode-dev-containers/",
520
+ "testcontainers": "https://wslcontainers.com/guides/testcontainers/"
521
+ },
522
+ "renamedOptional": {
523
+ "$comment": "wslc accepts BOTH the docker-style short command and the noun-verb form (verified: `wslc ps` and `wslc container list` both exit 0). These rewrites are cosmetic; converters should not treat the short form as an error.",
524
+ "commands": {
525
+ "ps": "container list",
526
+ "images": "image list",
527
+ "rmi": "image remove",
528
+ "rm": "container remove",
529
+ "create": "container create"
530
+ }
531
+ },
532
+ "verification": {
533
+ "wslcVersion": "2.9.4.0",
534
+ "verifiedAt": "2026-07-29",
535
+ "method": "GitHub Actions windows-2025 runner, real wslc invocations",
536
+ "runs": [
537
+ "30417819781",
538
+ "30417964880",
539
+ "30418758451"
540
+ ]
541
+ },
542
+ "twoWord": {
543
+ "system prune": {
544
+ "status": "unsupported",
545
+ "note": "`wslc system` only exposes `session` in 2.9.4 — there is no `system prune`. Run the per-noun prunes instead: `wslc container prune`, `wslc image prune`, `wslc volume prune`, `wslc network prune`."
546
+ },
547
+ "system info": {
548
+ "status": "unsupported",
549
+ "note": "No `system info` in wslc 2.9.4. Use `wslc version`."
550
+ },
551
+ "system df": {
552
+ "status": "unsupported",
553
+ "note": "No `system df` in wslc 2.9.4. Inspect per-noun listings instead."
554
+ },
555
+ "container prune": {
556
+ "status": "supported",
557
+ "note": "Removes all stopped containers."
558
+ },
559
+ "image prune": {
560
+ "status": "supported",
561
+ "note": "Removes dangling images; --all removes all unused images."
562
+ },
563
+ "volume prune": {
564
+ "status": "supported",
565
+ "note": "Removes unused anonymous volumes; --all includes named ones."
566
+ },
567
+ "network prune": {
568
+ "status": "supported",
569
+ "note": "Removes all unused networks."
570
+ }
571
+ }
572
+ }
@@ -45,7 +45,12 @@ class Result:
45
45
  """0 clean, 1 degraded (flags dropped/rewritten), 2 unmigratable."""
46
46
  if self.unsupported_hit or self.compose_hit:
47
47
  return 2
48
- if any(n.severity in ("warn", "error") for n in self.notes):
48
+ # severity=error means wslc refuses the command outright (e.g.
49
+ # `--network host` exits 1 with "host mode networking is not
50
+ # supported"), so the result is unmigratable, not merely degraded.
51
+ if any(n.severity == "error" for n in self.notes):
52
+ return 2
53
+ if any(n.severity == "warn" for n in self.notes):
49
54
  return 1
50
55
  return 0
51
56
 
@@ -83,6 +88,11 @@ def tokenize(line: str) -> list[str]:
83
88
  return out
84
89
 
85
90
 
91
+ # Verbs where wslc also accepts the docker-style top-level form, so rewriting to
92
+ # the noun form is cosmetic rather than required. Verified on wslc 2.9.4.
93
+ _ALIAS_OK = set(RULES.get("renamedOptional", {}).get("commands", {}))
94
+
95
+
86
96
  def _flag_spec(flag: str) -> tuple[str, dict[str, Any]] | tuple[None, None]:
87
97
  flags = RULES["flags"]
88
98
  if flag in flags:
@@ -120,6 +130,15 @@ def _translate_args(args: list[str], notes: list[Note]) -> list[str]:
120
130
  notes.append(Note(branch.get("severity", "info"), branch["note"]))
121
131
  i += consumed
122
132
  continue
133
+ if branch["action"] == "error":
134
+ # Value is passed through so the reader sees what they wrote,
135
+ # but flagged as an error: wslc rejects it outright.
136
+ notes.append(Note(branch.get("severity", "error"), branch["note"]))
137
+ out.append(f"{bare}={value}" if has_inline else bare)
138
+ if not has_inline and takes_value and value:
139
+ out.append(value)
140
+ i += consumed
141
+ continue
123
142
  notes.append(Note(spec.get("severity", "info"), spec["note"]))
124
143
  out.append(f"{bare}={value}" if has_inline else bare)
125
144
  if not has_inline and takes_value and value:
@@ -142,9 +161,30 @@ def _translate_args(args: list[str], notes: list[Note]) -> list[str]:
142
161
  note_win = spec.get("noteWhenWindowsPath")
143
162
  if note_win and (WINDOWS_PATH.match(value) or value.startswith("/mnt/")):
144
163
  notes.append(Note(spec.get("severity", "info"), note_win))
145
- out.append(arg)
146
- if not has_inline and takes_value and value:
147
- out.append(value)
164
+ # Some flags exist but reject certain value formats (verified: wslc wants
165
+ # uppercase size units, so `-m 512m` fails while `512M` works).
166
+ emit_value = value
167
+ fixed = False
168
+ if spec.get("fixValueCase") == "upperSizeSuffix" and value:
169
+ up = re.sub(
170
+ r"^(\d+(?:\.\d+)?)\s*([kmgtKMGT])(b?|B?)$",
171
+ lambda m: m.group(1) + m.group(2).upper() + m.group(3).upper(),
172
+ value,
173
+ )
174
+ if up != value:
175
+ emit_value, fixed = up, True
176
+ if fixed:
177
+ notes.append(Note("warn", spec["noteWhenValueFixed"]))
178
+ else:
179
+ require = spec.get("requireValuePattern")
180
+ if require and emit_value and not re.match(require, emit_value):
181
+ notes.append(Note("error", spec["noteWhenValueRejected"]))
182
+ note_always = spec.get("noteAlways")
183
+ if note_always:
184
+ notes.append(Note(spec.get("severity", "info"), note_always))
185
+ out.append(f"{bare}={emit_value}" if has_inline else arg)
186
+ if not has_inline and takes_value and emit_value:
187
+ out.append(emit_value)
148
188
  i += consumed
149
189
  return out
150
190
 
@@ -193,6 +233,20 @@ def translate_line(raw: str) -> Result | None:
193
233
  )
194
234
 
195
235
  two = f"{tokens[0]} {tokens[1]}" if len(tokens) > 1 else ""
236
+ # Two-word forms with a verified verdict of their own (e.g. `docker system
237
+ # prune` has no wslc equivalent, but the per-noun prunes do).
238
+ two_word = RULES.get("twoWord", {})
239
+ if two and two in two_word:
240
+ entry = two_word[two]
241
+ if entry["status"] == "unsupported":
242
+ notes.append(Note("error", entry["note"]))
243
+ return Result(
244
+ output=f"# {two}: not supported by wslc", notes=notes, unsupported_hit=True
245
+ )
246
+ notes.append(Note("info", entry["note"]))
247
+ rest = _translate_args(tokens[2:], notes)
248
+ return Result(output=" ".join(["wslc", two, *rest]).strip(), notes=notes)
249
+
196
250
  if two and two in (RULES["renamed"].values()):
197
251
  rest = _translate_args(tokens[2:], notes)
198
252
  return Result(output=" ".join(["wslc", two, *rest]).strip(), notes=notes)
@@ -216,7 +270,12 @@ def translate_line(raw: str) -> Result | None:
216
270
  Note(
217
271
  "info",
218
272
  f"`docker {verb}` is grouped under a noun in wslc: `wslc {mapped}`. "
219
- f"Recent previews accept `wslc {verb}` as an alias, but the noun form is stable.",
273
+ + (
274
+ f"`wslc {verb}` also works as a top-level alias (verified on 2.9.4), "
275
+ "so this rewrite is cosmetic."
276
+ if verb in _ALIAS_OK
277
+ else f"There is no top-level `wslc {verb}`; the noun form is required."
278
+ ),
220
279
  )
221
280
  )
222
281
  return Result(output=" ".join(["wslc", mapped, *rest]).strip(), notes=notes)
@@ -1,167 +0,0 @@
1
- {
2
- "$comment": "Single source of truth for Docker -> wslc translation. Consumed by the Python package, the npm CLI, the MCP server and the VS Code extension. Do not fork this logic per language.",
3
- "schemaVersion": 1,
4
- "wslcPreview": "2026-07",
5
- "identical": [
6
- "run", "build", "pull", "push", "stop", "start", "restart", "exec", "logs",
7
- "inspect", "stats", "cp", "tag", "login", "logout", "kill", "pause",
8
- "unpause", "version", "info", "top", "wait", "port", "rename", "diff",
9
- "commit", "save", "load", "attach"
10
- ],
11
- "renamed": {
12
- "ps": "container list",
13
- "images": "image list",
14
- "rmi": "image remove",
15
- "rm": "container remove",
16
- "create": "container create",
17
- "history": "image history",
18
- "search": "image search"
19
- },
20
- "renamedFlags": {
21
- "ps": { "-a": "--all", "--all": "--all", "-q": "--quiet", "--quiet": "--quiet" },
22
- "images": { "-a": "--all", "--all": "--all" },
23
- "rm": { "-f": "--force", "--force": "--force" },
24
- "rmi": { "-f": "--force", "--force": "--force" }
25
- },
26
- "unsupported": {
27
- "swarm": "Swarm orchestration has no wslc equivalent. Use Kubernetes or keep Docker for this workload.",
28
- "service": "Swarm services are not supported by wslc.",
29
- "stack": "Swarm stacks are not supported by wslc.",
30
- "node": "Swarm node management is not supported by wslc.",
31
- "secret": "Swarm secrets are not supported. Pass values with -e or mount a file.",
32
- "config": "Swarm configs are not supported by wslc.",
33
- "plugin": "Docker plugins are not supported by wslc.",
34
- "context": "wslc has a single local runtime, so there are no contexts to switch.",
35
- "buildx": "buildx / bake is not available. Use wslc build for single-platform images.",
36
- "manifest": "Manifest lists cannot be created with wslc in the preview.",
37
- "trust": "Docker Content Trust is Docker-specific and has no wslc equivalent.",
38
- "checkpoint": "Checkpoint/restore is not implemented in wslc."
39
- },
40
- "flags": {
41
- "--platform": {
42
- "action": "drop",
43
- "takesValue": true,
44
- "severity": "warn",
45
- "note": "`--platform` is dropped: wslc builds and runs for the host architecture only in the preview."
46
- },
47
- "--restart": {
48
- "action": "drop",
49
- "takesValue": true,
50
- "severity": "warn",
51
- "note": "Restart policies are not implemented in the wslc preview. Flag dropped — use a Windows scheduled task or a wrapper script for auto-restart."
52
- },
53
- "--gpus": {
54
- "action": "rewrite",
55
- "takesValue": true,
56
- "replaceWith": "--device nvidia.com/gpu=all",
57
- "severity": "info",
58
- "note": "GPU access in wslc goes through the Container Device Interface. Use `--device nvidia.com/gpu=all` instead of `--gpus`."
59
- },
60
- "--network": {
61
- "action": "conditional",
62
- "takesValue": true,
63
- "whenValue": {
64
- "host": {
65
- "action": "drop",
66
- "severity": "info",
67
- "note": "`--network host` behaves differently: wslc routes container traffic through the Windows host stack already, so host networking is implicit. Flag dropped."
68
- }
69
- },
70
- "severity": "info",
71
- "note": "Custom networks are supported but bridge-only. Create it first with `wslc network create`."
72
- },
73
- "--volume": {
74
- "action": "keep",
75
- "takesValue": true,
76
- "aliases": ["-v", "--mount"],
77
- "severity": "info",
78
- "noteWhenWindowsPath": "Windows host paths are shared over VirtioFS. Use forward slashes (`C:/work:/app`) and expect Linux-style permissions on the container side."
79
- }
80
- },
81
- "compose": {
82
- "supported": false,
83
- "note": "wslc has no built-in Compose runtime. Translate each service into a wslc run call, or drive them from a PowerShell/bash script.",
84
- "docsUrl": "https://wslcontainers.com/guides/compose/",
85
- "keys": {
86
- "image": { "status": "ok", "maps": "positional image argument" },
87
- "build": { "status": "ok", "maps": "wslc build -t <name>" },
88
- "command": { "status": "ok", "maps": "trailing command args" },
89
- "entrypoint": { "status": "ok", "maps": "--entrypoint" },
90
- "environment": { "status": "ok", "maps": "-e KEY=VALUE" },
91
- "env_file": { "status": "ok", "maps": "--env-file" },
92
- "ports": { "status": "ok", "maps": "-p HOST:CONTAINER" },
93
- "volumes": { "status": "partial", "maps": "-v", "note": "Named volumes must be created first with wslc volume create. Windows paths go over VirtioFS." },
94
- "networks": { "status": "partial", "maps": "--network", "note": "Bridge-only. Create with wslc network create before running." },
95
- "working_dir": { "status": "ok", "maps": "-w" },
96
- "user": { "status": "ok", "maps": "-u" },
97
- "hostname": { "status": "ok", "maps": "--hostname" },
98
- "container_name": { "status": "ok", "maps": "--name" },
99
- "labels": { "status": "ok", "maps": "--label" },
100
- "cap_add": { "status": "partial", "maps": "--cap-add", "note": "Some capabilities are restricted inside the utility VM." },
101
- "devices": { "status": "partial", "maps": "--device", "note": "CDI syntax differs from Docker for GPUs." },
102
- "tmpfs": { "status": "ok", "maps": "--tmpfs" },
103
- "stdin_open": { "status": "ok", "maps": "-i" },
104
- "tty": { "status": "ok", "maps": "-t" },
105
- "restart": { "status": "missing", "note": "No restart policies in the wslc preview." },
106
- "healthcheck": { "status": "missing", "note": "wslc has no healthcheck support; depends_on conditions relying on it cannot work." },
107
- "depends_on": { "status": "missing", "note": "No dependency ordering. Start services in order yourself and add readiness waits." },
108
- "deploy": { "status": "missing", "note": "Swarm-only section, ignored entirely." },
109
- "profiles": { "status": "missing", "note": "Compose-only concept." },
110
- "extends": { "status": "missing", "note": "Compose-only concept." },
111
- "configs": { "status": "missing", "note": "Swarm configs are unsupported; mount a file instead." },
112
- "secrets": { "status": "missing", "note": "Swarm secrets are unsupported; use -e or a mounted file." }
113
- }
114
- },
115
- "devcontainer": {
116
- "keys": {
117
- "image": { "status": "ok" },
118
- "build.dockerfile": { "status": "ok" },
119
- "build.args": { "status": "ok", "maps": "--build-arg" },
120
- "build.platform": { "status": "missing", "note": "Host architecture only." },
121
- "workspaceMount": { "status": "partial", "note": "VirtioFS; use forward slashes for Windows paths." },
122
- "workspaceFolder": { "status": "ok" },
123
- "containerEnv": { "status": "ok", "maps": "-e" },
124
- "remoteEnv": { "status": "ok" },
125
- "forwardPorts": { "status": "ok", "maps": "-p" },
126
- "postCreateCommand": { "status": "ok", "maps": "wslc exec" },
127
- "postStartCommand": { "status": "ok" },
128
- "postAttachCommand": { "status": "ok" },
129
- "remoteUser": { "status": "ok", "maps": "-u" },
130
- "containerUser": { "status": "ok" },
131
- "mounts": { "status": "partial", "note": "VirtioFS path rules apply." },
132
- "runArgs": { "status": "partial", "note": "Passed through verbatim; unsupported flags will fail at runtime." },
133
- "dockerComposeFile": { "status": "missing", "note": "No Compose runtime. Replace with a single image or build entry." },
134
- "features": { "status": "missing", "note": "Requires BuildKit metadata that wslc build does not emit." },
135
- "runServices": { "status": "missing", "note": "Compose-only key." },
136
- "shutdownAction": { "status": "partial", "note": "stopCompose is meaningless without Compose." }
137
- },
138
- "requiredSetting": {
139
- "key": "dev.containers.dockerPath",
140
- "value": "wslc",
141
- "note": "Point the Dev Containers extension at wslc. Prefer workspace scope over global."
142
- }
143
- },
144
- "apiIncompatible": {
145
- "note": "CLI-driven tooling ports to wslc. API-driven tooling cannot, because wslc is daemonless and exposes no Docker Engine API or socket.",
146
- "tools": [
147
- { "name": "Testcontainers", "via": "Engine API", "works": false },
148
- { "name": "Docker-in-Docker sidecars", "via": "mounted socket", "works": false },
149
- { "name": "Portainer", "via": "Engine API", "works": false },
150
- { "name": "Lazydocker", "via": "Engine API", "works": false },
151
- { "name": "LocalStack (docker mode)", "via": "Engine API", "works": false },
152
- { "name": "act", "via": "Engine API", "works": false },
153
- { "name": "VS Code Dev Containers", "via": "CLI binary", "works": true },
154
- { "name": "shell scripts calling docker", "via": "CLI binary", "works": true }
155
- ]
156
- },
157
- "links": {
158
- "site": "https://wslcontainers.com",
159
- "converter": "https://wslcontainers.com/",
160
- "cheatsheet": "https://wslcontainers.com/reference/cheatsheet/",
161
- "compose": "https://wslcontainers.com/guides/compose/",
162
- "install": "https://wslcontainers.com/guides/install/",
163
- "vsDocker": "https://wslcontainers.com/guides/vs-docker-desktop/",
164
- "devcontainers": "https://wslcontainers.com/guides/vscode-dev-containers/",
165
- "testcontainers": "https://wslcontainers.com/guides/testcontainers/"
166
- }
167
- }
File without changes
File without changes