(a: z.infer<typeof InspectArgs>)
| 64 | description = 'Inspect a container or image. With no path, returns a condensed summary (state, health, mounts, networks, env count, image). With a Go-template path, returns just that field. Read-only.'; |
| 65 | isReadOnly = true; isDestructive = false; argsSchema = InspectArgs; |
| 66 | async execute(a: z.infer<typeof InspectArgs>): Promise<ToolResult> { |
| 67 | if (a.path) return docker(['inspect', '--format', a.path, a.target], 20_000); |
| 68 | const r = await runProcess('docker', ['inspect', a.target], { timeoutMs: 20_000 }); |
| 69 | if (r.notFound) return { content: notInstalledMessage('docker', DOCKER_HINT), isError: true }; |
| 70 | if (!r.ok) return { content: (r.stderr || r.stdout).trim() || 'inspect failed', isError: true }; |
| 71 | // Condense the (huge) inspect JSON to the fields a developer actually reads. |
| 72 | try { |
| 73 | const arr = JSON.parse(r.stdout); |
| 74 | const o = Array.isArray(arr) ? arr[0] : arr; |
| 75 | const summary: Record<string, unknown> = { |
| 76 | name: o?.Name, image: o?.Config?.Image ?? o?.RepoTags, |
| 77 | state: o?.State?.Status, health: o?.State?.Health?.Status, |
| 78 | startedAt: o?.State?.StartedAt, restartCount: o?.RestartCount, |
| 79 | ports: o?.NetworkSettings?.Ports ? Object.keys(o.NetworkSettings.Ports) : undefined, |
| 80 | mounts: Array.isArray(o?.Mounts) ? o.Mounts.map((m: any) => `${m.Source}:${m.Destination}`) : undefined, |
| 81 | networks: o?.NetworkSettings?.Networks ? Object.keys(o.NetworkSettings.Networks) : undefined, |
| 82 | envCount: Array.isArray(o?.Config?.Env) ? o.Config.Env.length : undefined, |
| 83 | cmd: o?.Config?.Cmd, |
| 84 | }; |
| 85 | return { content: JSON.stringify(summary, null, 2) }; |
| 86 | } catch { |
| 87 | return { content: r.stdout.slice(0, 4000) }; |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // ---- docker_exec ---- |
nothing calls this directly
no test coverage detected