dsh-plugin-container 0.0.0-stage → 0.3.0

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -2
  3. package/cordis.patch.yml +3 -0
  4. package/docs/ai-chat.png +0 -0
  5. package/docs/ai-new-session.png +0 -0
  6. package/docs/apple-container.png +0 -0
  7. package/docs/attach.png +0 -0
  8. package/docs/docker-console.png +0 -0
  9. package/docs/docker-overview.png +0 -0
  10. package/docs/docker-volumes.png +0 -0
  11. package/docs/image-architecture.png +0 -0
  12. package/docs/package-install.png +0 -0
  13. package/docs/provider-switch.png +0 -0
  14. package/docs/run-container.png +0 -0
  15. package/index.js +138 -0
  16. package/lib/client.js +3560 -0
  17. package/package.json +62 -4
  18. package/src/client/api.js +98 -0
  19. package/src/client/attach.jsx +134 -0
  20. package/src/client/components.jsx +320 -0
  21. package/src/client/hooks.js +161 -0
  22. package/src/client/i18n.js +502 -0
  23. package/src/client/icons.jsx +227 -0
  24. package/src/client/index.jsx +76 -0
  25. package/src/client/page.jsx +782 -0
  26. package/src/client/run-container.jsx +187 -0
  27. package/src/client/runs.js +182 -0
  28. package/src/client/store.js +91 -0
  29. package/src/client/styles.js +371 -0
  30. package/src/client/tabs/compose.jsx +94 -0
  31. package/src/client/tabs/console.jsx +211 -0
  32. package/src/client/tabs/containers.jsx +148 -0
  33. package/src/client/tabs/images.jsx +127 -0
  34. package/src/client/tabs/networks.jsx +91 -0
  35. package/src/client/tabs/overview.jsx +266 -0
  36. package/src/client/tabs/volumes.jsx +76 -0
  37. package/src/host/apple-cli.js +307 -0
  38. package/src/host/apple.js +471 -0
  39. package/src/host/attach.js +246 -0
  40. package/src/host/commands.js +235 -0
  41. package/src/host/docker-cli.js +405 -0
  42. package/src/host/jobs.js +245 -0
  43. package/src/host/parsers.js +484 -0
  44. package/src/host/runtime.js +285 -0
  45. package/src/host/service.js +836 -0
  46. package/src/host/tools.js +198 -0
  47. package/src/host/util.js +97 -0
@@ -0,0 +1,161 @@
1
+ /** Data hooks for the Docker panel. */
2
+ import { useCallback, useEffect, useRef, useState } from 'react'
3
+
4
+ import { cacheClear, cacheGet, cacheSet, isAbortError } from './api.js'
5
+
6
+ const LIST_TTL = 2000
7
+ const STATUS_INTERVAL = 10_000
8
+
9
+ /**
10
+ * Load one Docker list resource. Manual refreshes bypass the short cache so a
11
+ * click always reflects a fresh command result.
12
+ */
13
+ export function useDockerList(api, provider, resource, context, { all = true, refreshToken = 0, enabled = true } = {}) {
14
+ const key = `list:${provider}:${resource}:${context ?? ''}:${all ? 'all' : 'running'}`
15
+ const [state, setState] = useState(() => {
16
+ const cached = cacheGet(key)
17
+ return { data: cached ?? null, error: null, loading: cached === undefined }
18
+ })
19
+ const [localVersion, setLocalVersion] = useState(0)
20
+ const [reloadSignal, setReloadSignal] = useState(0)
21
+
22
+ useEffect(() => {
23
+ setState({ data: null, error: null, loading: enabled })
24
+ }, [enabled, key])
25
+
26
+ useEffect(() => {
27
+ if (!enabled) {
28
+ setState((current) => (current.data === null && !current.loading && current.error === null ? current : { data: null, error: null, loading: false }))
29
+ return undefined
30
+ }
31
+ const cached = refreshToken === 0 && reloadSignal === 0 ? cacheGet(key) : undefined
32
+ if (cached !== undefined) {
33
+ setState({ data: cached, error: null, loading: false })
34
+ return undefined
35
+ }
36
+ const controller = new AbortController()
37
+ let active = true
38
+ setState((current) => ({ data: current.data, error: null, loading: current.data === null }))
39
+ api.call('list', { provider, resource, context: context ?? undefined, all }, controller.signal).then(
40
+ (value) => {
41
+ if (!active) return
42
+ cacheSet(key, value, LIST_TTL)
43
+ setState({ data: value, error: null, loading: false })
44
+ },
45
+ (error) => {
46
+ if (!active || isAbortError(error)) return
47
+ setState((current) => ({ data: current.data, error, loading: false }))
48
+ },
49
+ )
50
+ return () => {
51
+ active = false
52
+ controller.abort()
53
+ }
54
+ }, [api, provider, key, resource, context, all, enabled, refreshToken, reloadSignal, localVersion])
55
+
56
+ const reload = useCallback(() => {
57
+ cacheClear(key)
58
+ setReloadSignal((value) => value + 1)
59
+ }, [key])
60
+
61
+ return { ...state, reload }
62
+ }
63
+
64
+ /**
65
+ * Poll Docker status while the panel is visible; keep the last good snapshot
66
+ * when a poll fails so the panel does not flicker during a daemon restart.
67
+ */
68
+ export function useDockerStatus(api, provider, context, refreshToken = 0) {
69
+ const [state, setState] = useState({ data: null, error: null, loading: true, updatedAt: null })
70
+ const [localVersion, setLocalVersion] = useState(0)
71
+ const mounted = useRef(true)
72
+
73
+ const load = useCallback(
74
+ async (signal) => {
75
+ try {
76
+ const value = await api.call('status', { provider, context: context ?? undefined }, signal)
77
+ if (!mounted.current || signal?.aborted === true) return
78
+ setState({ data: value, error: null, loading: false, updatedAt: Date.now() })
79
+ } catch (error) {
80
+ if (!mounted.current || isAbortError(error)) return
81
+ setState((current) => ({ ...current, error, loading: false }))
82
+ }
83
+ },
84
+ [api, provider, context],
85
+ )
86
+
87
+ useEffect(() => {
88
+ mounted.current = true
89
+ return () => {
90
+ mounted.current = false
91
+ }
92
+ }, [])
93
+
94
+ useEffect(() => {
95
+ setState({ data: null, error: null, loading: true, updatedAt: null })
96
+ }, [api, provider, context])
97
+
98
+ useEffect(() => {
99
+ let controller = new AbortController()
100
+ let timer
101
+ const tick = () => {
102
+ if (document.visibilityState !== 'visible') {
103
+ timer = setTimeout(tick, STATUS_INTERVAL)
104
+ return
105
+ }
106
+ controller.abort()
107
+ controller = new AbortController()
108
+ load(controller.signal)
109
+ timer = setTimeout(tick, STATUS_INTERVAL)
110
+ }
111
+ setState((current) => ({ ...current, loading: current.data === null }))
112
+ tick()
113
+ const onVisibility = () => {
114
+ if (document.visibilityState === 'visible') {
115
+ clearTimeout(timer)
116
+ tick()
117
+ }
118
+ }
119
+ document.addEventListener('visibilitychange', onVisibility)
120
+ return () => {
121
+ controller.abort()
122
+ clearTimeout(timer)
123
+ document.removeEventListener('visibilitychange', onVisibility)
124
+ }
125
+ }, [load, refreshToken, localVersion])
126
+
127
+ const refresh = useCallback(() => {
128
+ cacheClear('list:')
129
+ setLocalVersion((value) => value + 1)
130
+ }, [])
131
+
132
+ return { ...state, refresh }
133
+ }
134
+
135
+
136
+ /** Load the available providers and their CLI/system availability. */
137
+ export function useProviders(api, refreshToken = 0) {
138
+ const [state, setState] = useState({ data: null, error: null, loading: true })
139
+ const [localVersion, setLocalVersion] = useState(0)
140
+ useEffect(() => {
141
+ const controller = new AbortController()
142
+ let active = true
143
+ setState((current) => ({ ...current, loading: current.data === null, error: null }))
144
+ api.call('providers', {}, controller.signal).then(
145
+ (value) => {
146
+ if (!active) return
147
+ setState({ data: value, error: null, loading: false })
148
+ },
149
+ (error) => {
150
+ if (!active || isAbortError(error)) return
151
+ setState({ data: null, error, loading: false })
152
+ },
153
+ )
154
+ return () => {
155
+ active = false
156
+ controller.abort()
157
+ }
158
+ }, [api, refreshToken, localVersion])
159
+ const reload = useCallback(() => setLocalVersion((value) => value + 1), [])
160
+ return { ...state, reload }
161
+ }
@@ -0,0 +1,502 @@
1
+ /** Localized copy for the Docker panel. */
2
+ import { createContext, useContext } from 'react'
3
+
4
+ export const NS = 'docker'
5
+ export const LocaleContext = createContext((key) => key)
6
+
7
+ export function useT() {
8
+ return useContext(LocaleContext)
9
+ }
10
+
11
+ /** Simplified Chinese is the key source of truth. */
12
+ export const zh = {
13
+ panel: '容器',
14
+ title: '容器运行时',
15
+ subtitle: 'Docker 与 Apple container',
16
+ statusRunning: '运行中',
17
+ statusStopped: '已停止',
18
+ statusStarting: '启动中',
19
+ statusUnavailable: '不可用',
20
+ statusRemote: '远程',
21
+ statusUnknown: '未知',
22
+ context: '上下文',
23
+ providerLabel: '运行时',
24
+ providerDocker: 'Docker',
25
+ providerApple: 'Apple container',
26
+ systemService: '系统服务',
27
+ appleSystemStopped: 'Apple container 服务未启动',
28
+ appleSystemStoppedBody: '启动系统服务后可查看容器。首次启动可能需要管理员权限和 kernel;失败时请在终端执行 container system start。',
29
+ appleCliMissing: '未找到 container 命令',
30
+ appleCliMissingBody: '请安装 Apple container(macOS 26 / Apple silicon),并执行 container system start。',
31
+ appleCommandPlaceholder: 'container ls -a',
32
+ currentContext: '当前上下文',
33
+ currentSuffix: '当前',
34
+ noContext: '无上下文',
35
+ refresh: '刷新',
36
+ start: '启动',
37
+ stop: '停止',
38
+ restart: '重启',
39
+ starting: '正在启动…',
40
+ stopping: '正在停止…',
41
+ cliMissing: '未找到 Docker 命令',
42
+ cliMissingBody: '请安装 Docker Desktop,或安装 colima 并启动运行时。',
43
+ daemonStopped: 'Docker 引擎未运行',
44
+ daemonStoppedBody: '启动本机运行时后即可查看容器并执行命令。',
45
+ daemonUnreachable: '无法连接 Docker 引擎',
46
+ remoteHint: '当前是远程 Docker 上下文,运行时需在目标主机管理。',
47
+ runtimeControlDisabled: '当前环境禁用运行时启停。',
48
+ runtimeActionFailed: '运行时操作失败,请查看命令终端输出。',
49
+ runtimeActionTimeout: '运行时操作超时;请查看命令终端或终端输出。',
50
+ overview: '概览',
51
+ containers: '容器',
52
+ images: '镜像',
53
+ volumes: '卷',
54
+ networks: '网络',
55
+ compose: 'Compose',
56
+ console: '命令',
57
+ search: '搜索',
58
+ all: '全部',
59
+ running: '运行中',
60
+ stopped: '已停止',
61
+ name: '名称',
62
+ image: '镜像',
63
+ status: '状态',
64
+ ports: '端口',
65
+ created: '创建时间',
66
+ actions: '操作',
67
+ startContainer: '启动',
68
+ stopContainer: '停止',
69
+ restartContainer: '重启',
70
+ logs: '日志',
71
+ runContainer: '启动容器',
72
+ runContainerTitle: '启动新容器',
73
+ runImage: '镜像',
74
+ runImagePlaceholder: 'nginx:latest',
75
+ runImageSelect: '选择本地镜像',
76
+ runImageCustom: '自定义镜像…',
77
+ runImageListEmpty: '暂无本地镜像;可选择自定义镜像或先拉取。',
78
+ runFromImage: '用此镜像启动容器',
79
+ runName: '名称(可选)',
80
+ runNamePlaceholder: 'my-container',
81
+ runCommand: '命令(可选)',
82
+ runCommandPlaceholder: 'sh -c "echo hi"',
83
+ runPorts: '端口(可选)',
84
+ runPortsPlaceholder: '8080:80',
85
+ runEnv: '环境变量(可选)',
86
+ runEnvPlaceholder: 'KEY=VALUE\nANOTHER=value',
87
+ runDetachedHint: '后台运行 (-d);启动后可在容器行点 Attach。',
88
+ runStart: '启动',
89
+ runStarted: '容器启动已提交',
90
+ runImageRequired: '请输入镜像名',
91
+ restartFeatures: '重启 DSH 以启用启动容器 / Attach',
92
+ restartForArchitecture: '重启 DSH 以显示镜像架构',
93
+ attach: 'Attach',
94
+ exec: 'Exec',
95
+ execTitle: 'Exec 终端',
96
+ askAi: '问 AI',
97
+ diagnose: '诊断',
98
+ askAiSent: '已发送到 AI 会话',
99
+ askAiNewSession: '已创建诊断会话并在主对话中打开',
100
+ askAiUnavailable: '当前 host 或会话不支持 AI 工具,请重启 DSH 后重试',
101
+ attachTitle: 'Attach 终端',
102
+ attachStarting: '正在连接…',
103
+ attachRunning: '已连接',
104
+ attachExited: '已结束',
105
+ attachFailed: '连接失败',
106
+ attachClosed: '已关闭',
107
+ attachHint: '已连接。点击终端后输入;Ctrl+C 中断,关闭窗口结束会话。',
108
+ attachInputHint: '点击终端输入 · Ctrl+C 中断',
109
+ attachClose: '结束 Attach',
110
+ execClose: '结束 Exec',
111
+ attachNotRunning: '容器未运行,无法 attach',
112
+ followLogs: '持续日志',
113
+ inspect: '检查',
114
+ remove: '删除',
115
+ removeImage: '删除镜像',
116
+ removeVolume: '删除卷',
117
+ removeNetwork: '删除网络',
118
+ pull: '拉取',
119
+ pullPlaceholder: 'nginx:latest',
120
+ pullAction: '拉取镜像',
121
+ emptyContainers: '没有容器',
122
+ emptyImages: '没有镜像',
123
+ emptyVolumes: '没有卷',
124
+ emptyNetworks: '没有网络',
125
+ emptyCompose: '没有 Compose 项目',
126
+ emptySearch: '没有匹配项',
127
+ loading: '正在读取…',
128
+ errorTitle: '读取失败',
129
+ retry: '重试',
130
+ runningContainers: '运行中容器',
131
+ stoppedContainers: '已停止容器',
132
+ imageCount: '镜像',
133
+ volumeCount: '卷',
134
+ networkCount: '网络',
135
+ cpus: 'CPU',
136
+ memory: '内存',
137
+ disk: '磁盘',
138
+ server: '服务端',
139
+ client: '客户端',
140
+ version: '版本',
141
+ runtime: '运行时',
142
+ endpoint: 'Endpoint',
143
+ driver: 'Driver',
144
+ arch: '架构',
145
+ mountType: '挂载类型',
146
+ kubernetes: 'Kubernetes',
147
+ yes: '是',
148
+ no: '否',
149
+ recentContainers: '最近容器',
150
+ viewAll: '查看全部',
151
+ quickCommands: '快捷命令',
152
+ commandPlaceholder: 'docker ps -a',
153
+ shellHint: '命令直接以 argv 执行,不支持管道/重定向。',
154
+ run: '运行',
155
+ cancel: '取消',
156
+ clear: '清空',
157
+ copy: '复制',
158
+ copied: '已复制',
159
+ history: '历史',
160
+ noHistory: '暂无历史',
161
+ cwd: '工作目录',
162
+ cwdPlaceholder: '默认(Home);可填绝对路径',
163
+ contextLabel: '上下文',
164
+ exitCode: '退出码',
165
+ elapsed: '耗时',
166
+ timedOut: '已超时',
167
+ cancelled: '已取消',
168
+ failed: '失败',
169
+ exited: '已完成',
170
+ truncation: '输出已截断(超出保留上限)',
171
+ commandRunning: '命令运行中',
172
+ commandFinished: '命令已完成',
173
+ confirmTitle: '确认操作',
174
+ confirmDanger: '这是危险操作,请确认命令内容。',
175
+ confirmDelete: '删除后无法恢复。',
176
+ confirmStop: '停止容器会中断其进程。',
177
+ confirmRuntime: '停止/重启运行时会中断所有容器。',
178
+ confirmRun: '继续执行',
179
+ confirmCancel: '取消',
180
+ dangerDelete: '删除',
181
+ dangerStop: '停止',
182
+ dangerPrune: '清理',
183
+ dangerComposeDown: '停止并移除',
184
+ dangerRuntime: '停止运行时',
185
+ inspectTitle: '检查详情',
186
+ close: '关闭',
187
+ rawJson: '原始 JSON',
188
+ noOutput: '还没有输出',
189
+ selectContext: '选择上下文',
190
+ runtimeStart: '启动运行时',
191
+ runtimeStop: '停止运行时',
192
+ runtimeRestart: '重启运行时',
193
+ cliPath: 'Docker 路径',
194
+ openDocs: 'Docker 文档',
195
+ resetHistory: '清空命令历史',
196
+ cacheCleared: '缓存已清空',
197
+ refreshFailed: '刷新失败',
198
+ statusFailed: '无法读取运行时状态',
199
+ listFailed: '无法读取列表',
200
+ composeReadOnly: 'Compose 项目为只读;请在命令中执行 up/down。',
201
+ copyCommand: '复制命令',
202
+ details: '详情',
203
+ labels: '标签',
204
+ mounts: '挂载',
205
+ networksLabel: '网络',
206
+ command: '命令',
207
+ createdSince: '创建于',
208
+ size: '大小',
209
+ architecture: '架构',
210
+ repository: '仓库',
211
+ tag: '标签',
212
+ id: 'ID',
213
+ scope: 'Scope',
214
+ mountpoint: '挂载点',
215
+ internal: 'Internal',
216
+ configFiles: '配置文件',
217
+ project: '项目',
218
+ stopFollowing: '停止日志',
219
+ following: '日志跟随中',
220
+ terminal: '命令终端',
221
+ startRuntimeTitle: '启动运行时',
222
+ stopRuntimeTitle: '停止运行时',
223
+ confirmStopRuntime: '确认停止',
224
+ confirmRestartRuntime: '确认重启',
225
+ confirmRemoveTitle: '确认删除',
226
+ confirmRemoveBody: '将执行:',
227
+ cancelRun: '取消命令',
228
+ keepRunning: '继续运行',
229
+ noActiveRun: '没有运行中的命令',
230
+ clearOutput: '清空输出',
231
+ workspace: '工作目录',
232
+ lastUpdated: '更新于',
233
+ noDocker: '未检测到 Docker',
234
+ noDockerBody: '安装 Docker 或 colima 后刷新。',
235
+ colima: 'colima',
236
+ dockerDesktop: 'Docker Desktop',
237
+ orbstack: 'OrbStack',
238
+ remote: '远程上下文',
239
+ unknownRuntime: '未知运行时',
240
+ inspectAction: 'Inspect',
241
+ openInspect: '查看详情',
242
+ textCopyFailed: '复制失败',
243
+ confirmRequired: '该操作需要确认',
244
+ modalCancel: '取消',
245
+ modalContinue: '继续',
246
+ noDiskData: '没有磁盘数据',
247
+ pullInvalid: '请输入合法的镜像名,例如 nginx:latest',
248
+ composeUnavailable: '当前上下文不支持 Compose',
249
+ statusErrorHint: '请确认当前容器运行时已启动,然后重试。',
250
+ unavailableValue: '—',
251
+ closePanel: '关闭',
252
+ viewRuntime: '运行时详情',
253
+ restartToApply: '需要重启 DSH 才能应用 host 变更',
254
+ notInstalled: '未安装',
255
+ unknown: '未知',
256
+ }
257
+
258
+ export const en = {
259
+ panel: 'Containers',
260
+ title: 'Container runtimes',
261
+ subtitle: 'Docker and Apple container',
262
+ statusRunning: 'Running',
263
+ statusStopped: 'Stopped',
264
+ statusStarting: 'Starting',
265
+ statusUnavailable: 'Unavailable',
266
+ statusRemote: 'Remote',
267
+ statusUnknown: 'Unknown',
268
+ context: 'Context',
269
+ providerLabel: 'Provider',
270
+ providerDocker: 'Docker',
271
+ providerApple: 'Apple container',
272
+ systemService: 'System service',
273
+ appleSystemStopped: 'Apple container service is not running',
274
+ appleSystemStoppedBody: 'Start the system service to inspect containers. The first start may require admin permission and a kernel; if it fails, run container system start in a terminal.',
275
+ appleCliMissing: 'container command not found',
276
+ appleCliMissingBody: 'Install Apple container (macOS 26 / Apple silicon) and run container system start.',
277
+ appleCommandPlaceholder: 'container ls -a',
278
+ currentContext: 'Current context',
279
+ currentSuffix: 'current',
280
+ noContext: 'No context',
281
+ refresh: 'Refresh',
282
+ start: 'Start',
283
+ stop: 'Stop',
284
+ restart: 'Restart',
285
+ starting: 'Starting…',
286
+ stopping: 'Stopping…',
287
+ cliMissing: 'Docker command not found',
288
+ cliMissingBody: 'Install Docker Desktop, or install colima and start the runtime.',
289
+ daemonStopped: 'Docker engine is not running',
290
+ daemonStoppedBody: 'Start the local runtime to inspect containers and run commands.',
291
+ daemonUnreachable: 'Cannot reach the Docker engine',
292
+ remoteHint: 'This is a remote Docker context; manage its runtime on the target host.',
293
+ runtimeControlDisabled: 'Runtime control is disabled in this deployment.',
294
+ runtimeActionFailed: 'Runtime action failed; check the command terminal output.',
295
+ runtimeActionTimeout: 'Runtime action timed out; check the command terminal output.',
296
+ overview: 'Overview',
297
+ containers: 'Containers',
298
+ images: 'Images',
299
+ volumes: 'Volumes',
300
+ networks: 'Networks',
301
+ compose: 'Compose',
302
+ console: 'Command',
303
+ search: 'Search',
304
+ all: 'All',
305
+ running: 'Running',
306
+ stopped: 'Stopped',
307
+ name: 'Name',
308
+ image: 'Image',
309
+ status: 'Status',
310
+ ports: 'Ports',
311
+ created: 'Created',
312
+ actions: 'Actions',
313
+ startContainer: 'Start',
314
+ stopContainer: 'Stop',
315
+ restartContainer: 'Restart',
316
+ logs: 'Logs',
317
+ runContainer: 'Start container',
318
+ runContainerTitle: 'Start a new container',
319
+ runImage: 'Image',
320
+ runImagePlaceholder: 'nginx:latest',
321
+ runImageSelect: 'Select a local image',
322
+ runImageCustom: 'Custom image…',
323
+ runImageListEmpty: 'No local images; choose a custom image or pull one first.',
324
+ runFromImage: 'Start a container from this image',
325
+ runName: 'Name (optional)',
326
+ runNamePlaceholder: 'my-container',
327
+ runCommand: 'Command (optional)',
328
+ runCommandPlaceholder: 'sh -c "echo hi"',
329
+ runPorts: 'Ports (optional)',
330
+ runPortsPlaceholder: '8080:80',
331
+ runEnv: 'Environment (optional)',
332
+ runEnvPlaceholder: 'KEY=VALUE\nANOTHER=value',
333
+ runDetachedHint: 'Runs detached (-d); use Attach on the container row afterwards.',
334
+ runStart: 'Start',
335
+ runStarted: 'Container start submitted',
336
+ runImageRequired: 'Image is required',
337
+ restartFeatures: 'Restart DSH to enable Start container / Attach',
338
+ restartForArchitecture: 'Restart DSH to show image architecture',
339
+ attach: 'Attach',
340
+ exec: 'Exec',
341
+ execTitle: 'Exec terminal',
342
+ askAi: 'Ask AI',
343
+ diagnose: 'Diagnose',
344
+ askAiSent: 'Sent to the AI conversation',
345
+ askAiNewSession: 'Created a diagnosis session and opened it in the main conversation',
346
+ askAiUnavailable: 'AI tools are unavailable in this host or session; restart DSH and retry',
347
+ attachTitle: 'Attach terminal',
348
+ attachStarting: 'Connecting…',
349
+ attachRunning: 'Connected',
350
+ attachExited: 'Exited',
351
+ attachFailed: 'Connection failed',
352
+ attachClosed: 'Closed',
353
+ attachHint: 'Connected. Click the terminal and type; Ctrl+C interrupts. Closing the dialog ends the session.',
354
+ attachInputHint: 'Click terminal to type · Ctrl+C interrupts',
355
+ attachClose: 'End attach',
356
+ execClose: 'End exec',
357
+ attachNotRunning: 'Container is not running; attach is unavailable',
358
+ followLogs: 'Follow logs',
359
+ inspect: 'Inspect',
360
+ remove: 'Remove',
361
+ removeImage: 'Remove image',
362
+ removeVolume: 'Remove volume',
363
+ removeNetwork: 'Remove network',
364
+ pull: 'Pull',
365
+ pullPlaceholder: 'nginx:latest',
366
+ pullAction: 'Pull image',
367
+ emptyContainers: 'No containers',
368
+ emptyImages: 'No images',
369
+ emptyVolumes: 'No volumes',
370
+ emptyNetworks: 'No networks',
371
+ emptyCompose: 'No Compose projects',
372
+ emptySearch: 'No matches',
373
+ loading: 'Loading…',
374
+ errorTitle: 'Failed to load',
375
+ retry: 'Retry',
376
+ runningContainers: 'Running containers',
377
+ stoppedContainers: 'Stopped containers',
378
+ imageCount: 'Images',
379
+ volumeCount: 'Volumes',
380
+ networkCount: 'Networks',
381
+ cpus: 'CPU',
382
+ memory: 'Memory',
383
+ disk: 'Disk',
384
+ server: 'Server',
385
+ client: 'Client',
386
+ version: 'Version',
387
+ runtime: 'Runtime',
388
+ endpoint: 'Endpoint',
389
+ driver: 'Driver',
390
+ arch: 'Arch',
391
+ mountType: 'Mount type',
392
+ kubernetes: 'Kubernetes',
393
+ yes: 'Yes',
394
+ no: 'No',
395
+ recentContainers: 'Recent containers',
396
+ viewAll: 'View all',
397
+ quickCommands: 'Quick commands',
398
+ commandPlaceholder: 'docker ps -a',
399
+ shellHint: 'Commands run as argv; pipes and redirection are not supported.',
400
+ run: 'Run',
401
+ cancel: 'Cancel',
402
+ clear: 'Clear',
403
+ copy: 'Copy',
404
+ copied: 'Copied',
405
+ history: 'History',
406
+ noHistory: 'No history yet',
407
+ cwd: 'Working directory',
408
+ cwdPlaceholder: 'Default (home); absolute path allowed',
409
+ contextLabel: 'Context',
410
+ exitCode: 'Exit code',
411
+ elapsed: 'Elapsed',
412
+ timedOut: 'Timed out',
413
+ cancelled: 'Cancelled',
414
+ failed: 'Failed',
415
+ exited: 'Completed',
416
+ truncation: 'Output was truncated (retention limit)',
417
+ commandRunning: 'Command running',
418
+ commandFinished: 'Command finished',
419
+ confirmTitle: 'Confirm action',
420
+ confirmDanger: 'This is a destructive action. Confirm the command below.',
421
+ confirmDelete: 'Deletion cannot be undone.',
422
+ confirmStop: 'Stopping a container interrupts its processes.',
423
+ confirmRuntime: 'Stopping/restarting the runtime interrupts every container.',
424
+ confirmRun: 'Continue',
425
+ confirmCancel: 'Cancel',
426
+ dangerDelete: 'Delete',
427
+ dangerStop: 'Stop',
428
+ dangerPrune: 'Prune',
429
+ dangerComposeDown: 'Stop and remove',
430
+ dangerRuntime: 'Stop runtime',
431
+ inspectTitle: 'Inspect',
432
+ close: 'Close',
433
+ rawJson: 'Raw JSON',
434
+ noOutput: 'No output yet',
435
+ selectContext: 'Select context',
436
+ runtimeStart: 'Start runtime',
437
+ runtimeStop: 'Stop runtime',
438
+ runtimeRestart: 'Restart runtime',
439
+ cliPath: 'Docker path',
440
+ openDocs: 'Docker docs',
441
+ resetHistory: 'Clear command history',
442
+ cacheCleared: 'Cache cleared',
443
+ refreshFailed: 'Refresh failed',
444
+ statusFailed: 'Could not read Docker status',
445
+ listFailed: 'Could not read the list',
446
+ composeReadOnly: 'Compose projects are read-only; run up/down from the command tab.',
447
+ copyCommand: 'Copy command',
448
+ details: 'Details',
449
+ labels: 'Labels',
450
+ mounts: 'Mounts',
451
+ networksLabel: 'Networks',
452
+ command: 'Command',
453
+ createdSince: 'Created',
454
+ size: 'Size',
455
+ architecture: 'Architecture',
456
+ repository: 'Repository',
457
+ tag: 'Tag',
458
+ id: 'ID',
459
+ scope: 'Scope',
460
+ mountpoint: 'Mountpoint',
461
+ internal: 'Internal',
462
+ configFiles: 'Config files',
463
+ project: 'Project',
464
+ stopFollowing: 'Stop logs',
465
+ following: 'Following logs',
466
+ terminal: 'Command terminal',
467
+ startRuntimeTitle: 'Start runtime',
468
+ stopRuntimeTitle: 'Stop runtime',
469
+ confirmStopRuntime: 'Confirm stop',
470
+ confirmRestartRuntime: 'Confirm restart',
471
+ confirmRemoveTitle: 'Confirm removal',
472
+ confirmRemoveBody: 'This will run:',
473
+ cancelRun: 'Cancel command',
474
+ keepRunning: 'Keep running',
475
+ noActiveRun: 'No command is running',
476
+ clearOutput: 'Clear output',
477
+ workspace: 'Working directory',
478
+ lastUpdated: 'Updated',
479
+ noDocker: 'Docker not detected',
480
+ noDockerBody: 'Install Docker or colima, then refresh.',
481
+ colima: 'colima',
482
+ dockerDesktop: 'Docker Desktop',
483
+ orbstack: 'OrbStack',
484
+ remote: 'Remote context',
485
+ unknownRuntime: 'Unknown runtime',
486
+ inspectAction: 'Inspect',
487
+ openInspect: 'View details',
488
+ textCopyFailed: 'Copy failed',
489
+ confirmRequired: 'This action needs confirmation',
490
+ modalCancel: 'Cancel',
491
+ modalContinue: 'Continue',
492
+ noDiskData: 'No disk data',
493
+ pullInvalid: 'Enter a valid image reference, for example nginx:latest',
494
+ composeUnavailable: 'Compose is unavailable in this context',
495
+ statusErrorHint: 'Make sure the selected container runtime is running, then retry.',
496
+ unavailableValue: '—',
497
+ closePanel: 'Close',
498
+ viewRuntime: 'Runtime details',
499
+ restartToApply: 'Restart DSH to apply host-side changes',
500
+ notInstalled: 'Not installed',
501
+ unknown: 'Unknown',
502
+ }