fix: v0.4.3 — inspect_image rendering polish (follow-up to #4)
Three live-NAS observations that the 0.4.2 implementation got wrong:
1. Header showed "?:?" — DSM Image/get returns image="" and tag=""
for name:tag lookups; the response fields are unreliable. The
header now echoes the user-supplied image_id, falling back to the
sha256 id only when image_id itself is empty.
2. Ports printed as raw Python dicts ({'port':'22','protocol':'tcp'}).
The ports array is a list of {port, protocol} objects — each entry
now renders as "22/tcp".
3. Environment printed as raw Python dicts ({'key':'PATH','value':...}).
The env array is a list of {key, value} objects — each entry now
renders as "PATH=/usr/local/...".
cmd, entrypoint, and volumes (plain string arrays) were already
correct and are untouched. Tests updated to match the live shape;
two new tests guard the header fallback. References #4 (already
closed by 0.4.2 — no need to reopen for a rendering polish).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -290,10 +290,12 @@ def register_images(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None:
|
||||
if not isinstance(data, dict) or not data:
|
||||
return f"Image '{image_id}' not found."
|
||||
|
||||
repo = data.get("image") or "?"
|
||||
tag = data.get("tag") or "?"
|
||||
display_name = f"{repo}:{tag}"
|
||||
img_hash = data.get("id") or ""
|
||||
# The DSM Image/get response leaves `image` and `tag` empty when the
|
||||
# lookup is by name:tag (live-confirmed against the NAS), so the
|
||||
# response fields are unreliable for the header. Prefer the user-
|
||||
# supplied image_id, then fall back to the id hash.
|
||||
display_name = image_id or img_hash or "?"
|
||||
digest = data.get("digest") or ""
|
||||
size_val = data.get("size") or 0
|
||||
virtual_size_val = data.get("virtual_size") or 0
|
||||
@@ -301,9 +303,9 @@ def register_images(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None:
|
||||
docker_version = data.get("docker_version") or ""
|
||||
cmd = data.get("cmd") or []
|
||||
entrypoint = data.get("entrypoint") or []
|
||||
env_list: list[str] = data.get("env") or []
|
||||
ports: list[str] = data.get("ports") or []
|
||||
volumes: list[str] = data.get("volumes") or []
|
||||
env_list: list[Any] = data.get("env") or []
|
||||
ports: list[Any] = data.get("ports") or []
|
||||
volumes: list[Any] = data.get("volumes") or []
|
||||
|
||||
lines = [f"Image: {display_name}"]
|
||||
if img_hash:
|
||||
@@ -337,7 +339,13 @@ def register_images(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None:
|
||||
lines.append("")
|
||||
lines.append(f"Exposed ports ({len(ports)}):")
|
||||
for port in ports:
|
||||
lines.append(f" {port}")
|
||||
# Live shape: {"port": "22", "protocol": "tcp"}.
|
||||
if isinstance(port, dict):
|
||||
port_num = port.get("port", "?")
|
||||
proto = port.get("protocol", "tcp")
|
||||
lines.append(f" {port_num}/{proto}")
|
||||
else:
|
||||
lines.append(f" {port}")
|
||||
|
||||
if volumes:
|
||||
lines.append("")
|
||||
@@ -349,7 +357,13 @@ def register_images(mcp: FastMCP, config: AppConfig, client: DsmClient) -> None:
|
||||
lines.append("")
|
||||
lines.append(f"Environment ({len(env_list)}):")
|
||||
for var in env_list:
|
||||
lines.append(f" {var}")
|
||||
# Live shape: {"key": "PATH", "value": "/usr/local/sbin"}.
|
||||
if isinstance(var, dict):
|
||||
key = var.get("key", "?")
|
||||
value = var.get("value", "")
|
||||
lines.append(f" {key}={value}")
|
||||
else:
|
||||
lines.append(f" {var}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user