@exagone313/dsh-podman 0.2.0-rc.2

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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +41 -0
  3. package/README.zh.md +41 -0
  4. package/cordis.patch.yml +17 -0
  5. package/dist/approval-reasons.d.ts +129 -0
  6. package/dist/approval-reasons.js +253 -0
  7. package/dist/approval-reasons.test.d.ts +1 -0
  8. package/dist/approval-reasons.test.js +115 -0
  9. package/dist/approval.d.ts +29 -0
  10. package/dist/approval.js +412 -0
  11. package/dist/approval.test.d.ts +1 -0
  12. package/dist/approval.test.js +462 -0
  13. package/dist/card-route.d.ts +15 -0
  14. package/dist/card-route.js +478 -0
  15. package/dist/card-route.test.d.ts +1 -0
  16. package/dist/card-route.test.js +181 -0
  17. package/dist/card-test-support.d.ts +15 -0
  18. package/dist/card-test-support.js +160 -0
  19. package/dist/client/ContainerCard.d.ts +6 -0
  20. package/dist/client/ContainerCard.js +79 -0
  21. package/dist/client/card-client.d.ts +6 -0
  22. package/dist/client/card-client.js +47 -0
  23. package/dist/client/card-protocol.d.ts +101 -0
  24. package/dist/client/card-protocol.js +10 -0
  25. package/dist/client/container-card-caches.d.ts +10 -0
  26. package/dist/client/container-card-caches.js +31 -0
  27. package/dist/client/container-card-controller.d.ts +107 -0
  28. package/dist/client/container-card-controller.js +207 -0
  29. package/dist/client/container-card-create-modal.d.ts +24 -0
  30. package/dist/client/container-card-create-modal.js +109 -0
  31. package/dist/client/container-card-directory-styles.d.ts +5 -0
  32. package/dist/client/container-card-directory-styles.js +246 -0
  33. package/dist/client/container-card-directory.d.ts +12 -0
  34. package/dist/client/container-card-directory.js +144 -0
  35. package/dist/client/container-card-editors.d.ts +30 -0
  36. package/dist/client/container-card-editors.js +116 -0
  37. package/dist/client/container-card-images.d.ts +37 -0
  38. package/dist/client/container-card-images.js +35 -0
  39. package/dist/client/container-card-paths.d.ts +20 -0
  40. package/dist/client/container-card-paths.js +88 -0
  41. package/dist/client/container-card-row.d.ts +30 -0
  42. package/dist/client/container-card-row.js +54 -0
  43. package/dist/client/container-card-secrets.d.ts +21 -0
  44. package/dist/client/container-card-secrets.js +71 -0
  45. package/dist/client/container-card-shared.d.ts +55 -0
  46. package/dist/client/container-card-shared.js +152 -0
  47. package/dist/client/container-card-styles.d.ts +21 -0
  48. package/dist/client/container-card-styles.js +143 -0
  49. package/dist/client/container-card-volumes.d.ts +12 -0
  50. package/dist/client/container-card-volumes.js +37 -0
  51. package/dist/client/container-card-workspace.d.ts +31 -0
  52. package/dist/client/container-card-workspace.js +24 -0
  53. package/dist/client/directory-picker.d.ts +12 -0
  54. package/dist/client/directory-picker.js +30 -0
  55. package/dist/client/index.d.ts +5 -0
  56. package/dist/client/index.js +4419 -0
  57. package/dist/client/locales.d.ts +9 -0
  58. package/dist/client/locales.js +370 -0
  59. package/dist/client/read-only-approval.d.ts +8 -0
  60. package/dist/client/read-only-approval.js +63 -0
  61. package/dist/client/slot-contract.d.ts +12 -0
  62. package/dist/client/slot-contract.js +4 -0
  63. package/dist/client/terminal-styles.d.ts +5 -0
  64. package/dist/client/terminal-styles.js +31 -0
  65. package/dist/client/tool-views.d.ts +8 -0
  66. package/dist/client/tool-views.js +241 -0
  67. package/dist/containers.test.d.ts +1 -0
  68. package/dist/containers.test.js +443 -0
  69. package/dist/daemons.test.d.ts +1 -0
  70. package/dist/daemons.test.js +153 -0
  71. package/dist/fs-provider.d.ts +23 -0
  72. package/dist/fs-provider.js +184 -0
  73. package/dist/fs-provider.test.d.ts +1 -0
  74. package/dist/fs-provider.test.js +260 -0
  75. package/dist/generated/version.d.ts +2 -0
  76. package/dist/generated/version.js +6 -0
  77. package/dist/grpc/proto/dshctl/v1/control.proto +133 -0
  78. package/dist/grpc/proto/dshguest/v1/guest.proto +79 -0
  79. package/dist/grpc/runtime-client.d.ts +5 -0
  80. package/dist/grpc/runtime-client.js +43 -0
  81. package/dist/guest-rpc.d.ts +62 -0
  82. package/dist/guest-rpc.js +391 -0
  83. package/dist/images.test.d.ts +1 -0
  84. package/dist/images.test.js +79 -0
  85. package/dist/index.d.ts +22 -0
  86. package/dist/index.js +140 -0
  87. package/dist/misc.test.d.ts +1 -0
  88. package/dist/misc.test.js +141 -0
  89. package/dist/mount-enums.d.ts +22 -0
  90. package/dist/mount-enums.js +81 -0
  91. package/dist/mount-input.d.ts +14 -0
  92. package/dist/mount-input.js +64 -0
  93. package/dist/mounts.test.d.ts +1 -0
  94. package/dist/mounts.test.js +408 -0
  95. package/dist/output-reader.d.ts +34 -0
  96. package/dist/output-reader.js +87 -0
  97. package/dist/paths.test.d.ts +1 -0
  98. package/dist/paths.test.js +74 -0
  99. package/dist/preferences.d.ts +6 -0
  100. package/dist/preferences.js +27 -0
  101. package/dist/project-path.d.ts +6 -0
  102. package/dist/project-path.js +73 -0
  103. package/dist/project-path.test.d.ts +1 -0
  104. package/dist/project-path.test.js +52 -0
  105. package/dist/prompts.d.ts +13 -0
  106. package/dist/prompts.js +149 -0
  107. package/dist/public.d.ts +4 -0
  108. package/dist/public.js +63 -0
  109. package/dist/read-only-shell.d.ts +14 -0
  110. package/dist/read-only-shell.js +150 -0
  111. package/dist/read-only-shell.test.d.ts +1 -0
  112. package/dist/read-only-shell.test.js +127 -0
  113. package/dist/secrets.test.d.ts +1 -0
  114. package/dist/secrets.test.js +181 -0
  115. package/dist/settings-commands.test.d.ts +1 -0
  116. package/dist/settings-commands.test.js +549 -0
  117. package/dist/settings-create.test.d.ts +1 -0
  118. package/dist/settings-create.test.js +394 -0
  119. package/dist/settings-mounts.test.d.ts +1 -0
  120. package/dist/settings-mounts.test.js +467 -0
  121. package/dist/settings-paths.test.d.ts +1 -0
  122. package/dist/settings-paths.test.js +65 -0
  123. package/dist/settings-schema.d.ts +14 -0
  124. package/dist/settings-schema.js +14 -0
  125. package/dist/settings-workspaces.test.d.ts +1 -0
  126. package/dist/settings-workspaces.test.js +265 -0
  127. package/dist/spill-store.d.ts +17 -0
  128. package/dist/spill-store.js +54 -0
  129. package/dist/spill-store.test.d.ts +1 -0
  130. package/dist/spill-store.test.js +59 -0
  131. package/dist/subprocess.d.ts +9 -0
  132. package/dist/subprocess.js +369 -0
  133. package/dist/subprocess.test.d.ts +1 -0
  134. package/dist/subprocess.test.js +234 -0
  135. package/dist/test-support.d.ts +328 -0
  136. package/dist/test-support.js +437 -0
  137. package/dist/tool-defs.d.ts +26 -0
  138. package/dist/tool-defs.js +188 -0
  139. package/dist/tool-handlers.d.ts +2 -0
  140. package/dist/tool-handlers.js +546 -0
  141. package/dist/tool-params.d.ts +803 -0
  142. package/dist/tool-params.js +494 -0
  143. package/dist/tool-schemas.d.ts +2 -0
  144. package/dist/tool-schemas.js +5 -0
  145. package/dist/tool-views.d.ts +2 -0
  146. package/dist/tool-views.js +56 -0
  147. package/dist/views.test.d.ts +1 -0
  148. package/dist/views.test.js +23 -0
  149. package/dist/volumes.test.d.ts +1 -0
  150. package/dist/volumes.test.js +40 -0
  151. package/dist/workspace-binding.d.ts +40 -0
  152. package/dist/workspace-binding.js +275 -0
  153. package/dist/workspace-binding.test.d.ts +1 -0
  154. package/dist/workspace-binding.test.js +337 -0
  155. package/docs/architecture.md +173 -0
  156. package/docs/architecture.zh.md +129 -0
  157. package/docs/configuration.md +160 -0
  158. package/docs/configuration.zh.md +147 -0
  159. package/docs/development.md +142 -0
  160. package/docs/development.zh.md +135 -0
  161. package/docs/install-dsh-and-dsh-podman.md +165 -0
  162. package/docs/install-dsh-and-dsh-podman.zh.md +145 -0
  163. package/docs/usage.md +393 -0
  164. package/docs/usage.zh.md +315 -0
  165. package/package.json +119 -0
@@ -0,0 +1,4419 @@
1
+ window.__ModuleLoader__.load({ id: "@exagone313/dsh-podman", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __export = (target, all) => {
10
+ for (var name2 in all)
11
+ __defProp(target, name2, { get: all[name2], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
23
+
24
+ // src/client/index.ts
25
+ var index_exports = {};
26
+ __export(index_exports, {
27
+ apply: () => apply,
28
+ inject: () => inject,
29
+ name: () => name
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/client/directory-picker.ts
34
+ var DirectoryPickerError = class extends Error {
35
+ constructor(failure2) {
36
+ super(
37
+ typeof failure2?.message === "string" && failure2.message !== "" ? failure2.message : "directory listing failed"
38
+ );
39
+ __publicField(this, "code");
40
+ this.code = typeof failure2?.code === "string" ? failure2.code : "";
41
+ }
42
+ };
43
+ function buildDirectoryPicker(remote) {
44
+ const picker = remote?.directoryPicker;
45
+ if (picker === void 0 || typeof picker.list !== "function") return void 0;
46
+ return {
47
+ async list(path, signal) {
48
+ const result = await picker.list(path, signal);
49
+ if (result?.ok === false) throw new DirectoryPickerError(result.error);
50
+ return result.value;
51
+ }
52
+ };
53
+ }
54
+
55
+ // src/client/container-card-styles.ts
56
+ var cardStyle = {
57
+ listStyle: "none",
58
+ border: "1px solid var(--dsw-alias-border-l2)",
59
+ borderRadius: "12px",
60
+ background: "var(--dsw-alias-bg-layer-3)",
61
+ transition: "border-color .16s, background .16s"
62
+ };
63
+ var cardOpenStyle = {
64
+ background: "var(--dsw-alias-bg-layer-2)",
65
+ borderColor: "var(--dsw-alias-label-dimmed)"
66
+ };
67
+ var cardHoverStyle = {
68
+ borderColor: "var(--dsw-alias-label-dimmed)"
69
+ };
70
+ var cardHeaderStyle = {
71
+ width: "100%",
72
+ appearance: "none",
73
+ border: 0,
74
+ background: "none",
75
+ font: "inherit",
76
+ color: "inherit",
77
+ textAlign: "left",
78
+ cursor: "pointer",
79
+ display: "flex",
80
+ alignItems: "center",
81
+ gap: "12px",
82
+ padding: "14px 16px",
83
+ borderRadius: "12px"
84
+ };
85
+ var cardHeadTextStyle = {
86
+ flex: 1,
87
+ minWidth: 0,
88
+ display: "flex",
89
+ flexDirection: "column",
90
+ gap: "4px"
91
+ };
92
+ var cardNameStyle = {
93
+ fontSize: "15px",
94
+ fontWeight: 600,
95
+ lineHeight: 1.4,
96
+ color: "var(--dsw-alias-label-primary)"
97
+ };
98
+ var cardDescriptionStyle = {
99
+ fontSize: "13px",
100
+ lineHeight: 1.5,
101
+ color: "var(--dsw-alias-label-tertiary)"
102
+ };
103
+ var cardBodyStyle = {
104
+ borderTop: "1px solid var(--dsw-alias-border-l2)",
105
+ margin: "0 16px",
106
+ paddingBottom: "8px"
107
+ };
108
+ var sectionTitle = {
109
+ fontWeight: 600,
110
+ margin: "16px 0 8px",
111
+ fontSize: "13px",
112
+ color: "var(--dsw-alias-label-secondary)",
113
+ textTransform: "uppercase",
114
+ letterSpacing: "0.04em"
115
+ };
116
+ var banner = {
117
+ padding: "6px 10px",
118
+ borderRadius: "6px",
119
+ border: "1px solid rgba(210,153,34,0.6)",
120
+ margin: "12px 0",
121
+ fontSize: "13px"
122
+ };
123
+ var greyId = {
124
+ color: "var(--dsw-alias-label-tertiary)",
125
+ fontSize: "12px",
126
+ fontFamily: "var(--dsw-alias-font-mono, ui-monospace, monospace)"
127
+ };
128
+ var hint = {
129
+ fontSize: "13px",
130
+ color: "var(--dsw-alias-label-tertiary)",
131
+ margin: "8px 0"
132
+ };
133
+ var wsBody = {
134
+ display: "flex",
135
+ flexDirection: "column",
136
+ gap: "8px",
137
+ padding: "10px 0 12px"
138
+ };
139
+ var containerRow = {
140
+ display: "flex",
141
+ flexDirection: "column",
142
+ gap: "8px",
143
+ padding: "10px 12px",
144
+ border: "1px solid var(--dsw-alias-border-l2)",
145
+ borderRadius: "10px",
146
+ background: "var(--dsw-alias-bg-layer-3)"
147
+ };
148
+ var containerHeader = {
149
+ display: "flex",
150
+ flexWrap: "wrap",
151
+ alignItems: "center",
152
+ gap: "8px"
153
+ };
154
+ var actions = {
155
+ display: "flex",
156
+ flexWrap: "wrap",
157
+ gap: "8px",
158
+ alignItems: "center"
159
+ };
160
+ var footerRow = {
161
+ display: "flex",
162
+ justifyContent: "flex-end",
163
+ paddingTop: "12px",
164
+ marginTop: "12px",
165
+ borderTop: "1px solid var(--dsw-alias-border-l2)"
166
+ };
167
+ var tableStyle = {
168
+ width: "100%",
169
+ borderCollapse: "collapse",
170
+ fontSize: "13px"
171
+ };
172
+ var thStyle = {
173
+ textAlign: "left",
174
+ padding: "6px 10px",
175
+ borderBottom: "1px solid var(--dsw-alias-border-l2)",
176
+ color: "var(--dsw-alias-label-secondary)",
177
+ fontWeight: 600,
178
+ whiteSpace: "nowrap"
179
+ };
180
+ var tdStyle = {
181
+ padding: "6px 10px",
182
+ borderBottom: "1px solid var(--dsw-alias-border-l2)",
183
+ color: "var(--dsw-alias-label-primary)",
184
+ verticalAlign: "top"
185
+ };
186
+ var imageSelect = {
187
+ appearance: "none",
188
+ padding: "4px 8px",
189
+ borderRadius: "8px",
190
+ border: "1px solid var(--dsw-alias-border-l2)",
191
+ background: "var(--dsw-alias-bg-layer-3)",
192
+ color: "inherit",
193
+ fontSize: "12px",
194
+ maxWidth: "160px"
195
+ };
196
+
197
+ // src/client/container-card-shared.tsx
198
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
199
+ var import_react = require("react");
200
+ var import_jsx_runtime = require("react/jsx-runtime");
201
+ function CardChevron({ open }) {
202
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
203
+ "svg",
204
+ {
205
+ viewBox: "0 0 14 14",
206
+ width: "14",
207
+ height: "14",
208
+ "aria-hidden": "true",
209
+ style: {
210
+ flex: "none",
211
+ color: "var(--dsw-alias-label-tertiary)",
212
+ transition: "transform .16s",
213
+ transform: open ? "rotate(180deg)" : void 0
214
+ },
215
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
216
+ "path",
217
+ {
218
+ d: "M3 5l4 4 4-4",
219
+ fill: "none",
220
+ stroke: "currentColor",
221
+ strokeWidth: "1.5",
222
+ strokeLinecap: "round",
223
+ strokeLinejoin: "round"
224
+ }
225
+ )
226
+ }
227
+ );
228
+ }
229
+ function containerStateDot(status) {
230
+ return status === "running" ? "done" : "error";
231
+ }
232
+ function ConfigField(props) {
233
+ const { t, label, value, current, writable, onChange, onSave, onDiscard } = props;
234
+ const id = (0, import_react.useId)();
235
+ const dirty = value !== current;
236
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
237
+ "div",
238
+ {
239
+ style: {
240
+ display: "flex",
241
+ flexWrap: "wrap",
242
+ alignItems: "center",
243
+ gap: "8px",
244
+ padding: "8px 0"
245
+ },
246
+ children: [
247
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
248
+ "label",
249
+ {
250
+ htmlFor: id,
251
+ style: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)", minWidth: "110px" },
252
+ children: label
253
+ }
254
+ ),
255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
256
+ import_dsh_client_ui_primitives.Input,
257
+ {
258
+ id,
259
+ value,
260
+ disabled: !writable,
261
+ onChange: (event) => onChange(event.target.value),
262
+ style: { width: "200px" }
263
+ }
264
+ ),
265
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
266
+ import_dsh_client_ui_primitives.Button,
267
+ {
268
+ variant: "outline",
269
+ size: "sm",
270
+ disabled: !writable || !dirty,
271
+ onClick: onSave,
272
+ children: t("save")
273
+ }
274
+ ),
275
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
276
+ import_dsh_client_ui_primitives.Button,
277
+ {
278
+ variant: "ghost",
279
+ size: "sm",
280
+ disabled: !dirty,
281
+ onClick: onDiscard,
282
+ children: t("discard")
283
+ }
284
+ )
285
+ ]
286
+ }
287
+ );
288
+ }
289
+ function Field(props) {
290
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: props.htmlFor, style: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)" }, children: props.label }),
292
+ props.children
293
+ ] });
294
+ }
295
+ var namePattern = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,63}$/;
296
+ var imageIdPattern = /^[a-zA-Z0-9_][a-zA-Z0-9_.\-/:]{0,127}$/;
297
+ var sanitizeName = (raw) => raw.replace(/[^a-zA-Z0-9_.-]/g, "");
298
+ var sanitizeImageId = (raw) => raw.replace(/[^a-zA-Z0-9_.\-/:]/g, "");
299
+ var mountKindShort = (kind) => {
300
+ if (kind === "MOUNT_KIND_TMPFS") return "tmpfs";
301
+ if (kind === "MOUNT_KIND_VOLUME") return "volume";
302
+ if (kind === "MOUNT_KIND_SECRET") return "secret";
303
+ return "project";
304
+ };
305
+ var mountModeShort = (mode) => mode === "MOUNT_MODE_READ_ONLY" ? "read_only" : "read_write";
306
+ var mountViewToInput = (mount) => ({
307
+ kind: mountKindShort(mount.kind),
308
+ project: mount.projectName,
309
+ destination: mount.destination,
310
+ mode: mountModeShort(mount.mode),
311
+ volume: mount.volume,
312
+ secret: mount.secret
313
+ });
314
+ var mountLabel = (t, mount, withMode = true) => {
315
+ if (mount.kind === "tmpfs") {
316
+ return `tmpfs${mount.destination !== "" ? ` at ${mount.destination}` : ""}`;
317
+ }
318
+ if (mount.kind === "volume") {
319
+ return `volume ${mount.volume}${mount.destination !== "" ? ` \u2192 ${mount.destination}` : ""}`;
320
+ }
321
+ if (mount.kind === "secret") {
322
+ return `secret ${mount.secret}${mount.destination !== "" ? ` \u2192 ${mount.destination}` : ""}`;
323
+ }
324
+ const mode = withMode ? mount.mode === "read_only" ? " (ro)" : " (rw)" : "";
325
+ return `${mount.project}${mount.destination !== "" ? ` \u2192 ${mount.destination}` : ""}${mode}`;
326
+ };
327
+ var emptyMount = (kind = "project") => ({
328
+ kind,
329
+ project: "",
330
+ destination: "",
331
+ mode: kind === "tmpfs" ? "read_write" : "read_only",
332
+ volume: "",
333
+ secret: ""
334
+ });
335
+ function ConfirmButton(props) {
336
+ const { t, label, title, description, disabled, ariaLabel, onConfirm } = props;
337
+ const [open, setOpen] = (0, import_react.useState)(false);
338
+ const confirm = () => {
339
+ setOpen(false);
340
+ onConfirm();
341
+ };
342
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
343
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
344
+ import_dsh_client_ui_primitives.Button,
345
+ {
346
+ variant: "outline",
347
+ size: "sm",
348
+ disabled,
349
+ "aria-label": ariaLabel,
350
+ onClick: () => setOpen(true),
351
+ children: label
352
+ }
353
+ ),
354
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
355
+ import_dsh_client_ui_primitives.Modal,
356
+ {
357
+ open,
358
+ onClose: () => setOpen(false),
359
+ title,
360
+ closeLabel: t("cancel"),
361
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
362
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
363
+ import_dsh_client_ui_primitives.Button,
364
+ {
365
+ variant: "outline",
366
+ size: "sm",
367
+ onClick: () => setOpen(false),
368
+ children: t("cancel")
369
+ }
370
+ ),
371
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", size: "sm", onClick: confirm, children: t("confirm") })
372
+ ] }),
373
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { ...hint, margin: 0 }, children: description })
374
+ }
375
+ )
376
+ ] });
377
+ }
378
+ function Chip(props) {
379
+ const { t, label, disabled, onRemove } = props;
380
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
381
+ "span",
382
+ {
383
+ style: {
384
+ display: "inline-flex",
385
+ alignItems: "center",
386
+ gap: "2px",
387
+ height: "24px",
388
+ padding: onRemove === void 0 ? "0 8px" : "0 4px 0 8px",
389
+ borderRadius: "999px",
390
+ border: "1px solid var(--dsw-alias-border-l2)",
391
+ background: "var(--dsw-alias-bg-layer-3)",
392
+ fontSize: "12px",
393
+ fontFamily: "var(--dsw-alias-font-mono, ui-monospace, monospace)",
394
+ color: "var(--dsw-alias-label-primary)"
395
+ },
396
+ children: [
397
+ label,
398
+ onRemove === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
+ import_dsh_client_ui_primitives.Button,
400
+ {
401
+ variant: "ghost",
402
+ size: "sm",
403
+ "aria-label": t("removeTag"),
404
+ disabled,
405
+ onClick: onRemove,
406
+ style: {
407
+ padding: 0,
408
+ minWidth: "18px",
409
+ height: "18px",
410
+ lineHeight: 1,
411
+ fontSize: "13px",
412
+ color: "var(--dsw-alias-label-tertiary)"
413
+ },
414
+ children: "\xD7"
415
+ }
416
+ )
417
+ ]
418
+ }
419
+ );
420
+ }
421
+ function TagInput(props) {
422
+ const { t, value, onChange, placeholder, disabled, id } = props;
423
+ const [draft, setDraft] = (0, import_react.useState)("");
424
+ const commit = (raw) => {
425
+ const tag = raw.trim();
426
+ if (tag === "" || value.includes(tag)) return;
427
+ onChange([...value, tag]);
428
+ };
429
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
430
+ "div",
431
+ {
432
+ style: {
433
+ display: "flex",
434
+ flexWrap: "wrap",
435
+ alignItems: "center",
436
+ gap: "6px"
437
+ },
438
+ children: [
439
+ value.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
440
+ Chip,
441
+ {
442
+ t,
443
+ label: tag,
444
+ disabled,
445
+ onRemove: () => onChange(value.filter((item) => item !== tag))
446
+ },
447
+ tag
448
+ )),
449
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
450
+ import_dsh_client_ui_primitives.Input,
451
+ {
452
+ id,
453
+ value: draft,
454
+ disabled,
455
+ placeholder,
456
+ onChange: (event) => setDraft(event.target.value),
457
+ onKeyDown: (event) => {
458
+ if (event.key === " " || event.key === "," || event.key === "Enter") {
459
+ if (event.key === " " || event.key === ",") event.preventDefault();
460
+ commit(draft);
461
+ setDraft("");
462
+ } else if (event.key === "Backspace" && draft === "") {
463
+ const last = value[value.length - 1];
464
+ if (last !== void 0) onChange(value.slice(0, -1));
465
+ }
466
+ },
467
+ onPaste: (event) => {
468
+ const text = event.clipboardData.getData("text");
469
+ if (text === "") return;
470
+ event.preventDefault();
471
+ const tokens = text.split(/[\s,]+/);
472
+ const next = [...value];
473
+ for (const token of tokens) {
474
+ const tag = token.trim();
475
+ if (tag !== "" && !next.includes(tag)) next.push(tag);
476
+ }
477
+ if (next.length !== value.length) onChange(next);
478
+ },
479
+ style: { flex: 1, minWidth: "160px" }
480
+ }
481
+ )
482
+ ]
483
+ }
484
+ );
485
+ }
486
+
487
+ // src/client/container-card-images.tsx
488
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
489
+ var import_react2 = require("react");
490
+ var import_jsx_runtime2 = require("react/jsx-runtime");
491
+ function ImageItem(props) {
492
+ const { t, image, busy, defaultImage, onRemove, onRebuild, onSetDefault } = props;
493
+ const [open, setOpen] = (0, import_react2.useState)(false);
494
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
495
+ import_dsh_client_ui_primitives2.DisclosureRow,
496
+ {
497
+ icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
498
+ title: image.imageId,
499
+ open,
500
+ expandable: true,
501
+ onToggle: () => setOpen(!open),
502
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: wsBody, children: [
503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("table", { style: tableStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tbody", { children: [
504
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
505
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("parent") }),
506
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.parent })
507
+ ] }),
508
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
509
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("imageTag") }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.imageTag })
511
+ ] }),
512
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("builtAt") }),
514
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.builtAt })
515
+ ] }),
516
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("packages") }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.packages.length === 0 ? t("none") : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: image.packages.map((pkg) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chip, { t, label: pkg }, pkg)) }) })
519
+ ] })
520
+ ] }) }),
521
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: actions, children: [
522
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
523
+ ConfirmButton,
524
+ {
525
+ t,
526
+ label: t("rebuildImage"),
527
+ title: t("confirmTitle"),
528
+ description: t("confirmRebuildImage"),
529
+ disabled: busy,
530
+ onConfirm: () => onRebuild(image.imageId)
531
+ }
532
+ ),
533
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
534
+ ConfirmButton,
535
+ {
536
+ t,
537
+ label: t("removeImage"),
538
+ title: t("confirmTitle"),
539
+ description: t("confirmRemoveImage"),
540
+ disabled: busy,
541
+ onConfirm: () => onRemove(image.imageId)
542
+ }
543
+ ),
544
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
545
+ import_dsh_client_ui_primitives2.Button,
546
+ {
547
+ variant: "outline",
548
+ size: "sm",
549
+ disabled: busy || image.imageId === defaultImage,
550
+ onClick: () => onSetDefault(image.imageId),
551
+ children: t("setDefaultImage")
552
+ }
553
+ )
554
+ ] })
555
+ ] })
556
+ }
557
+ );
558
+ }
559
+ function BaseImageRow(props) {
560
+ const { t, image, busy, defaultImage, onRebuild, onPull, onSetDefault } = props;
561
+ const [open, setOpen] = (0, import_react2.useState)(false);
562
+ const pull = image.basePublic && (image.status === "missing" || image.status === "pulled");
563
+ const build = !image.basePublic && image.status === "missing";
564
+ const rebuild = !image.basePublic && image.status === "built";
565
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
566
+ import_dsh_client_ui_primitives2.DisclosureRow,
567
+ {
568
+ icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
569
+ title: image.imageId,
570
+ open,
571
+ expandable: true,
572
+ onToggle: () => setOpen(!open),
573
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: wsBody, children: [
574
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("table", { style: tableStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tbody", { children: [
575
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
576
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("primitive") }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.primitive })
578
+ ] }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("packageManager") }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.packageManager })
582
+ ] }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
584
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("status") }),
585
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.status })
586
+ ] }),
587
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
588
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("builtAt") }),
589
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.builtAt === "" ? t("none") : image.builtAt })
590
+ ] }),
591
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
592
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: thStyle, scope: "row", children: t("packages") }),
593
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tdStyle, children: image.packages.length === 0 ? t("none") : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: image.packages.map((pkg) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chip, { t, label: pkg }, pkg)) }) })
594
+ ] })
595
+ ] }) }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: actions, children: [
597
+ pull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
598
+ import_dsh_client_ui_primitives2.Button,
599
+ {
600
+ variant: "outline",
601
+ size: "sm",
602
+ disabled: busy,
603
+ onClick: () => onPull(image.imageId),
604
+ children: t("pullImage")
605
+ }
606
+ ) : null,
607
+ build ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
608
+ import_dsh_client_ui_primitives2.Button,
609
+ {
610
+ variant: "outline",
611
+ size: "sm",
612
+ disabled: busy,
613
+ onClick: () => onRebuild(image.imageId),
614
+ children: t("build")
615
+ }
616
+ ) : null,
617
+ rebuild ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
618
+ import_dsh_client_ui_primitives2.Button,
619
+ {
620
+ variant: "outline",
621
+ size: "sm",
622
+ disabled: busy,
623
+ onClick: () => onRebuild(image.imageId),
624
+ children: t("rebuildImage")
625
+ }
626
+ ) : null,
627
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
628
+ import_dsh_client_ui_primitives2.Button,
629
+ {
630
+ variant: "outline",
631
+ size: "sm",
632
+ disabled: busy || image.imageId === defaultImage,
633
+ onClick: () => onSetDefault(image.imageId),
634
+ children: t("setDefaultImage")
635
+ }
636
+ )
637
+ ] })
638
+ ] })
639
+ }
640
+ );
641
+ }
642
+ function ImageBuildModal(props) {
643
+ const {
644
+ t,
645
+ images,
646
+ open,
647
+ imageId,
648
+ parent,
649
+ packages,
650
+ onImageId,
651
+ onParent,
652
+ onPackages,
653
+ onClose,
654
+ onBuild
655
+ } = props;
656
+ const canBuild = imageIdPattern.test(imageId) && parent.trim() !== "";
657
+ const imageIdLabel = (0, import_react2.useId)();
658
+ const parentLabel = (0, import_react2.useId)();
659
+ const packagesLabel = (0, import_react2.useId)();
660
+ const baseImages = images.filter((image) => image.isBase);
661
+ const customImages = images.filter((image) => !image.isBase);
662
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
663
+ import_dsh_client_ui_primitives2.Modal,
664
+ {
665
+ open,
666
+ onClose,
667
+ title: t("buildImageTitle"),
668
+ closeLabel: t("cancel"),
669
+ footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
670
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
671
+ import_dsh_client_ui_primitives2.Button,
672
+ {
673
+ variant: "outline",
674
+ size: "sm",
675
+ onClick: onClose,
676
+ children: t("cancel")
677
+ }
678
+ ),
679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
680
+ import_dsh_client_ui_primitives2.Button,
681
+ {
682
+ variant: "primary",
683
+ size: "sm",
684
+ disabled: !canBuild,
685
+ onClick: onBuild,
686
+ children: t("buildImage")
687
+ }
688
+ )
689
+ ] }),
690
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
691
+ "div",
692
+ {
693
+ style: {
694
+ display: "flex",
695
+ flexDirection: "column",
696
+ gap: "12px"
697
+ },
698
+ children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Field, { label: t("imageId"), htmlFor: imageIdLabel, children: [
700
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
701
+ import_dsh_client_ui_primitives2.Input,
702
+ {
703
+ id: imageIdLabel,
704
+ value: imageId,
705
+ onChange: (event) => onImageId(sanitizeImageId(event.target.value))
706
+ }
707
+ ),
708
+ imageId !== "" && !imageIdPattern.test(imageId) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { ...hint, margin: 0 }, children: t("invalidImageId") }) : null
709
+ ] }),
710
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Field, { label: t("parent"), htmlFor: parentLabel, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
711
+ "select",
712
+ {
713
+ id: parentLabel,
714
+ style: imageSelect,
715
+ value: parent,
716
+ onChange: (event) => onParent(event.target.value),
717
+ children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: t("selectImage") }),
719
+ baseImages.map((image) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: image.imageId, children: image.imageId }, image.imageId)),
720
+ customImages.map((image) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: image.imageId, children: image.imageId }, image.imageId))
721
+ ]
722
+ }
723
+ ) }),
724
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Field, { label: t("packages"), htmlFor: packagesLabel, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
725
+ TagInput,
726
+ {
727
+ id: packagesLabel,
728
+ t,
729
+ value: packages,
730
+ onChange: onPackages
731
+ }
732
+ ) })
733
+ ]
734
+ }
735
+ )
736
+ }
737
+ );
738
+ }
739
+
740
+ // src/client/container-card-caches.tsx
741
+ var import_jsx_runtime3 = require("react/jsx-runtime");
742
+ function formatBytes(bytes) {
743
+ if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
744
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
745
+ let value = bytes;
746
+ let unit = 0;
747
+ while (value >= 1024 && unit < units.length - 1) {
748
+ value /= 1024;
749
+ unit += 1;
750
+ }
751
+ return `${unit === 0 ? String(value) : value.toFixed(1)} ${units[unit]}`;
752
+ }
753
+ function CachesSection(props) {
754
+ const { t, caches, busy, onClean } = props;
755
+ const disabled = busy || caches.length === 0;
756
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
757
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: sectionTitle, children: t("cachesTitle") }),
758
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: wsBody, children: [
759
+ caches.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { ...hint, margin: 0 }, children: t("noCaches") }) : caches.map((cache) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
760
+ "div",
761
+ {
762
+ style: {
763
+ display: "flex",
764
+ flexWrap: "wrap",
765
+ alignItems: "center",
766
+ gap: "8px"
767
+ },
768
+ children: [
769
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { style: { color: "var(--dsw-alias-label-primary)" }, children: cache.manager }),
770
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: hint, children: t("cacheUsage", { size: formatBytes(cache.bytes), n: cache.files }) })
771
+ ]
772
+ },
773
+ cache.manager
774
+ )),
775
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
777
+ ConfirmButton,
778
+ {
779
+ t,
780
+ label: t("cacheKeepLatest"),
781
+ title: t("confirmTitle"),
782
+ description: t("confirmCacheKeepLatest"),
783
+ disabled,
784
+ onConfirm: () => onClean("keep-latest")
785
+ }
786
+ ),
787
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
788
+ ConfirmButton,
789
+ {
790
+ t,
791
+ label: t("cacheRemoveAll"),
792
+ title: t("confirmTitle"),
793
+ description: t("confirmCacheRemoveAll"),
794
+ disabled,
795
+ onConfirm: () => onClean("all")
796
+ }
797
+ )
798
+ ] })
799
+ ] })
800
+ ] });
801
+ }
802
+
803
+ // src/client/container-card-secrets.tsx
804
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
805
+ var import_react3 = require("react");
806
+ var import_jsx_runtime4 = require("react/jsx-runtime");
807
+ function SecretRow(props) {
808
+ const { t, name: name2, busy, writable, onSet, onRemove } = props;
809
+ const [content, setContent] = (0, import_react3.useState)("");
810
+ const canSave = content !== "" && !busy;
811
+ const submit = () => {
812
+ if (content === "") return;
813
+ onSet(name2, content);
814
+ setContent("");
815
+ };
816
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
817
+ "div",
818
+ {
819
+ style: {
820
+ display: "flex",
821
+ flexWrap: "wrap",
822
+ alignItems: "center",
823
+ gap: "8px"
824
+ },
825
+ children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
827
+ "code",
828
+ {
829
+ style: {
830
+ ...greyId,
831
+ flex: 1,
832
+ fontSize: "13px",
833
+ color: "var(--dsw-alias-label-primary)"
834
+ },
835
+ children: name2
836
+ }
837
+ ),
838
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
839
+ import_dsh_client_ui_primitives3.Input,
840
+ {
841
+ type: "password",
842
+ value: content,
843
+ disabled: !writable || busy,
844
+ placeholder: t("setSecret"),
845
+ onChange: (event) => setContent(event.target.value),
846
+ onKeyDown: (event) => {
847
+ if (event.key === "Enter") submit();
848
+ },
849
+ style: { width: "200px" }
850
+ }
851
+ ),
852
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
853
+ ConfirmButton,
854
+ {
855
+ t,
856
+ label: t("setSecret"),
857
+ title: t("confirmTitle"),
858
+ description: t("confirmSetSecret"),
859
+ disabled: !writable || !canSave,
860
+ onConfirm: submit
861
+ }
862
+ ),
863
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
864
+ ConfirmButton,
865
+ {
866
+ t,
867
+ label: t("removeSecret"),
868
+ title: t("confirmTitle"),
869
+ description: t("confirmRemoveSecret"),
870
+ disabled: busy,
871
+ onConfirm: () => onRemove(name2)
872
+ }
873
+ )
874
+ ]
875
+ }
876
+ );
877
+ }
878
+ function SecretsSection(props) {
879
+ const { t, secrets, busy, writable, onCreate, onRemove, onSet } = props;
880
+ const [open, setOpen] = (0, import_react3.useState)(false);
881
+ const [openSecret, setOpenSecret] = (0, import_react3.useState)(null);
882
+ const [name2, setName] = (0, import_react3.useState)("");
883
+ const [length, setLength] = (0, import_react3.useState)("32");
884
+ const [charset, setCharset] = (0, import_react3.useState)("alphanumeric");
885
+ const secretNameId = (0, import_react3.useId)();
886
+ const secretLengthId = (0, import_react3.useId)();
887
+ const secretCharsetId = (0, import_react3.useId)();
888
+ const canCreate = namePattern.test(name2);
889
+ const submit = () => {
890
+ if (!namePattern.test(name2)) return;
891
+ const parsedLength = parseInt(length, 10);
892
+ const normalized = length.trim() === "" || Number.isNaN(parsedLength) || parsedLength < 1 ? void 0 : parsedLength;
893
+ onCreate(name2.trim(), normalized, charset);
894
+ setName("");
895
+ setLength("32");
896
+ setCharset("alphanumeric");
897
+ setOpen(false);
898
+ };
899
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { children: [
900
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
901
+ "div",
902
+ {
903
+ style: {
904
+ display: "flex",
905
+ flexWrap: "wrap",
906
+ alignItems: "center",
907
+ gap: "8px"
908
+ },
909
+ children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { ...sectionTitle, flex: 1 }, children: t("secretsTitle") }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
912
+ import_dsh_client_ui_primitives3.Button,
913
+ {
914
+ variant: "outline",
915
+ size: "sm",
916
+ disabled: !writable || busy,
917
+ onClick: () => setOpen(true),
918
+ children: t("createSecret")
919
+ }
920
+ )
921
+ ]
922
+ }
923
+ ),
924
+ secrets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: hint, children: t("none") }) : secrets.map((secret) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
925
+ import_dsh_client_ui_primitives3.DisclosureRow,
926
+ {
927
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", {}),
928
+ title: secret.name,
929
+ open: openSecret === secret.name,
930
+ expandable: true,
931
+ onToggle: () => setOpenSecret(openSecret === secret.name ? null : secret.name),
932
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: wsBody, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
933
+ SecretRow,
934
+ {
935
+ t,
936
+ name: secret.name,
937
+ busy,
938
+ writable,
939
+ onSet,
940
+ onRemove
941
+ }
942
+ ) })
943
+ },
944
+ secret.name
945
+ )),
946
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
947
+ import_dsh_client_ui_primitives3.Modal,
948
+ {
949
+ open,
950
+ onClose: () => setOpen(false),
951
+ title: t("secretsTitle"),
952
+ closeLabel: t("cancel"),
953
+ footer: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
954
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
955
+ import_dsh_client_ui_primitives3.Button,
956
+ {
957
+ variant: "outline",
958
+ size: "sm",
959
+ onClick: () => setOpen(false),
960
+ children: t("cancel")
961
+ }
962
+ ),
963
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
964
+ import_dsh_client_ui_primitives3.Button,
965
+ {
966
+ variant: "primary",
967
+ size: "sm",
968
+ disabled: !canCreate,
969
+ onClick: submit,
970
+ children: t("createSecret")
971
+ }
972
+ )
973
+ ] }),
974
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
975
+ "div",
976
+ {
977
+ style: {
978
+ display: "flex",
979
+ flexDirection: "column",
980
+ gap: "12px"
981
+ },
982
+ children: [
983
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Field, { label: t("secretName"), htmlFor: secretNameId, children: [
984
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
985
+ import_dsh_client_ui_primitives3.Input,
986
+ {
987
+ id: secretNameId,
988
+ value: name2,
989
+ disabled: !writable || busy,
990
+ autoFocus: true,
991
+ onChange: (event) => setName(sanitizeName(event.target.value)),
992
+ onKeyDown: (event) => {
993
+ if (event.key === "Enter") submit();
994
+ }
995
+ }
996
+ ),
997
+ name2 !== "" && !namePattern.test(name2) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { ...hint, margin: 0 }, children: t("invalidName") }) : null
998
+ ] }),
999
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Field, { label: t("secretLength"), htmlFor: secretLengthId, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1000
+ import_dsh_client_ui_primitives3.Input,
1001
+ {
1002
+ id: secretLengthId,
1003
+ type: "number",
1004
+ min: 1,
1005
+ max: 1024,
1006
+ value: length,
1007
+ disabled: !writable || busy,
1008
+ onChange: (event) => setLength(event.target.value)
1009
+ }
1010
+ ) }),
1011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Field, { label: t("secretCharset"), htmlFor: secretCharsetId, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1012
+ "select",
1013
+ {
1014
+ id: secretCharsetId,
1015
+ style: imageSelect,
1016
+ value: charset,
1017
+ disabled: !writable || busy,
1018
+ onChange: (event) => setCharset(event.target.value),
1019
+ children: [
1020
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "alphanumeric", children: "alphanumeric" }),
1021
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "hex", children: "hex" }),
1022
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "base64url", children: "base64url" })
1023
+ ]
1024
+ }
1025
+ ) })
1026
+ ]
1027
+ }
1028
+ )
1029
+ }
1030
+ )
1031
+ ] });
1032
+ }
1033
+
1034
+ // src/client/container-card-volumes.tsx
1035
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
1036
+ var import_react4 = require("react");
1037
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1038
+ function VolumesSection(props) {
1039
+ const { t, volumes, busy, writable, onCreate, onRemove } = props;
1040
+ const [open, setOpen] = (0, import_react4.useState)(false);
1041
+ const [openVolume, setOpenVolume] = (0, import_react4.useState)(null);
1042
+ const [name2, setName] = (0, import_react4.useState)("");
1043
+ const volumeId = (0, import_react4.useId)();
1044
+ const canCreate = namePattern.test(name2);
1045
+ const submit = () => {
1046
+ if (!namePattern.test(name2)) return;
1047
+ onCreate(name2.trim());
1048
+ setName("");
1049
+ setOpen(false);
1050
+ };
1051
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
1052
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1053
+ "div",
1054
+ {
1055
+ style: {
1056
+ display: "flex",
1057
+ flexWrap: "wrap",
1058
+ alignItems: "center",
1059
+ gap: "8px"
1060
+ },
1061
+ children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...sectionTitle, flex: 1 }, children: t("volumesTitle") }),
1063
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1064
+ import_dsh_client_ui_primitives4.Button,
1065
+ {
1066
+ variant: "outline",
1067
+ size: "sm",
1068
+ disabled: !writable || busy,
1069
+ onClick: () => setOpen(true),
1070
+ children: t("createVolume")
1071
+ }
1072
+ )
1073
+ ]
1074
+ }
1075
+ ),
1076
+ volumes.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: hint, children: t("none") }) : volumes.map((volume) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1077
+ import_dsh_client_ui_primitives4.DisclosureRow,
1078
+ {
1079
+ icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
1080
+ title: volume.name,
1081
+ open: openVolume === volume.name,
1082
+ expandable: true,
1083
+ onToggle: () => setOpenVolume(openVolume === volume.name ? null : volume.name),
1084
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: wsBody, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1085
+ "div",
1086
+ {
1087
+ style: {
1088
+ display: "flex",
1089
+ flexWrap: "wrap",
1090
+ alignItems: "center",
1091
+ gap: "8px"
1092
+ },
1093
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1094
+ ConfirmButton,
1095
+ {
1096
+ t,
1097
+ label: t("removeVolume"),
1098
+ title: t("confirmTitle"),
1099
+ description: t("confirmRemoveVolume"),
1100
+ disabled: busy,
1101
+ onConfirm: () => onRemove(volume.name)
1102
+ }
1103
+ )
1104
+ }
1105
+ ) })
1106
+ },
1107
+ volume.name
1108
+ )),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1110
+ import_dsh_client_ui_primitives4.Modal,
1111
+ {
1112
+ open,
1113
+ onClose: () => setOpen(false),
1114
+ title: t("volumesTitle"),
1115
+ closeLabel: t("cancel"),
1116
+ footer: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1117
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1118
+ import_dsh_client_ui_primitives4.Button,
1119
+ {
1120
+ variant: "outline",
1121
+ size: "sm",
1122
+ onClick: () => setOpen(false),
1123
+ children: t("cancel")
1124
+ }
1125
+ ),
1126
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1127
+ import_dsh_client_ui_primitives4.Button,
1128
+ {
1129
+ variant: "primary",
1130
+ size: "sm",
1131
+ disabled: !canCreate,
1132
+ onClick: submit,
1133
+ children: t("createVolume")
1134
+ }
1135
+ )
1136
+ ] }),
1137
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Field, { label: t("volumeName"), htmlFor: volumeId, children: [
1138
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1139
+ import_dsh_client_ui_primitives4.Input,
1140
+ {
1141
+ id: volumeId,
1142
+ value: name2,
1143
+ disabled: !writable || busy,
1144
+ autoFocus: true,
1145
+ onChange: (event) => setName(sanitizeName(event.target.value)),
1146
+ onKeyDown: (event) => {
1147
+ if (event.key === "Enter") submit();
1148
+ }
1149
+ }
1150
+ ),
1151
+ name2 !== "" && !namePattern.test(name2) ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { ...hint, margin: 0 }, children: t("invalidName") }) : null
1152
+ ] })
1153
+ }
1154
+ )
1155
+ ] });
1156
+ }
1157
+
1158
+ // src/client/container-card-directory-styles.ts
1159
+ var DIRECTORY_CLASS = "dsh-podman-directory";
1160
+ var DIRECTORY_STYLES = `
1161
+ .dsh-podman-directory.dsh-podman-directory {
1162
+ width: min(680px, 100%);
1163
+ height: min(500px, calc(100dvh - 32px));
1164
+ padding: 0;
1165
+ gap: 0;
1166
+ --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
1167
+ --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
1168
+ }
1169
+ .dsh-podman-directory-scope {
1170
+ display: contents;
1171
+ }
1172
+ .dsh-podman-directory-header {
1173
+ display: flex;
1174
+ flex-direction: column;
1175
+ flex: none;
1176
+ gap: 8px;
1177
+ padding: 16px 14px 8px 24px;
1178
+ border-bottom: 0.5px solid var(--dsw-alias-border-l3);
1179
+ }
1180
+ .dsh-podman-directory-title {
1181
+ margin: 0;
1182
+ min-height: 28px;
1183
+ font-size: 16px;
1184
+ line-height: 24px;
1185
+ font-weight: 510;
1186
+ color: var(--dsw-alias-label-primary);
1187
+ }
1188
+ .dsh-podman-directory-crumbbar {
1189
+ display: flex;
1190
+ align-items: center;
1191
+ gap: 4px;
1192
+ box-sizing: border-box;
1193
+ min-height: 24px;
1194
+ margin-left: -9px;
1195
+ padding: 0 8px;
1196
+ border: 1px solid transparent;
1197
+ border-radius: 8px;
1198
+ }
1199
+ .dsh-podman-directory-crumbs {
1200
+ display: flex;
1201
+ align-items: center;
1202
+ gap: 4px;
1203
+ flex: 0 1 auto;
1204
+ min-width: 0;
1205
+ overflow-x: auto;
1206
+ scrollbar-width: none;
1207
+ }
1208
+ .dsh-podman-directory-crumbseat {
1209
+ display: inline-flex;
1210
+ align-items: center;
1211
+ gap: 4px;
1212
+ flex: none;
1213
+ min-width: 0;
1214
+ }
1215
+ .dsh-podman-directory-crumb {
1216
+ border: none;
1217
+ background: transparent;
1218
+ padding: 0;
1219
+ max-width: 160px;
1220
+ overflow: hidden;
1221
+ text-overflow: ellipsis;
1222
+ white-space: nowrap;
1223
+ font-size: 13px;
1224
+ line-height: 20px;
1225
+ font-weight: 500;
1226
+ color: var(--dsw-alias-label-tertiary);
1227
+ cursor: pointer;
1228
+ }
1229
+ .dsh-podman-directory-crumb:hover {
1230
+ color: var(--dsw-alias-label-primary);
1231
+ }
1232
+ .dsh-podman-directory-crumb:disabled {
1233
+ cursor: default;
1234
+ color: var(--dsw-alias-label-caption);
1235
+ }
1236
+ .dsh-podman-directory-crumbchevron {
1237
+ flex: none;
1238
+ color: var(--dsw-alias-label-tertiary);
1239
+ }
1240
+ .dsh-podman-directory-content {
1241
+ display: flex;
1242
+ flex-direction: column;
1243
+ flex: 1 1 0;
1244
+ min-height: 0;
1245
+ position: relative;
1246
+ padding: 16px 16px 16px 24px;
1247
+ }
1248
+ .dsh-podman-directory-miller {
1249
+ display: flex;
1250
+ align-items: stretch;
1251
+ flex: 1 1 0;
1252
+ min-height: 0;
1253
+ gap: 12px;
1254
+ overflow-x: auto;
1255
+ scrollbar-width: none;
1256
+ }
1257
+ .dsh-podman-directory-column {
1258
+ display: flex;
1259
+ flex-direction: column;
1260
+ gap: 2px;
1261
+ flex: 1 1 0;
1262
+ min-width: 256px;
1263
+ margin: 0;
1264
+ list-style: none;
1265
+ overflow-y: auto;
1266
+ padding-right: 8px;
1267
+ }
1268
+ .dsh-podman-directory-divider {
1269
+ flex: none;
1270
+ width: 0.5px;
1271
+ background: var(--dsw-alias-border-l3);
1272
+ }
1273
+ .dsh-podman-directory-row {
1274
+ width: 100%;
1275
+ display: flex;
1276
+ align-items: center;
1277
+ gap: 4px;
1278
+ height: 28px;
1279
+ flex: none;
1280
+ padding: 4px;
1281
+ border: none;
1282
+ border-radius: 6px;
1283
+ background: transparent;
1284
+ text-align: left;
1285
+ cursor: pointer;
1286
+ }
1287
+ .dsh-podman-directory-seat {
1288
+ display: flex;
1289
+ flex: none;
1290
+ }
1291
+ .dsh-podman-directory-row:hover:not(:disabled) {
1292
+ background: var(--dsw-alias-interactive-bg-hover);
1293
+ }
1294
+ .dsh-podman-directory-row-selected,
1295
+ .dsh-podman-directory-row-selected:hover:not(:disabled) {
1296
+ background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover));
1297
+ }
1298
+ .dsh-podman-directory-row:disabled {
1299
+ cursor: default;
1300
+ }
1301
+ .dsh-podman-directory-rowicon {
1302
+ flex: none;
1303
+ color: var(--dsw-alias-label-secondary);
1304
+ }
1305
+ .dsh-podman-directory-rowicon-selected {
1306
+ flex: none;
1307
+ color: var(--dsw-alias-button-info-fill);
1308
+ }
1309
+ .dsh-podman-directory-rowname {
1310
+ flex: 1 1 0;
1311
+ min-width: 0;
1312
+ overflow: hidden;
1313
+ text-overflow: ellipsis;
1314
+ white-space: nowrap;
1315
+ font-size: 13px;
1316
+ line-height: 20px;
1317
+ font-weight: 500;
1318
+ color: var(--dsw-alias-label-primary);
1319
+ }
1320
+ .dsh-podman-directory-rowchevron {
1321
+ flex: none;
1322
+ color: var(--dsw-alias-label-tertiary);
1323
+ }
1324
+ .dsh-podman-directory-status,
1325
+ .dsh-podman-directory-error {
1326
+ margin: 0;
1327
+ padding: 4px;
1328
+ font-size: 12px;
1329
+ line-height: 18px;
1330
+ }
1331
+ .dsh-podman-directory-status {
1332
+ color: var(--dsw-alias-label-secondary);
1333
+ }
1334
+ .dsh-podman-directory-error {
1335
+ color: var(--dsw-alias-state-error-primary);
1336
+ }
1337
+ .dsh-podman-directory-loading {
1338
+ position: absolute;
1339
+ right: 16px;
1340
+ bottom: 8px;
1341
+ padding: 2px 8px;
1342
+ font-size: 12px;
1343
+ line-height: 18px;
1344
+ color: var(--dsw-alias-label-secondary);
1345
+ background: var(--dsw-alias-bg-layer-2);
1346
+ }
1347
+ .dsh-podman-directory-footer {
1348
+ display: flex;
1349
+ align-items: center;
1350
+ flex-wrap: wrap;
1351
+ gap: 8px;
1352
+ flex: none;
1353
+ padding: 16px 24px;
1354
+ border-top: 0.5px solid var(--dsw-alias-border-l3);
1355
+ }
1356
+ .dsh-podman-directory-toggle {
1357
+ display: inline-flex;
1358
+ align-items: center;
1359
+ gap: 4px;
1360
+ padding: 0;
1361
+ border: none;
1362
+ background: transparent;
1363
+ font-size: 13px;
1364
+ line-height: 20px;
1365
+ font-weight: 500;
1366
+ color: var(--dsw-alias-label-secondary);
1367
+ cursor: pointer;
1368
+ }
1369
+ .dsh-podman-directory-toggle[aria-pressed="true"] {
1370
+ color: var(--dsw-alias-label-primary);
1371
+ }
1372
+ .dsh-podman-directory-toggle:disabled {
1373
+ cursor: default;
1374
+ color: var(--dsw-alias-label-caption);
1375
+ }
1376
+ .dsh-podman-directory-gap {
1377
+ flex: 1 1 0;
1378
+ }
1379
+ .dsh-podman-directory-action {
1380
+ min-width: 72px;
1381
+ }
1382
+ `;
1383
+ function installDirectoryStyles(ctx) {
1384
+ if (typeof document === "undefined") return;
1385
+ ctx.effect(() => {
1386
+ const tag = document.createElement("style");
1387
+ tag.dataset.plugin = "@exagone313/dsh-podman";
1388
+ tag.textContent = DIRECTORY_STYLES;
1389
+ document.head.appendChild(tag);
1390
+ return () => {
1391
+ tag.remove();
1392
+ };
1393
+ }, "podman: directory styles");
1394
+ }
1395
+
1396
+ // src/project-path.ts
1397
+ function projectNameFromHostPath(projectsRoot, path) {
1398
+ const root = stripTrailingSlash(projectsRoot);
1399
+ const target = stripTrailingSlash(path);
1400
+ if (root === "" || target === "" || target === root) return void 0;
1401
+ if (!target.startsWith(`${root}/`)) return void 0;
1402
+ return target.slice(root.length + 1);
1403
+ }
1404
+ function hostPathForProjectName(projectsRoot, project) {
1405
+ const root = stripTrailingSlash(projectsRoot);
1406
+ const name2 = stripTrailingSlash(project).replace(/^\/+/, "");
1407
+ return name2 === "" ? root : `${root}/${name2}`;
1408
+ }
1409
+ function stripTrailingSlash(value) {
1410
+ return String(value ?? "").replace(/\/+$/, "");
1411
+ }
1412
+ function confineToRoot(root, path) {
1413
+ const normalizedRoot = stripTrailingSlash(root);
1414
+ const normalizedPath = stripTrailingSlash(path);
1415
+ if (normalizedRoot === "" || normalizedPath === normalizedRoot) {
1416
+ return normalizedRoot;
1417
+ }
1418
+ return normalizedPath.startsWith(`${normalizedRoot}/`) ? normalizedPath : normalizedRoot;
1419
+ }
1420
+ function rootCrumbs(root, path) {
1421
+ const normalizedRoot = stripTrailingSlash(root);
1422
+ const prefix = `${normalizedRoot}/`;
1423
+ if (normalizedRoot === "" || !path.startsWith(prefix)) return [];
1424
+ const crumbs = [];
1425
+ let accumulated = normalizedRoot;
1426
+ for (const segment of path.slice(prefix.length).split("/")) {
1427
+ if (segment === "") continue;
1428
+ accumulated = `${accumulated}/${segment}`;
1429
+ crumbs.push(accumulated);
1430
+ }
1431
+ return crumbs;
1432
+ }
1433
+ function crumbLabel(path) {
1434
+ const trimmed = stripTrailingSlash(path);
1435
+ const name2 = trimmed.slice(trimmed.lastIndexOf("/") + 1);
1436
+ return name2 === "" ? trimmed : name2;
1437
+ }
1438
+
1439
+ // src/client/container-card-directory.tsx
1440
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
1441
+ var import_react5 = require("react");
1442
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1443
+ var SLOW_SCAN_DELAY_MS = 300;
1444
+ function DirectoryPickerModal(props) {
1445
+ const { t, open, root, start, picker, onSelect, onClose } = props;
1446
+ const [path, setPath] = (0, import_react5.useState)(() => confineToRoot(root, start));
1447
+ const [level, setLevel] = (0, import_react5.useState)(void 0);
1448
+ const [selected, setSelected] = (0, import_react5.useState)(null);
1449
+ const [child, setChild] = (0, import_react5.useState)(void 0);
1450
+ const [showHidden, setShowHidden] = (0, import_react5.useState)(false);
1451
+ const [error, setError] = (0, import_react5.useState)("");
1452
+ const [busy, setBusy] = (0, import_react5.useState)(false);
1453
+ const [slow, setSlow] = (0, import_react5.useState)(false);
1454
+ const tRef = (0, import_react5.useRef)(t);
1455
+ tRef.current = t;
1456
+ const trailRef = (0, import_react5.useRef)(null);
1457
+ (0, import_react5.useEffect)(() => {
1458
+ if (!open) return;
1459
+ setPath(confineToRoot(root, start));
1460
+ setSelected(null);
1461
+ setShowHidden(false);
1462
+ }, [open, root, start]);
1463
+ (0, import_react5.useEffect)(() => {
1464
+ if (!open) return;
1465
+ const controller = new AbortController();
1466
+ let cancelled = false;
1467
+ setBusy(true);
1468
+ setSlow(false);
1469
+ const timer = setTimeout(() => {
1470
+ if (!cancelled) setSlow(true);
1471
+ }, SLOW_SCAN_DELAY_MS);
1472
+ picker.list(path, controller.signal).then((listing) => {
1473
+ if (cancelled) return;
1474
+ setLevel(toLevel(listing));
1475
+ setError("");
1476
+ }).catch((failure2) => {
1477
+ if (cancelled) return;
1478
+ const code = failure2?.code;
1479
+ setLevel(void 0);
1480
+ setError(
1481
+ code === "directory-picker/unavailable" ? tRef.current("browseUnavailable") : tRef.current("browseError")
1482
+ );
1483
+ }).finally(() => {
1484
+ if (cancelled) return;
1485
+ clearTimeout(timer);
1486
+ setSlow(false);
1487
+ setBusy(false);
1488
+ });
1489
+ return () => {
1490
+ cancelled = true;
1491
+ clearTimeout(timer);
1492
+ controller.abort();
1493
+ };
1494
+ }, [open, path, picker]);
1495
+ (0, import_react5.useEffect)(() => {
1496
+ if (!open || selected === null) {
1497
+ setChild(void 0);
1498
+ return;
1499
+ }
1500
+ const controller = new AbortController();
1501
+ let cancelled = false;
1502
+ setBusy(true);
1503
+ picker.list(selected.path, controller.signal).then((listing) => {
1504
+ if (!cancelled) setChild(toLevel(listing));
1505
+ }).catch(() => {
1506
+ if (!cancelled) setChild(void 0);
1507
+ }).finally(() => {
1508
+ if (!cancelled) setBusy(false);
1509
+ });
1510
+ return () => {
1511
+ cancelled = true;
1512
+ controller.abort();
1513
+ };
1514
+ }, [open, selected, picker]);
1515
+ const select = (entry) => {
1516
+ setSelected(entry);
1517
+ };
1518
+ const advance = (entry) => {
1519
+ if (selected !== null) setPath(selected.path);
1520
+ setSelected(entry);
1521
+ };
1522
+ const navigate = (target) => {
1523
+ setPath(confineToRoot(root, target));
1524
+ setSelected(null);
1525
+ };
1526
+ (0, import_react5.useEffect)(() => {
1527
+ const trail = trailRef.current;
1528
+ if (trail !== null) trail.scrollLeft = trail.scrollWidth;
1529
+ }, [path, open]);
1530
+ const crumbs = rootCrumbs(root, path);
1531
+ const visible = (entries) => entries.filter((entry) => showHidden || !entry.hidden);
1532
+ const truncated = level?.truncated === true || child?.truncated === true;
1533
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1534
+ import_dsh_client_ui_primitives5.Modal,
1535
+ {
1536
+ open,
1537
+ onClose,
1538
+ title: t("browseTitle"),
1539
+ className: DIRECTORY_CLASS,
1540
+ headless: true,
1541
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-podman-directory-scope", children: [
1542
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-podman-directory-header", children: [
1543
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "dsh-podman-directory-title", children: t("browseTitle") }),
1544
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-podman-directory-crumbbar", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1545
+ "nav",
1546
+ {
1547
+ ref: trailRef,
1548
+ className: "dsh-podman-directory-crumbs",
1549
+ "aria-label": t("browseTitle"),
1550
+ children: [
1551
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-podman-directory-crumbseat", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1552
+ "button",
1553
+ {
1554
+ type: "button",
1555
+ className: "dsh-podman-directory-crumb",
1556
+ disabled: busy,
1557
+ onClick: () => navigate(root),
1558
+ children: crumbLabel(root)
1559
+ }
1560
+ ) }),
1561
+ crumbs.map((crumb) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-podman-directory-crumbseat", children: [
1562
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1563
+ import_dsh_client_ui_primitives5.IconChevronRightOutline14,
1564
+ {
1565
+ size: 12,
1566
+ className: "dsh-podman-directory-crumbchevron"
1567
+ }
1568
+ ),
1569
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1570
+ "button",
1571
+ {
1572
+ type: "button",
1573
+ className: "dsh-podman-directory-crumb",
1574
+ disabled: busy,
1575
+ onClick: () => navigate(crumb),
1576
+ children: crumbLabel(crumb)
1577
+ }
1578
+ )
1579
+ ] }, crumb))
1580
+ ]
1581
+ }
1582
+ ) })
1583
+ ] }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-podman-directory-content", children: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-podman-directory-miller", children: [
1586
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "dsh-podman-directory-column", children: (level?.entries ?? []).length === 0 ? null : visible(level?.entries ?? []).map((entry) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1587
+ DirectoryRow,
1588
+ {
1589
+ entry,
1590
+ selected: selected?.path === entry.path,
1591
+ busy,
1592
+ onPick: select
1593
+ },
1594
+ entry.path
1595
+ )) }),
1596
+ selected === null ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1597
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-podman-directory-divider" }),
1598
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "dsh-podman-directory-column", children: visible(child?.entries ?? []).map((entry) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1599
+ DirectoryRow,
1600
+ {
1601
+ entry,
1602
+ selected: false,
1603
+ busy,
1604
+ onPick: advance
1605
+ },
1606
+ entry.path
1607
+ )) })
1608
+ ] })
1609
+ ] }),
1610
+ error === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dsh-podman-directory-error", role: "alert", children: error }),
1611
+ error === "" && truncated ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dsh-podman-directory-status", role: "status", children: t("browseTruncated") }) : null,
1612
+ slow ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-podman-directory-loading", role: "status", children: t("browseLoading") }) : null
1613
+ ] }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-podman-directory-footer", children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1616
+ "button",
1617
+ {
1618
+ type: "button",
1619
+ className: "dsh-podman-directory-toggle",
1620
+ "aria-pressed": showHidden,
1621
+ disabled: busy,
1622
+ onClick: () => setShowHidden((previous) => !previous),
1623
+ children: [
1624
+ t("browseHidden"),
1625
+ showHidden ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives5.IconCheckOutline16, { size: 14 }) : null
1626
+ ]
1627
+ }
1628
+ ),
1629
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-podman-directory-gap" }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1631
+ import_dsh_client_ui_primitives5.Button,
1632
+ {
1633
+ variant: "outline",
1634
+ className: "dsh-podman-directory-action",
1635
+ disabled: busy,
1636
+ onClick: onClose,
1637
+ children: t("cancel")
1638
+ }
1639
+ ),
1640
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1641
+ import_dsh_client_ui_primitives5.Button,
1642
+ {
1643
+ variant: "primary",
1644
+ className: "dsh-podman-directory-action",
1645
+ disabled: busy || error !== "",
1646
+ onClick: () => onSelect(selected?.path ?? path),
1647
+ children: t("browseSelect")
1648
+ }
1649
+ )
1650
+ ] })
1651
+ ] })
1652
+ }
1653
+ );
1654
+ }
1655
+ function DirectoryRow(props) {
1656
+ const { entry, selected, busy, onPick } = props;
1657
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { className: "dsh-podman-directory-seat", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1658
+ "button",
1659
+ {
1660
+ type: "button",
1661
+ className: selected ? "dsh-podman-directory-row dsh-podman-directory-row-selected" : "dsh-podman-directory-row",
1662
+ "aria-current": selected ? true : void 0,
1663
+ disabled: busy,
1664
+ onClick: () => onPick(entry),
1665
+ children: [
1666
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1667
+ import_dsh_client_ui_primitives5.IconFolderOpen16,
1668
+ {
1669
+ size: 16,
1670
+ className: "dsh-podman-directory-rowicon-selected"
1671
+ }
1672
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives5.IconFolderClose16, { size: 16, className: "dsh-podman-directory-rowicon" }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-podman-directory-rowname", children: entry.name }),
1674
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1675
+ import_dsh_client_ui_primitives5.IconChevronRightOutline14,
1676
+ {
1677
+ size: 12,
1678
+ className: "dsh-podman-directory-rowchevron"
1679
+ }
1680
+ )
1681
+ ]
1682
+ }
1683
+ ) });
1684
+ }
1685
+ function toLevel(listing) {
1686
+ return {
1687
+ entries: listing.entries ?? [],
1688
+ truncated: listing.truncated === true
1689
+ };
1690
+ }
1691
+
1692
+ // src/mount-enums.ts
1693
+ function forcedMountMode(kind) {
1694
+ if (kind === "tmpfs") return "read_write";
1695
+ if (kind === "secret") return "read_only";
1696
+ return void 0;
1697
+ }
1698
+
1699
+ // src/client/container-card-editors.tsx
1700
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
1701
+ var import_react6 = require("react");
1702
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1703
+ function EnvEditor(props) {
1704
+ const { t, env, busy, onChange } = props;
1705
+ const entries = Object.entries(env);
1706
+ const updateKey = (oldKey, key, value) => {
1707
+ const next = {};
1708
+ for (const [k, v] of entries) {
1709
+ if (k !== oldKey) next[k] = v;
1710
+ }
1711
+ next[key] = value;
1712
+ onChange(next);
1713
+ };
1714
+ const updateValue = (key, value) => {
1715
+ onChange({ ...env, [key]: value });
1716
+ };
1717
+ const remove = (key) => {
1718
+ const next = { ...env };
1719
+ delete next[key];
1720
+ onChange(next);
1721
+ };
1722
+ const add = () => {
1723
+ onChange({ ...env, "": "" });
1724
+ };
1725
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
1726
+ entries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1727
+ "div",
1728
+ {
1729
+ style: {
1730
+ display: "flex",
1731
+ flexWrap: "wrap",
1732
+ alignItems: "center",
1733
+ gap: "8px"
1734
+ },
1735
+ children: [
1736
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1737
+ import_dsh_client_ui_primitives6.Input,
1738
+ {
1739
+ value: key,
1740
+ disabled: busy,
1741
+ placeholder: t("envKey"),
1742
+ "aria-label": t("envKey"),
1743
+ onChange: (event) => updateKey(key, event.target.value, value),
1744
+ style: { width: "160px" }
1745
+ }
1746
+ ),
1747
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1748
+ import_dsh_client_ui_primitives6.Input,
1749
+ {
1750
+ value,
1751
+ disabled: busy,
1752
+ placeholder: t("envValue"),
1753
+ "aria-label": t("envValue"),
1754
+ onChange: (event) => updateValue(key, event.target.value),
1755
+ style: { width: "200px" }
1756
+ }
1757
+ ),
1758
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1759
+ import_dsh_client_ui_primitives6.Button,
1760
+ {
1761
+ variant: "outline",
1762
+ size: "sm",
1763
+ disabled: busy,
1764
+ onClick: () => remove(key),
1765
+ children: t("removeEnv")
1766
+ }
1767
+ )
1768
+ ]
1769
+ },
1770
+ key
1771
+ )),
1772
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1773
+ import_dsh_client_ui_primitives6.Button,
1774
+ {
1775
+ variant: "outline",
1776
+ size: "sm",
1777
+ disabled: busy,
1778
+ onClick: add,
1779
+ children: t("addEnv")
1780
+ }
1781
+ ) })
1782
+ ] });
1783
+ }
1784
+ function MountsEditor(props) {
1785
+ const {
1786
+ t,
1787
+ mounts,
1788
+ volumes,
1789
+ secrets,
1790
+ busy,
1791
+ enabled,
1792
+ projectsRoot,
1793
+ directoryPicker,
1794
+ confirmRemove,
1795
+ modeControl = "remount",
1796
+ primaryProject = "",
1797
+ onAdd,
1798
+ onRemove,
1799
+ onUpdate
1800
+ } = props;
1801
+ const [adding, setAdding] = (0, import_react6.useState)(false);
1802
+ const [browsing, setBrowsing] = (0, import_react6.useState)(false);
1803
+ const [browseError, setBrowseError] = (0, import_react6.useState)("");
1804
+ const [draft, setDraft] = (0, import_react6.useState)(emptyMount());
1805
+ const mountKindId = (0, import_react6.useId)();
1806
+ const mountProjectId = (0, import_react6.useId)();
1807
+ const mountDestinationId = (0, import_react6.useId)();
1808
+ const mountModeId = (0, import_react6.useId)();
1809
+ const mountVolumeId = (0, import_react6.useId)();
1810
+ const mountSecretId = (0, import_react6.useId)();
1811
+ const updateDraft = (patch) => {
1812
+ setDraft((prev) => ({ ...prev, ...patch }));
1813
+ };
1814
+ const canAdd = draft.kind === "project" ? draft.project.trim() !== "" : draft.kind === "volume" ? draft.volume !== "" : draft.kind === "secret" ? draft.secret !== "" : true;
1815
+ const openAdd = () => {
1816
+ setDraft(emptyMount());
1817
+ setBrowseError("");
1818
+ setAdding(true);
1819
+ };
1820
+ const submit = () => {
1821
+ if (!canAdd) return;
1822
+ onAdd(draft);
1823
+ setAdding(false);
1824
+ };
1825
+ const kindField = draft.kind === "tmpfs" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountDestination"), htmlFor: mountDestinationId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1826
+ import_dsh_client_ui_primitives6.Input,
1827
+ {
1828
+ id: mountDestinationId,
1829
+ value: draft.destination,
1830
+ disabled: busy,
1831
+ onChange: (event) => updateDraft({ destination: event.target.value })
1832
+ }
1833
+ ) }) : draft.kind === "volume" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountVolume"), htmlFor: mountVolumeId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1835
+ "select",
1836
+ {
1837
+ id: mountVolumeId,
1838
+ style: imageSelect,
1839
+ value: draft.volume,
1840
+ disabled: busy,
1841
+ onChange: (event) => updateDraft({ volume: event.target.value }),
1842
+ children: [
1843
+ volumes.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: t("none") }) : null,
1844
+ volumes.map((volume) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: volume.name, children: volume.name }, volume.name))
1845
+ ]
1846
+ }
1847
+ ) }),
1848
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountDestination"), htmlFor: mountDestinationId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1849
+ import_dsh_client_ui_primitives6.Input,
1850
+ {
1851
+ id: mountDestinationId,
1852
+ value: draft.destination,
1853
+ disabled: busy,
1854
+ onChange: (event) => updateDraft({ destination: event.target.value })
1855
+ }
1856
+ ) }),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountMode"), htmlFor: mountModeId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1858
+ "select",
1859
+ {
1860
+ id: mountModeId,
1861
+ style: imageSelect,
1862
+ value: draft.mode,
1863
+ disabled: busy,
1864
+ onChange: (event) => updateDraft({ mode: event.target.value }),
1865
+ children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_only", children: t("readOnly") }),
1867
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_write", children: t("readWrite") })
1868
+ ]
1869
+ }
1870
+ ) })
1871
+ ] }) : draft.kind === "secret" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1872
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountSecret"), htmlFor: mountSecretId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1873
+ "select",
1874
+ {
1875
+ id: mountSecretId,
1876
+ style: imageSelect,
1877
+ value: draft.secret,
1878
+ disabled: busy,
1879
+ onChange: (event) => updateDraft({ secret: event.target.value }),
1880
+ children: [
1881
+ secrets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: t("none") }) : null,
1882
+ secrets.map((secret) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: secret.name, children: secret.name }, secret.name))
1883
+ ]
1884
+ }
1885
+ ) }),
1886
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountDestination"), htmlFor: mountDestinationId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1887
+ import_dsh_client_ui_primitives6.Input,
1888
+ {
1889
+ id: mountDestinationId,
1890
+ value: draft.destination,
1891
+ disabled: busy,
1892
+ onChange: (event) => updateDraft({ destination: event.target.value })
1893
+ }
1894
+ ) })
1895
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1896
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountProjectPath"), htmlFor: mountProjectId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1897
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1898
+ import_dsh_client_ui_primitives6.Input,
1899
+ {
1900
+ id: mountProjectId,
1901
+ value: draft.project,
1902
+ disabled: busy,
1903
+ onChange: (event) => updateDraft({ project: event.target.value })
1904
+ }
1905
+ ),
1906
+ directoryPicker !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1907
+ import_dsh_client_ui_primitives6.Button,
1908
+ {
1909
+ variant: "outline",
1910
+ size: "sm",
1911
+ disabled: busy,
1912
+ onClick: () => {
1913
+ setBrowseError("");
1914
+ setBrowsing(true);
1915
+ },
1916
+ children: t("browse")
1917
+ }
1918
+ ) : null
1919
+ ] }) }),
1920
+ browseError === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { margin: 0, fontSize: "13px" }, role: "alert", children: browseError }),
1921
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountMode"), htmlFor: mountModeId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1922
+ "select",
1923
+ {
1924
+ id: mountModeId,
1925
+ style: imageSelect,
1926
+ value: draft.mode,
1927
+ disabled: busy,
1928
+ onChange: (event) => updateDraft({ mode: event.target.value }),
1929
+ children: [
1930
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_only", children: t("readOnly") }),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_write", children: t("readWrite") })
1932
+ ]
1933
+ }
1934
+ ) })
1935
+ ] });
1936
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
1937
+ mounts.map((mount, index) => {
1938
+ const nextMode = mount.mode === "read_write" ? "read_only" : "read_write";
1939
+ const forced = forcedMountMode(mount.kind);
1940
+ const editable = mount.kind === "project" || mount.kind === "volume";
1941
+ const removable = mount.kind !== "project" || primaryProject === "" || mount.project !== primaryProject;
1942
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1943
+ "div",
1944
+ {
1945
+ style: {
1946
+ display: "flex",
1947
+ flexWrap: "wrap",
1948
+ alignItems: "center",
1949
+ gap: "8px"
1950
+ },
1951
+ children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1953
+ "code",
1954
+ {
1955
+ style: {
1956
+ ...greyId,
1957
+ flex: 1,
1958
+ fontSize: "13px",
1959
+ color: "var(--dsw-alias-label-primary)"
1960
+ },
1961
+ children: mountLabel(t, mount, modeControl !== "select")
1962
+ }
1963
+ ),
1964
+ modeControl === "select" && (editable || forced !== void 0) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1965
+ "select",
1966
+ {
1967
+ style: imageSelect,
1968
+ value: forced ?? mount.mode,
1969
+ disabled: !enabled || forced !== void 0,
1970
+ "aria-label": t("mountMode"),
1971
+ onChange: (event) => onUpdate?.({ ...mount, mode: event.target.value }, index),
1972
+ children: forced !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: forced, children: forced === "read_write" ? t("readWrite") : t("readOnly") }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_only", children: t("readOnly") }),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "read_write", children: t("readWrite") })
1975
+ ] })
1976
+ }
1977
+ ) : null,
1978
+ modeControl === "remount" && editable && onUpdate !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1979
+ ConfirmButton,
1980
+ {
1981
+ t,
1982
+ label: nextMode === "read_only" ? t("remountReadOnly") : t("remountReadWrite"),
1983
+ title: t("confirmTitle"),
1984
+ description: nextMode === "read_only" ? t("confirmRemountReadOnly") : t("confirmRemountReadWrite"),
1985
+ disabled: !enabled,
1986
+ onConfirm: () => onUpdate({ ...mount, mode: nextMode }, index)
1987
+ }
1988
+ ),
1989
+ removable && (confirmRemove ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1990
+ ConfirmButton,
1991
+ {
1992
+ t,
1993
+ label: t("remove"),
1994
+ title: t("confirmTitle"),
1995
+ description: t("confirmRemoveMount"),
1996
+ disabled: !enabled,
1997
+ onConfirm: () => onRemove(mount)
1998
+ }
1999
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2000
+ import_dsh_client_ui_primitives6.Button,
2001
+ {
2002
+ variant: "outline",
2003
+ size: "sm",
2004
+ disabled: !enabled,
2005
+ onClick: () => onRemove(mount),
2006
+ children: t("remove")
2007
+ }
2008
+ ))
2009
+ ]
2010
+ },
2011
+ mountLabel(t, mount)
2012
+ );
2013
+ }),
2014
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2015
+ import_dsh_client_ui_primitives6.Button,
2016
+ {
2017
+ variant: "outline",
2018
+ size: "sm",
2019
+ disabled: !enabled,
2020
+ onClick: openAdd,
2021
+ children: t("addMount")
2022
+ }
2023
+ ) }),
2024
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2025
+ import_dsh_client_ui_primitives6.Modal,
2026
+ {
2027
+ open: adding,
2028
+ onClose: () => setAdding(false),
2029
+ title: t("addMount"),
2030
+ closeLabel: t("cancel"),
2031
+ footer: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2032
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2033
+ import_dsh_client_ui_primitives6.Button,
2034
+ {
2035
+ variant: "outline",
2036
+ size: "sm",
2037
+ onClick: () => setAdding(false),
2038
+ children: t("cancel")
2039
+ }
2040
+ ),
2041
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2042
+ import_dsh_client_ui_primitives6.Button,
2043
+ {
2044
+ variant: "primary",
2045
+ size: "sm",
2046
+ disabled: busy || !canAdd,
2047
+ onClick: submit,
2048
+ children: t("addMount")
2049
+ }
2050
+ )
2051
+ ] }),
2052
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2053
+ "div",
2054
+ {
2055
+ style: {
2056
+ display: "flex",
2057
+ flexDirection: "column",
2058
+ gap: "12px"
2059
+ },
2060
+ children: [
2061
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: t("mountKind"), htmlFor: mountKindId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2062
+ "select",
2063
+ {
2064
+ id: mountKindId,
2065
+ style: imageSelect,
2066
+ value: draft.kind,
2067
+ disabled: busy,
2068
+ onChange: (event) => setDraft(emptyMount(event.target.value)),
2069
+ children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "project", children: t("mountProject") }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "tmpfs", children: "tmpfs" }),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "volume", children: t("mountVolume") }),
2073
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "secret", children: t("mountSecret") })
2074
+ ]
2075
+ }
2076
+ ) }),
2077
+ kindField
2078
+ ]
2079
+ }
2080
+ )
2081
+ }
2082
+ ),
2083
+ directoryPicker === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2084
+ DirectoryPickerModal,
2085
+ {
2086
+ t,
2087
+ open: browsing,
2088
+ root: projectsRoot,
2089
+ start: hostPathForProjectName(projectsRoot, draft.project),
2090
+ picker: directoryPicker,
2091
+ onSelect: (path) => {
2092
+ const project = projectNameFromHostPath(projectsRoot, path);
2093
+ if (project === void 0) {
2094
+ setBrowseError(t("browseOutsideRoot"));
2095
+ return;
2096
+ }
2097
+ updateDraft({ project });
2098
+ setBrowseError("");
2099
+ setBrowsing(false);
2100
+ },
2101
+ onClose: () => setBrowsing(false)
2102
+ }
2103
+ )
2104
+ ] });
2105
+ }
2106
+
2107
+ // src/client/container-card-paths.tsx
2108
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
2109
+ var import_react7 = require("react");
2110
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2111
+ var nextPathId = 0;
2112
+ function pathEntries(paths) {
2113
+ return paths.map((path) => ({ id: nextPathId++, path }));
2114
+ }
2115
+ var pathRow = {
2116
+ display: "flex",
2117
+ alignItems: "center",
2118
+ gap: "6px"
2119
+ };
2120
+ var pathInput = {
2121
+ flex: 1,
2122
+ minWidth: "120px"
2123
+ };
2124
+ var rowButton = {
2125
+ padding: 0,
2126
+ minWidth: "28px"
2127
+ };
2128
+ var dragHandle = {
2129
+ cursor: "grab",
2130
+ background: "none",
2131
+ border: "none",
2132
+ padding: 0,
2133
+ color: "var(--dsw-alias-label-tertiary)"
2134
+ };
2135
+ function PathsList(props) {
2136
+ const { t, entries, busy, onChange } = props;
2137
+ const [draft, setDraft] = (0, import_react7.useState)("");
2138
+ const [dragIndex, setDragIndex] = (0, import_react7.useState)(null);
2139
+ const addId = (0, import_react7.useId)();
2140
+ const move = (from, to) => {
2141
+ if (from === to || to < 0 || to >= entries.length) return;
2142
+ const next = [...entries];
2143
+ const [item] = next.splice(from, 1);
2144
+ next.splice(to, 0, item);
2145
+ onChange(next);
2146
+ };
2147
+ const add = () => {
2148
+ const path = draft.trim();
2149
+ if (path === "") return;
2150
+ onChange([{ id: nextPathId++, path }, ...entries]);
2151
+ setDraft("");
2152
+ };
2153
+ const update = (index, path) => {
2154
+ onChange(entries.map((entry, at) => at === index ? { ...entry, path } : entry));
2155
+ };
2156
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
2157
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Field, { label: t("addPath"), htmlFor: addId, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { ...pathRow, gap: "8px" }, children: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2159
+ import_dsh_client_ui_primitives7.Input,
2160
+ {
2161
+ id: addId,
2162
+ value: draft,
2163
+ disabled: busy,
2164
+ onChange: (event) => setDraft(event.target.value),
2165
+ style: pathInput
2166
+ }
2167
+ ),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2169
+ import_dsh_client_ui_primitives7.Button,
2170
+ {
2171
+ variant: "outline",
2172
+ size: "sm",
2173
+ disabled: busy || draft.trim() === "",
2174
+ onClick: add,
2175
+ children: t("add")
2176
+ }
2177
+ )
2178
+ ] }) }),
2179
+ entries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: { ...hint, margin: 0 }, children: t("noPaths") }) : entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: pathRow, children: [
2180
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2181
+ "button",
2182
+ {
2183
+ type: "button",
2184
+ title: t("dragToReorder"),
2185
+ "aria-label": t("dragToReorder"),
2186
+ draggable: !busy,
2187
+ onDragStart: () => setDragIndex(index),
2188
+ onDragOver: (event) => event.preventDefault(),
2189
+ onDrop: () => {
2190
+ if (dragIndex !== null) move(dragIndex, index);
2191
+ setDragIndex(null);
2192
+ },
2193
+ style: dragHandle,
2194
+ children: "\u2261"
2195
+ }
2196
+ ),
2197
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2198
+ import_dsh_client_ui_primitives7.Input,
2199
+ {
2200
+ value: entry.path,
2201
+ disabled: busy,
2202
+ onChange: (event) => update(index, event.target.value),
2203
+ style: pathInput
2204
+ }
2205
+ ),
2206
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2207
+ import_dsh_client_ui_primitives7.Button,
2208
+ {
2209
+ variant: "outline",
2210
+ size: "sm",
2211
+ title: t("moveUp"),
2212
+ "aria-label": t("moveUp"),
2213
+ disabled: busy || index === 0,
2214
+ onClick: () => move(index, index - 1),
2215
+ style: rowButton,
2216
+ children: "\u2191"
2217
+ }
2218
+ ),
2219
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2220
+ import_dsh_client_ui_primitives7.Button,
2221
+ {
2222
+ variant: "outline",
2223
+ size: "sm",
2224
+ title: t("moveDown"),
2225
+ "aria-label": t("moveDown"),
2226
+ disabled: busy || index === entries.length - 1,
2227
+ onClick: () => move(index, index + 1),
2228
+ style: rowButton,
2229
+ children: "\u2193"
2230
+ }
2231
+ ),
2232
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2233
+ import_dsh_client_ui_primitives7.Button,
2234
+ {
2235
+ variant: "outline",
2236
+ size: "sm",
2237
+ title: t("remove"),
2238
+ "aria-label": t("remove"),
2239
+ disabled: busy,
2240
+ onClick: () => onChange(entries.filter((_, at) => at !== index)),
2241
+ style: rowButton,
2242
+ children: "\xD7"
2243
+ }
2244
+ )
2245
+ ] }, entry.id))
2246
+ ] });
2247
+ }
2248
+ function PathsEditor(props) {
2249
+ const { t, paths, busy, enabled, onApply } = props;
2250
+ const [open, setOpen] = (0, import_react7.useState)(false);
2251
+ const [draft, setDraft] = (0, import_react7.useState)([]);
2252
+ const openEditor = () => {
2253
+ setDraft(pathEntries(paths));
2254
+ setOpen(true);
2255
+ };
2256
+ const apply2 = () => {
2257
+ onApply(draft.map((entry) => entry.path));
2258
+ setOpen(false);
2259
+ };
2260
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
2261
+ paths.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: { ...hint, margin: 0 }, children: t("noPaths") }) : paths.map((path) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2262
+ "code",
2263
+ {
2264
+ style: {
2265
+ ...greyId,
2266
+ fontSize: "13px",
2267
+ color: "var(--dsw-alias-label-primary)"
2268
+ },
2269
+ children: path
2270
+ },
2271
+ path
2272
+ )),
2273
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2274
+ import_dsh_client_ui_primitives7.Button,
2275
+ {
2276
+ variant: "outline",
2277
+ size: "sm",
2278
+ disabled: !enabled,
2279
+ onClick: openEditor,
2280
+ children: t("editPaths")
2281
+ }
2282
+ ) }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2284
+ import_dsh_client_ui_primitives7.Modal,
2285
+ {
2286
+ open,
2287
+ onClose: () => setOpen(false),
2288
+ title: t("pathsTitle"),
2289
+ closeLabel: t("cancel"),
2290
+ footer: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2291
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_dsh_client_ui_primitives7.Button, { variant: "outline", size: "sm", onClick: () => setOpen(false), children: t("cancel") }),
2292
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_dsh_client_ui_primitives7.Button, { variant: "primary", size: "sm", disabled: busy, onClick: apply2, children: t("apply") })
2293
+ ] }),
2294
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PathsList, { t, entries: draft, busy, onChange: setDraft })
2295
+ }
2296
+ )
2297
+ ] });
2298
+ }
2299
+
2300
+ // src/client/container-card-row.tsx
2301
+ var import_dsh_client_ui_primitives9 = require("@deepseek-ai/dsh-client-ui-primitives");
2302
+ var import_react9 = require("react");
2303
+
2304
+ // src/client/container-card-create-modal.tsx
2305
+ var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
2306
+ var import_react8 = require("react");
2307
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2308
+ function CreateContainerModal(props) {
2309
+ const {
2310
+ t,
2311
+ workspace,
2312
+ images,
2313
+ volumes,
2314
+ secrets,
2315
+ busy,
2316
+ defaultImage,
2317
+ projectsRoot,
2318
+ directoryPicker,
2319
+ named,
2320
+ existing,
2321
+ open,
2322
+ onClose,
2323
+ onCreate
2324
+ } = props;
2325
+ const [image, setImage] = (0, import_react8.useState)(workspace.imageId || defaultImage);
2326
+ const [name2, setName] = (0, import_react8.useState)("");
2327
+ const [env, setEnv] = (0, import_react8.useState)({});
2328
+ const [mounts, setMounts] = (0, import_react8.useState)(() => [
2329
+ {
2330
+ kind: "project",
2331
+ project: workspace.projectName,
2332
+ destination: "",
2333
+ mode: "read_write",
2334
+ volume: "",
2335
+ secret: ""
2336
+ }
2337
+ ]);
2338
+ const [secretEnv, setSecretEnv] = (0, import_react8.useState)({});
2339
+ const [paths, setPaths] = (0, import_react8.useState)([]);
2340
+ const [attachSecret, setAttachSecret] = (0, import_react8.useState)("");
2341
+ const [attachVar, setAttachVar] = (0, import_react8.useState)("");
2342
+ const [submitting, setSubmitting] = (0, import_react8.useState)(false);
2343
+ const imageLabel = (0, import_react8.useId)();
2344
+ const nameLabel = (0, import_react8.useId)();
2345
+ (0, import_react8.useEffect)(() => {
2346
+ if (!open) return;
2347
+ setImage(workspace.imageId || defaultImage);
2348
+ setName("");
2349
+ setEnv({});
2350
+ setMounts([
2351
+ {
2352
+ kind: "project",
2353
+ project: workspace.projectName,
2354
+ destination: "",
2355
+ mode: "read_write",
2356
+ volume: "",
2357
+ secret: ""
2358
+ }
2359
+ ]);
2360
+ setSecretEnv({});
2361
+ setPaths([]);
2362
+ setAttachSecret("");
2363
+ setAttachVar("");
2364
+ setSubmitting(false);
2365
+ }, [open, workspace, defaultImage]);
2366
+ const baseImages = images.filter((image2) => image2.isBase);
2367
+ const customImages = images.filter((image2) => !image2.isBase);
2368
+ const candidates = [
2369
+ ...baseImages.map((image2) => image2.imageId),
2370
+ ...customImages.map((image2) => image2.imageId)
2371
+ ];
2372
+ const nameTaken = existing.includes(name2);
2373
+ const validName = namePattern.test(name2) && name2 !== "default" && !nameTaken;
2374
+ const canCreate = !named || validName;
2375
+ const submit = () => {
2376
+ if (!canCreate || submitting) return;
2377
+ setSubmitting(true);
2378
+ onCreate(named ? name2 : "", {
2379
+ image,
2380
+ env,
2381
+ mounts,
2382
+ paths: paths.map((entry) => entry.path).filter((path) => path !== ""),
2383
+ secretEnv
2384
+ });
2385
+ };
2386
+ const attach = () => {
2387
+ const envVar = attachVar.trim();
2388
+ if (envVar === "" || attachSecret === "") return;
2389
+ setSecretEnv({ ...secretEnv, [envVar]: attachSecret });
2390
+ setAttachVar("");
2391
+ };
2392
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2393
+ import_dsh_client_ui_primitives8.Modal,
2394
+ {
2395
+ open,
2396
+ onClose,
2397
+ title: named ? t("addContainer") : t("createContainer"),
2398
+ closeLabel: t("cancel"),
2399
+ footer: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2400
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2401
+ import_dsh_client_ui_primitives8.Button,
2402
+ {
2403
+ variant: "outline",
2404
+ size: "sm",
2405
+ onClick: onClose,
2406
+ children: t("cancel")
2407
+ }
2408
+ ),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2410
+ import_dsh_client_ui_primitives8.Button,
2411
+ {
2412
+ variant: "primary",
2413
+ size: "sm",
2414
+ disabled: !canCreate || submitting,
2415
+ onClick: submit,
2416
+ children: named ? t("addContainer") : t("createContainer")
2417
+ }
2418
+ )
2419
+ ] }),
2420
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2421
+ "div",
2422
+ {
2423
+ style: {
2424
+ display: "flex",
2425
+ flexDirection: "column",
2426
+ gap: "12px"
2427
+ },
2428
+ children: [
2429
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Field, { label: t("image"), htmlFor: imageLabel, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2430
+ "select",
2431
+ {
2432
+ id: imageLabel,
2433
+ style: imageSelect,
2434
+ value: image,
2435
+ disabled: busy,
2436
+ onChange: (event) => setImage(event.target.value),
2437
+ children: [
2438
+ candidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "", children: t("none") }) : null,
2439
+ candidates.map((imageId) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: imageId, children: imageId }, imageId))
2440
+ ]
2441
+ }
2442
+ ) }),
2443
+ named ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Field, { label: t("containerName"), htmlFor: nameLabel, children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2445
+ import_dsh_client_ui_primitives8.Input,
2446
+ {
2447
+ id: nameLabel,
2448
+ value: name2,
2449
+ disabled: busy,
2450
+ onChange: (event) => setName(sanitizeName(event.target.value))
2451
+ }
2452
+ ),
2453
+ name2 !== "" && !validName ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: { ...hint, margin: 0 }, children: nameTaken ? t("containerNameTaken") : t("invalidContainerName") }) : null
2454
+ ] }) : null,
2455
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: sectionTitle, children: t("envTitle") }),
2456
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EnvEditor, { t, env, busy, onChange: setEnv }),
2457
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: sectionTitle, children: t("mountsTitle") }),
2458
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2459
+ MountsEditor,
2460
+ {
2461
+ t,
2462
+ mounts,
2463
+ volumes,
2464
+ secrets,
2465
+ busy,
2466
+ enabled: !busy,
2467
+ projectsRoot,
2468
+ directoryPicker,
2469
+ modeControl: "select",
2470
+ onAdd: (mount) => setMounts([...mounts, mount]),
2471
+ onRemove: (mount) => setMounts(mounts.filter((item) => item !== mount)),
2472
+ onUpdate: (updated, index) => setMounts(mounts.map((item, at) => at === index ? updated : item))
2473
+ }
2474
+ ),
2475
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: sectionTitle, children: t("pathsTitle") }),
2476
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PathsList, { t, entries: paths, busy, onChange: setPaths }),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: sectionTitle, children: t("containerSecretsTitle") }),
2478
+ Object.entries(secretEnv).map(([envVar, secretName]) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2479
+ "div",
2480
+ {
2481
+ style: {
2482
+ display: "flex",
2483
+ flexWrap: "wrap",
2484
+ alignItems: "center",
2485
+ gap: "8px"
2486
+ },
2487
+ children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2489
+ "code",
2490
+ {
2491
+ style: {
2492
+ ...greyId,
2493
+ flex: 1,
2494
+ fontSize: "13px",
2495
+ color: "var(--dsw-alias-label-primary)"
2496
+ },
2497
+ children: [
2498
+ envVar,
2499
+ "=",
2500
+ secretName
2501
+ ]
2502
+ }
2503
+ ),
2504
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2505
+ import_dsh_client_ui_primitives8.Button,
2506
+ {
2507
+ variant: "outline",
2508
+ size: "sm",
2509
+ disabled: busy,
2510
+ onClick: () => {
2511
+ const next = { ...secretEnv };
2512
+ delete next[envVar];
2513
+ setSecretEnv(next);
2514
+ },
2515
+ children: t("remove")
2516
+ }
2517
+ )
2518
+ ]
2519
+ },
2520
+ envVar
2521
+ )),
2522
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2523
+ "div",
2524
+ {
2525
+ style: {
2526
+ display: "flex",
2527
+ flexWrap: "wrap",
2528
+ alignItems: "center",
2529
+ gap: "8px"
2530
+ },
2531
+ children: [
2532
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2533
+ "select",
2534
+ {
2535
+ style: imageSelect,
2536
+ value: attachSecret,
2537
+ disabled: busy,
2538
+ onChange: (event) => setAttachSecret(event.target.value),
2539
+ "aria-label": t("attachSecret"),
2540
+ children: [
2541
+ secrets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "", children: t("none") }) : null,
2542
+ secrets.map((secret) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: secret.name, children: secret.name }, secret.name))
2543
+ ]
2544
+ }
2545
+ ),
2546
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2547
+ import_dsh_client_ui_primitives8.Input,
2548
+ {
2549
+ value: attachVar,
2550
+ disabled: busy,
2551
+ placeholder: t("secretEnvName"),
2552
+ onChange: (event) => setAttachVar(event.target.value),
2553
+ onKeyDown: (event) => {
2554
+ if (event.key === "Enter") attach();
2555
+ },
2556
+ style: { width: "200px" }
2557
+ }
2558
+ ),
2559
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2560
+ import_dsh_client_ui_primitives8.Button,
2561
+ {
2562
+ variant: "outline",
2563
+ size: "sm",
2564
+ disabled: busy || attachVar.trim() === "" || attachSecret === "",
2565
+ onClick: attach,
2566
+ children: t("attachSecret")
2567
+ }
2568
+ )
2569
+ ]
2570
+ }
2571
+ )
2572
+ ]
2573
+ }
2574
+ )
2575
+ }
2576
+ );
2577
+ }
2578
+
2579
+ // src/client/container-card-row.tsx
2580
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2581
+ function ContainerRow(props) {
2582
+ const {
2583
+ t,
2584
+ container,
2585
+ images,
2586
+ volumes,
2587
+ secrets,
2588
+ busy,
2589
+ onRemove,
2590
+ onRecreate,
2591
+ onAddContainerMount,
2592
+ onRemoveContainerMount,
2593
+ onUpdateContainerMount,
2594
+ onSetContainerPaths,
2595
+ onAddContainerSecret,
2596
+ onRemoveContainerSecret,
2597
+ projectName,
2598
+ projectsRoot,
2599
+ directoryPicker
2600
+ } = props;
2601
+ const [selected, setSelected] = (0, import_react9.useState)(container.imageId);
2602
+ const [env, setEnv] = (0, import_react9.useState)(container.env);
2603
+ const [envOpen, setEnvOpen] = (0, import_react9.useState)(false);
2604
+ const [mountOpen, setMountOpen] = (0, import_react9.useState)(false);
2605
+ const [pathOpen, setPathOpen] = (0, import_react9.useState)(false);
2606
+ const [secretOpen, setSecretOpen] = (0, import_react9.useState)(false);
2607
+ const [attachSecret, setAttachSecret] = (0, import_react9.useState)("");
2608
+ const [attachVar, setAttachVar] = (0, import_react9.useState)("");
2609
+ const enabled = container.workspaceSlug !== "" && !busy;
2610
+ const projects = container.mounts.map((mount) => mount.projectName).join(", ");
2611
+ const envEntries = Object.entries(container.env);
2612
+ const secretEntries = Object.entries(container.secretEnv);
2613
+ const attach = () => {
2614
+ const envVar = attachVar.trim();
2615
+ if (envVar === "" || attachSecret === "") return;
2616
+ onAddContainerSecret(container.workspaceSlug, envVar, attachSecret);
2617
+ setAttachVar("");
2618
+ };
2619
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: containerRow, children: [
2620
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: containerHeader, children: [
2621
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { style: { color: "var(--dsw-alias-label-primary)" }, children: container.containerName }),
2622
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives9.Pill, { children: container.status })
2623
+ ] }),
2624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { style: tableStyle, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tbody", { children: [
2625
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
2626
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: thStyle, scope: "row", children: t("image") }),
2627
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: tdStyle, children: container.imageId })
2628
+ ] }),
2629
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
2630
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: thStyle, scope: "row", children: t("created") }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: tdStyle, children: container.createdAt })
2632
+ ] }),
2633
+ projects !== "" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
2634
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: thStyle, scope: "row", children: t("projects") }),
2635
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: tdStyle, children: projects })
2636
+ ] }) : null,
2637
+ envEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
2638
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: thStyle, scope: "row", children: t("env") }),
2639
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: tdStyle, children: envEntries.map(([key]) => key).join(", ") })
2640
+ ] }) : null,
2641
+ secretEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
2642
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: thStyle, scope: "row", children: t("secretEnv") }),
2643
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: tdStyle, children: secretEntries.map(([envVar, secretName]) => `${envVar}=${secretName}`).join(", ") })
2644
+ ] }) : null
2645
+ ] }) }),
2646
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: actions, children: [
2647
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2648
+ ConfirmButton,
2649
+ {
2650
+ t,
2651
+ label: t("remove"),
2652
+ title: t("confirmTitle"),
2653
+ description: t("confirmRemoveContainer"),
2654
+ disabled: !enabled,
2655
+ onConfirm: () => onRemove(container.workspaceSlug)
2656
+ }
2657
+ ),
2658
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2659
+ ConfirmButton,
2660
+ {
2661
+ t,
2662
+ label: t("recreate"),
2663
+ title: t("confirmTitle"),
2664
+ description: t("confirmRecreate"),
2665
+ disabled: !enabled,
2666
+ onConfirm: () => onRecreate(container.workspaceSlug, "", env)
2667
+ }
2668
+ ),
2669
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2670
+ "select",
2671
+ {
2672
+ style: imageSelect,
2673
+ value: selected,
2674
+ disabled: !enabled,
2675
+ onChange: (event) => setSelected(event.target.value),
2676
+ "aria-label": t("recreateWithImage"),
2677
+ children: [
2678
+ container.imageId === "" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: t("none") }) : null,
2679
+ images.map((image) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: image.imageId, children: image.imageId }, image.imageId))
2680
+ ]
2681
+ }
2682
+ ),
2683
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2684
+ ConfirmButton,
2685
+ {
2686
+ t,
2687
+ label: t("recreateWithImage"),
2688
+ title: t("confirmTitle"),
2689
+ description: t("confirmRecreate"),
2690
+ disabled: !enabled || selected === "",
2691
+ onConfirm: () => onRecreate(container.workspaceSlug, selected, env)
2692
+ }
2693
+ )
2694
+ ] }),
2695
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2696
+ import_dsh_client_ui_primitives9.DisclosureRow,
2697
+ {
2698
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", {}),
2699
+ title: t("envTitle"),
2700
+ open: envOpen,
2701
+ expandable: true,
2702
+ onToggle: () => setEnvOpen(!envOpen),
2703
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: wsBody, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(EnvEditor, { t, env, busy, onChange: setEnv }) })
2704
+ }
2705
+ ),
2706
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2707
+ import_dsh_client_ui_primitives9.DisclosureRow,
2708
+ {
2709
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", {}),
2710
+ title: t("mountsTitle"),
2711
+ open: mountOpen,
2712
+ expandable: true,
2713
+ onToggle: () => setMountOpen(!mountOpen),
2714
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: wsBody, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2715
+ MountsEditor,
2716
+ {
2717
+ t,
2718
+ mounts: container.mounts.map(mountViewToInput),
2719
+ volumes,
2720
+ secrets,
2721
+ busy,
2722
+ enabled,
2723
+ projectsRoot,
2724
+ directoryPicker,
2725
+ confirmRemove: true,
2726
+ primaryProject: container.containerName === "default" ? projectName : "",
2727
+ onUpdate: (mount) => onUpdateContainerMount(
2728
+ container.workspaceSlug,
2729
+ container.containerName,
2730
+ mount
2731
+ ),
2732
+ onRemove: (mount) => onRemoveContainerMount(
2733
+ container.workspaceSlug,
2734
+ container.containerName,
2735
+ mount
2736
+ ),
2737
+ onAdd: (mount) => onAddContainerMount(
2738
+ container.workspaceSlug,
2739
+ container.containerName,
2740
+ mount
2741
+ )
2742
+ }
2743
+ ) })
2744
+ }
2745
+ ),
2746
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2747
+ import_dsh_client_ui_primitives9.DisclosureRow,
2748
+ {
2749
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", {}),
2750
+ title: t("pathsTitle"),
2751
+ open: pathOpen,
2752
+ expandable: true,
2753
+ onToggle: () => setPathOpen(!pathOpen),
2754
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: wsBody, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2755
+ PathsEditor,
2756
+ {
2757
+ t,
2758
+ paths: container.paths,
2759
+ busy,
2760
+ enabled,
2761
+ onApply: (paths) => onSetContainerPaths(
2762
+ container.workspaceSlug,
2763
+ container.containerName,
2764
+ paths
2765
+ )
2766
+ }
2767
+ ) })
2768
+ }
2769
+ ),
2770
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2771
+ import_dsh_client_ui_primitives9.DisclosureRow,
2772
+ {
2773
+ icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", {}),
2774
+ title: t("containerSecretsTitle"),
2775
+ open: secretOpen,
2776
+ expandable: true,
2777
+ onToggle: () => setSecretOpen(!secretOpen),
2778
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: wsBody, children: [
2779
+ secretEntries.map(([envVar, secretName]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2780
+ "div",
2781
+ {
2782
+ style: {
2783
+ display: "flex",
2784
+ flexWrap: "wrap",
2785
+ alignItems: "center",
2786
+ gap: "8px"
2787
+ },
2788
+ children: [
2789
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2790
+ "code",
2791
+ {
2792
+ style: {
2793
+ ...greyId,
2794
+ flex: 1,
2795
+ fontSize: "13px",
2796
+ color: "var(--dsw-alias-label-primary)"
2797
+ },
2798
+ children: [
2799
+ envVar,
2800
+ "=",
2801
+ secretName
2802
+ ]
2803
+ }
2804
+ ),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2806
+ ConfirmButton,
2807
+ {
2808
+ t,
2809
+ label: t("detachSecret"),
2810
+ title: t("confirmTitle"),
2811
+ description: t("confirmDetachSecret"),
2812
+ disabled: busy,
2813
+ onConfirm: () => onRemoveContainerSecret(container.workspaceSlug, envVar)
2814
+ }
2815
+ )
2816
+ ]
2817
+ },
2818
+ envVar
2819
+ )),
2820
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2821
+ "div",
2822
+ {
2823
+ style: {
2824
+ display: "flex",
2825
+ flexWrap: "wrap",
2826
+ alignItems: "center",
2827
+ gap: "8px",
2828
+ paddingTop: "8px"
2829
+ },
2830
+ children: [
2831
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2832
+ "select",
2833
+ {
2834
+ style: imageSelect,
2835
+ value: attachSecret,
2836
+ disabled: !enabled,
2837
+ onChange: (event) => setAttachSecret(event.target.value),
2838
+ "aria-label": t("attachSecret"),
2839
+ children: [
2840
+ secrets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: t("none") }) : null,
2841
+ secrets.map((secret) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: secret.name, children: secret.name }, secret.name))
2842
+ ]
2843
+ }
2844
+ ),
2845
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2846
+ import_dsh_client_ui_primitives9.Input,
2847
+ {
2848
+ value: attachVar,
2849
+ disabled: !enabled,
2850
+ placeholder: t("secretEnvName"),
2851
+ onChange: (event) => setAttachVar(event.target.value),
2852
+ onKeyDown: (event) => {
2853
+ if (event.key === "Enter") attach();
2854
+ },
2855
+ style: { width: "200px" }
2856
+ }
2857
+ ),
2858
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2859
+ import_dsh_client_ui_primitives9.Button,
2860
+ {
2861
+ variant: "outline",
2862
+ size: "sm",
2863
+ disabled: !enabled || attachVar.trim() === "" || attachSecret === "",
2864
+ onClick: attach,
2865
+ children: t("attachSecret")
2866
+ }
2867
+ )
2868
+ ]
2869
+ }
2870
+ )
2871
+ ] })
2872
+ }
2873
+ )
2874
+ ] });
2875
+ }
2876
+
2877
+ // src/client/container-card-workspace.tsx
2878
+ var import_dsh_client_ui_primitives10 = require("@deepseek-ai/dsh-client-ui-primitives");
2879
+ var import_react10 = require("react");
2880
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2881
+ function WorkspaceSection(props) {
2882
+ const {
2883
+ t,
2884
+ workspace,
2885
+ containers,
2886
+ images,
2887
+ volumes,
2888
+ secrets,
2889
+ busy,
2890
+ defaultImage,
2891
+ projectsRoot,
2892
+ directoryPicker,
2893
+ onRemove,
2894
+ onRemoveWorkspace,
2895
+ onRecreate,
2896
+ onCreate,
2897
+ onStartContainer,
2898
+ onAddContainerMount,
2899
+ onRemoveContainerMount,
2900
+ onUpdateContainerMount,
2901
+ onSetContainerPaths,
2902
+ onAddContainerSecret,
2903
+ onRemoveContainerSecret
2904
+ } = props;
2905
+ const [open, setOpen] = (0, import_react10.useState)(false);
2906
+ const [createOpen, setCreateOpen] = (0, import_react10.useState)(null);
2907
+ const hasContainer = containers.length > 0;
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2909
+ import_dsh_client_ui_primitives10.DisclosureRow,
2910
+ {
2911
+ icon: hasContainer ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_dsh_client_ui_primitives10.StateDot, { state: containerStateDot(containers[0]?.status ?? "") }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", {}),
2912
+ title: workspace.projectName,
2913
+ open,
2914
+ expandable: true,
2915
+ onToggle: () => setOpen(!open),
2916
+ children: [
2917
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: wsBody, children: [
2918
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("code", { style: greyId, children: workspace.workspaceSlug }),
2919
+ !hasContainer ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
2920
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { ...hint, margin: 0 }, children: t("noContainers") }),
2921
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2922
+ import_dsh_client_ui_primitives10.Button,
2923
+ {
2924
+ variant: "outline",
2925
+ size: "sm",
2926
+ disabled: busy,
2927
+ onClick: () => setCreateOpen("default"),
2928
+ children: t("createContainer")
2929
+ }
2930
+ ) })
2931
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2932
+ containers.map((container) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2933
+ ContainerRow,
2934
+ {
2935
+ t,
2936
+ container,
2937
+ images,
2938
+ volumes,
2939
+ secrets,
2940
+ busy,
2941
+ onRemove,
2942
+ onRecreate,
2943
+ onAddContainerMount,
2944
+ onRemoveContainerMount,
2945
+ onUpdateContainerMount,
2946
+ onSetContainerPaths,
2947
+ projectName: workspace.projectName,
2948
+ projectsRoot,
2949
+ directoryPicker,
2950
+ onAddContainerSecret,
2951
+ onRemoveContainerSecret
2952
+ },
2953
+ container.containerName
2954
+ )),
2955
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2956
+ import_dsh_client_ui_primitives10.Button,
2957
+ {
2958
+ variant: "outline",
2959
+ size: "sm",
2960
+ disabled: busy,
2961
+ onClick: () => setCreateOpen("named"),
2962
+ children: t("addContainer")
2963
+ }
2964
+ ) })
2965
+ ] }),
2966
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2967
+ ConfirmButton,
2968
+ {
2969
+ t,
2970
+ label: t("removePod"),
2971
+ title: t("confirmTitle"),
2972
+ description: t("confirmRemovePod"),
2973
+ disabled: busy,
2974
+ onConfirm: () => onRemoveWorkspace(workspace.workspaceSlug)
2975
+ }
2976
+ ) })
2977
+ ] }),
2978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2979
+ CreateContainerModal,
2980
+ {
2981
+ t,
2982
+ workspace,
2983
+ images,
2984
+ volumes,
2985
+ secrets,
2986
+ busy,
2987
+ defaultImage,
2988
+ projectsRoot,
2989
+ directoryPicker,
2990
+ named: createOpen === "named",
2991
+ existing: containers.map((container) => container.containerName),
2992
+ open: createOpen !== null,
2993
+ onClose: () => setCreateOpen(null),
2994
+ onCreate: (container, config) => {
2995
+ if (createOpen === "named") {
2996
+ onStartContainer(workspace, container, config);
2997
+ } else {
2998
+ onCreate(workspace, config);
2999
+ }
3000
+ setCreateOpen(null);
3001
+ }
3002
+ }
3003
+ )
3004
+ ]
3005
+ }
3006
+ );
3007
+ }
3008
+
3009
+ // src/client/ContainerCard.tsx
3010
+ var import_dsh_client_ui_primitives11 = require("@deepseek-ai/dsh-client-ui-primitives");
3011
+ var import_react11 = require("react");
3012
+ var import_jsx_runtime12 = require("react/jsx-runtime");
3013
+ function ContainerCard(props) {
3014
+ const { t } = props;
3015
+ const state = props.useContainerCard((snapshot) => snapshot);
3016
+ const [open, setOpen] = (0, import_react11.useState)(false);
3017
+ const [hovered, setHovered] = (0, import_react11.useState)(false);
3018
+ const [buildOpen, setBuildOpen] = (0, import_react11.useState)(false);
3019
+ const [imageId, setImageId] = (0, import_react11.useState)("");
3020
+ const [parent, setParent] = (0, import_react11.useState)("");
3021
+ const [packages, setPackages] = (0, import_react11.useState)([]);
3022
+ const [defaultOpen, setDefaultOpen] = (0, import_react11.useState)(false);
3023
+ const [defaultImage, setDefaultImage] = (0, import_react11.useState)(state.defaultImage);
3024
+ const projectsRootId = (0, import_react11.useId)();
3025
+ (0, import_react11.useEffect)(() => {
3026
+ props.reload();
3027
+ }, []);
3028
+ const baseImages = state.images.filter((image) => image.isBase);
3029
+ const customImages = state.images.filter((image) => !image.isBase);
3030
+ const defaultCandidates = [
3031
+ ...baseImages.map((image) => image.imageId),
3032
+ ...customImages.map((image) => image.imageId)
3033
+ ];
3034
+ if (!state.available) {
3035
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { padding: "8px 0", fontSize: "13px", opacity: 0.8 }, children: t("unavailable") });
3036
+ }
3037
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3038
+ "li",
3039
+ {
3040
+ style: {
3041
+ ...cardStyle,
3042
+ ...open ? cardOpenStyle : {},
3043
+ ...hovered && !open ? cardHoverStyle : {}
3044
+ },
3045
+ onPointerEnter: () => setHovered(true),
3046
+ onPointerLeave: () => setHovered(false),
3047
+ children: [
3048
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3049
+ "button",
3050
+ {
3051
+ type: "button",
3052
+ style: cardHeaderStyle,
3053
+ "aria-expanded": open,
3054
+ onClick: () => setOpen(!open),
3055
+ children: [
3056
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: cardHeadTextStyle, children: [
3057
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: cardNameStyle, children: [
3058
+ t("cardTitle"),
3059
+ state.version ? ` ${state.version}` : "",
3060
+ state.commit ? ` \xB7 ${state.commit}` : ""
3061
+ ] }),
3062
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: cardDescriptionStyle, children: t("cardDescription") })
3063
+ ] }),
3064
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CardChevron, { open })
3065
+ ]
3066
+ }
3067
+ ),
3068
+ open ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: cardBodyStyle, children: [
3069
+ state.notice === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: banner, role: "status", children: [
3070
+ t("notice"),
3071
+ ": ",
3072
+ state.notice
3073
+ ] }),
3074
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: sectionTitle, children: t("workspacesTitle") }),
3075
+ state.workspaces.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: hint, children: t("none") }) : state.workspaces.map((workspace) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3076
+ WorkspaceSection,
3077
+ {
3078
+ t,
3079
+ workspace,
3080
+ containers: state.containers.filter(
3081
+ (container) => container.workspaceSlug === workspace.workspaceSlug
3082
+ ),
3083
+ images: state.images,
3084
+ volumes: state.volumes,
3085
+ secrets: state.secrets,
3086
+ busy: state.busy,
3087
+ defaultImage: state.defaultImage,
3088
+ projectsRoot: state.projectsRoot,
3089
+ directoryPicker: state.directoryPicker,
3090
+ onRemove: props.remove,
3091
+ onRemoveWorkspace: props.removeWorkspace,
3092
+ onRecreate: props.recreate,
3093
+ onCreate: props.createContainer,
3094
+ onStartContainer: props.startContainer,
3095
+ onAddContainerMount: props.addContainerMount,
3096
+ onRemoveContainerMount: props.removeContainerMount,
3097
+ onUpdateContainerMount: props.updateContainerMount,
3098
+ onSetContainerPaths: props.setContainerPaths,
3099
+ onAddContainerSecret: props.addContainerSecret,
3100
+ onRemoveContainerSecret: props.removeContainerSecret
3101
+ },
3102
+ workspace.workspaceSlug
3103
+ )),
3104
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3105
+ "div",
3106
+ {
3107
+ style: {
3108
+ display: "flex",
3109
+ flexWrap: "wrap",
3110
+ alignItems: "center",
3111
+ gap: "8px"
3112
+ },
3113
+ children: [
3114
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { ...sectionTitle, flex: 1 }, children: t("imagesTitle") }),
3115
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3116
+ import_dsh_client_ui_primitives11.Button,
3117
+ {
3118
+ variant: "outline",
3119
+ size: "sm",
3120
+ disabled: state.busy,
3121
+ onClick: () => {
3122
+ setDefaultImage(state.defaultImage);
3123
+ setDefaultOpen(true);
3124
+ },
3125
+ children: t("setDefaultImage")
3126
+ }
3127
+ ),
3128
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3129
+ import_dsh_client_ui_primitives11.Button,
3130
+ {
3131
+ variant: "outline",
3132
+ size: "sm",
3133
+ disabled: state.busy,
3134
+ onClick: () => {
3135
+ setImageId("");
3136
+ setParent(baseImages[0]?.imageId ?? customImages[0]?.imageId ?? "");
3137
+ setPackages([]);
3138
+ setBuildOpen(true);
3139
+ },
3140
+ children: t("buildImage")
3141
+ }
3142
+ ),
3143
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3144
+ ConfirmButton,
3145
+ {
3146
+ t,
3147
+ label: t("rebuildAllImages"),
3148
+ title: t("confirmTitle"),
3149
+ description: t("confirmRebuildAllImages"),
3150
+ disabled: state.busy,
3151
+ onConfirm: props.rebuildAllImages
3152
+ }
3153
+ )
3154
+ ]
3155
+ }
3156
+ ),
3157
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: sectionTitle, children: t("baseImagesTitle") }),
3158
+ baseImages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: hint, children: t("none") }) : baseImages.map((image) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3159
+ BaseImageRow,
3160
+ {
3161
+ t,
3162
+ image,
3163
+ busy: state.busy,
3164
+ defaultImage: state.defaultImage,
3165
+ onRebuild: props.rebuildBaseImage,
3166
+ onPull: props.pullBaseImage,
3167
+ onSetDefault: props.setDefaultImage
3168
+ },
3169
+ image.imageId
3170
+ )),
3171
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: sectionTitle, children: t("customImagesTitle") }),
3172
+ customImages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: hint, children: t("none") }) : customImages.map((image) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3173
+ ImageItem,
3174
+ {
3175
+ t,
3176
+ image,
3177
+ busy: state.busy,
3178
+ defaultImage: state.defaultImage,
3179
+ onRemove: props.removeImage,
3180
+ onRebuild: props.rebuildImage,
3181
+ onSetDefault: props.setDefaultImage
3182
+ },
3183
+ image.imageId
3184
+ )),
3185
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3186
+ ImageBuildModal,
3187
+ {
3188
+ t,
3189
+ images: state.images,
3190
+ open: buildOpen,
3191
+ imageId,
3192
+ parent,
3193
+ packages,
3194
+ onImageId: setImageId,
3195
+ onParent: setParent,
3196
+ onPackages: setPackages,
3197
+ onClose: () => setBuildOpen(false),
3198
+ onBuild: () => {
3199
+ props.buildImage(imageId.trim(), parent.trim(), packages);
3200
+ setImageId("");
3201
+ setParent("");
3202
+ setPackages([]);
3203
+ setBuildOpen(false);
3204
+ }
3205
+ }
3206
+ ),
3207
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3208
+ import_dsh_client_ui_primitives11.Modal,
3209
+ {
3210
+ open: defaultOpen,
3211
+ onClose: () => setDefaultOpen(false),
3212
+ title: t("setDefaultImageTitle"),
3213
+ closeLabel: t("cancel"),
3214
+ footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
3215
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3216
+ import_dsh_client_ui_primitives11.Button,
3217
+ {
3218
+ variant: "outline",
3219
+ size: "sm",
3220
+ onClick: () => setDefaultOpen(false),
3221
+ children: t("cancel")
3222
+ }
3223
+ ),
3224
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3225
+ import_dsh_client_ui_primitives11.Button,
3226
+ {
3227
+ variant: "primary",
3228
+ size: "sm",
3229
+ disabled: defaultImage === "",
3230
+ onClick: () => {
3231
+ props.setDefaultImage(defaultImage);
3232
+ setDefaultOpen(false);
3233
+ },
3234
+ children: t("setDefaultImage")
3235
+ }
3236
+ )
3237
+ ] }),
3238
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3239
+ "select",
3240
+ {
3241
+ style: imageSelect,
3242
+ value: defaultImage,
3243
+ onChange: (event) => setDefaultImage(event.target.value),
3244
+ children: [
3245
+ defaultCandidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "", children: t("none") }) : null,
3246
+ defaultCandidates.map((name2) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: name2, children: name2 }, name2))
3247
+ ]
3248
+ }
3249
+ )
3250
+ }
3251
+ ),
3252
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3253
+ CachesSection,
3254
+ {
3255
+ t,
3256
+ caches: state.caches,
3257
+ busy: state.busy,
3258
+ onClean: props.cleanCaches
3259
+ }
3260
+ ),
3261
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3262
+ VolumesSection,
3263
+ {
3264
+ t,
3265
+ volumes: state.volumes,
3266
+ busy: state.busy,
3267
+ writable: state.writable,
3268
+ onCreate: props.createVolume,
3269
+ onRemove: props.removeVolume
3270
+ }
3271
+ ),
3272
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3273
+ SecretsSection,
3274
+ {
3275
+ t,
3276
+ secrets: state.secrets,
3277
+ busy: state.busy,
3278
+ writable: state.writable,
3279
+ onCreate: props.createSecret,
3280
+ onRemove: props.removeSecret,
3281
+ onSet: props.setSecret
3282
+ }
3283
+ ),
3284
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: sectionTitle, children: t("configTitle") }),
3285
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3286
+ "div",
3287
+ {
3288
+ style: {
3289
+ display: "flex",
3290
+ flexWrap: "wrap",
3291
+ alignItems: "center",
3292
+ gap: "8px",
3293
+ padding: "8px 0"
3294
+ },
3295
+ children: [
3296
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3297
+ "label",
3298
+ {
3299
+ htmlFor: projectsRootId,
3300
+ style: {
3301
+ fontSize: "13px",
3302
+ color: "var(--dsw-alias-label-secondary)",
3303
+ minWidth: "110px"
3304
+ },
3305
+ children: t("projectsRoot")
3306
+ }
3307
+ ),
3308
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3309
+ import_dsh_client_ui_primitives11.Input,
3310
+ {
3311
+ id: projectsRootId,
3312
+ value: state.projectsRoot,
3313
+ disabled: true,
3314
+ style: { width: "200px" }
3315
+ }
3316
+ )
3317
+ ]
3318
+ }
3319
+ ),
3320
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3321
+ ConfigField,
3322
+ {
3323
+ t,
3324
+ label: t("socketsRoot"),
3325
+ value: state.socketsRootDraft,
3326
+ current: state.socketsRoot,
3327
+ writable: state.writable,
3328
+ onChange: props.editSocketsRoot,
3329
+ onSave: props.saveSocketsRoot,
3330
+ onDiscard: props.discardSocketsRoot
3331
+ }
3332
+ ),
3333
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: footerRow, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3334
+ import_dsh_client_ui_primitives11.Button,
3335
+ {
3336
+ variant: "outline",
3337
+ size: "sm",
3338
+ disabled: state.busy,
3339
+ onClick: props.reload,
3340
+ children: state.busy ? t("busy") : t("reload")
3341
+ }
3342
+ ) })
3343
+ ] }) : null
3344
+ ]
3345
+ }
3346
+ );
3347
+ }
3348
+
3349
+ // src/client/read-only-approval.tsx
3350
+ var import_dsh_client_ui_primitives12 = require("@deepseek-ai/dsh-client-ui-primitives");
3351
+ var import_react12 = require("react");
3352
+ var import_jsx_runtime13 = require("react/jsx-runtime");
3353
+ var BUILTIN_PROMPT_PREFIX = "dsh_podman_builtin_";
3354
+ function ReadOnlyApprovalPanel(props) {
3355
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ReadOnlyApprovalFlow, { ...props }, props.matched.key);
3356
+ }
3357
+ function ReadOnlyApprovalFlow({
3358
+ t,
3359
+ matched
3360
+ }) {
3361
+ const [answered, setAnswered] = (0, import_react12.useState)(false);
3362
+ const answer = (outcome) => {
3363
+ setAnswered(true);
3364
+ void matched.answer(outcome).catch(() => setAnswered(false));
3365
+ };
3366
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3367
+ "div",
3368
+ {
3369
+ style: {
3370
+ display: "flex",
3371
+ flexDirection: "column",
3372
+ alignItems: "center",
3373
+ padding: "8px calc(var(--dsh-composer-side-clearance) + 16px) 12px"
3374
+ },
3375
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3376
+ "div",
3377
+ {
3378
+ style: {
3379
+ overflow: "hidden",
3380
+ width: "100%",
3381
+ maxWidth: "var(--dsh-chat-content-width)",
3382
+ border: "1px solid var(--dsw-alias-state-warn-secondary)",
3383
+ borderRadius: "20px",
3384
+ background: "var(--dsw-specific-input-major)",
3385
+ boxShadow: "var(--dsw-shadow-lv2)"
3386
+ },
3387
+ children: [
3388
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3389
+ "div",
3390
+ {
3391
+ style: {
3392
+ display: "flex",
3393
+ alignItems: "center",
3394
+ gap: "8px",
3395
+ padding: "10px 16px",
3396
+ background: "var(--dsw-alias-state-warn-tertiary)",
3397
+ color: "var(--dsw-alias-state-warn-primary)",
3398
+ fontSize: "13px",
3399
+ lineHeight: "18px"
3400
+ },
3401
+ children: [
3402
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3403
+ "span",
3404
+ {
3405
+ style: {
3406
+ width: "8px",
3407
+ height: "8px",
3408
+ borderRadius: "50%",
3409
+ background: "var(--dsw-alias-state-warn-primary)"
3410
+ }
3411
+ }
3412
+ ),
3413
+ t("remountWaiting")
3414
+ ]
3415
+ }
3416
+ ),
3417
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3418
+ "div",
3419
+ {
3420
+ style: {
3421
+ boxSizing: "border-box",
3422
+ maxHeight: "var(--dsh-composer-text-max-height)",
3423
+ overflowY: "auto",
3424
+ padding: "12px 16px 0"
3425
+ },
3426
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3427
+ "div",
3428
+ {
3429
+ style: {
3430
+ color: "var(--dsw-alias-label-primary)",
3431
+ fontSize: "15px",
3432
+ fontWeight: 500,
3433
+ lineHeight: "24px",
3434
+ whiteSpace: "pre-line"
3435
+ },
3436
+ children: matched.reason ?? ""
3437
+ }
3438
+ )
3439
+ }
3440
+ ),
3441
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3442
+ "div",
3443
+ {
3444
+ style: {
3445
+ display: "flex",
3446
+ justifyContent: "flex-end",
3447
+ gap: "8px",
3448
+ padding: "14px 16px"
3449
+ },
3450
+ children: [
3451
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3452
+ import_dsh_client_ui_primitives12.Button,
3453
+ {
3454
+ variant: "outline",
3455
+ size: "sm",
3456
+ disabled: answered,
3457
+ onClick: () => answer("rejected"),
3458
+ children: t("remountReject")
3459
+ }
3460
+ ),
3461
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3462
+ import_dsh_client_ui_primitives12.Button,
3463
+ {
3464
+ variant: "primary",
3465
+ size: "sm",
3466
+ disabled: answered,
3467
+ onClick: () => answer("allowed-once"),
3468
+ children: t("remountApprove")
3469
+ }
3470
+ )
3471
+ ]
3472
+ }
3473
+ )
3474
+ ]
3475
+ }
3476
+ )
3477
+ }
3478
+ );
3479
+ }
3480
+
3481
+ // src/client/tool-views.tsx
3482
+ var import_react13 = require("react");
3483
+ var import_dsh_client_ui_primitives13 = require("@deepseek-ai/dsh-client-ui-primitives");
3484
+
3485
+ // src/client/terminal-styles.ts
3486
+ var TERMINAL_CLASS = "dsh-podman-terminal";
3487
+ var TERMINAL_STYLES = `
3488
+ .dsh-podman-terminal {
3489
+ --dsl-terminal-font: var(--dsw-font-markdown-code-block-small);
3490
+ --dsl-terminal-line-height: 18px;
3491
+ --dsl-terminal-output-max-height: 224px;
3492
+ margin: 4px 0 4px 4px;
3493
+ border: 1px solid var(--dsw-alias-border-l1);
3494
+ }
3495
+ `;
3496
+ function installTerminalStyles(ctx) {
3497
+ if (typeof document === "undefined") return;
3498
+ ctx.effect(() => {
3499
+ const tag = document.createElement("style");
3500
+ tag.dataset.plugin = "@exagone313/dsh-podman";
3501
+ tag.textContent = TERMINAL_STYLES;
3502
+ document.head.appendChild(tag);
3503
+ return () => {
3504
+ tag.remove();
3505
+ };
3506
+ }, "podman: terminal styles");
3507
+ }
3508
+
3509
+ // src/client/tool-views.tsx
3510
+ var import_jsx_runtime14 = require("react/jsx-runtime");
3511
+ var TOOL_PRESENTATION = {
3512
+ container_bash: { titleKey: "toolTitle_container_bash", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconApiOutline14, { size: 14 }), summaryKeys: ["description", "command"] },
3513
+ container_exec: { titleKey: "toolTitle_container_exec", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconApiOutline14, { size: 14 }), summaryKeys: ["description", "argv"] },
3514
+ container_read: { titleKey: "toolTitle_container_read", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconBrowseOutline16, { size: 14 }), summaryKeys: ["file_path"] },
3515
+ container_write: { titleKey: "toolTitle_container_write", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconEditOutline16, { size: 14 }), summaryKeys: ["file_path"] },
3516
+ container_edit: { titleKey: "toolTitle_container_edit", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconEditOutline16, { size: 14 }), summaryKeys: ["file_path"] },
3517
+ container_glob: { titleKey: "toolTitle_container_glob", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconSearchOutline16, { size: 14 }), summaryKeys: ["pattern"] },
3518
+ container_grep: { titleKey: "toolTitle_container_grep", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconSearchOutline16, { size: 14 }), summaryKeys: ["pattern"] },
3519
+ container_list: { titleKey: "toolTitle_container_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconDataOutline16, { size: 14 }), summaryKeys: [] },
3520
+ container_start: { titleKey: "toolTitle_container_start", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlayOutline16, { size: 14 }), summaryKeys: ["container", "image"] },
3521
+ container_recreate: { titleKey: "toolTitle_container_recreate", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconRefreshOutline16, { size: 14 }), summaryKeys: ["container", "image"] },
3522
+ container_remove: { titleKey: "toolTitle_container_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["container"] },
3523
+ container_mount_list: { titleKey: "toolTitle_container_mount_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconFolderOpenOutline16, { size: 14 }), summaryKeys: ["container"] },
3524
+ container_mount_add: { titleKey: "toolTitle_container_mount_add", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconFolderOpenOutline16, { size: 14 }), summaryKeys: ["container", "kind"] },
3525
+ container_mount_remove: { titleKey: "toolTitle_container_mount_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["container"] },
3526
+ container_mount_update: { titleKey: "toolTitle_container_mount_update", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconRefreshOutline16, { size: 14 }), summaryKeys: ["container", "mode"] },
3527
+ container_path_set: { titleKey: "toolTitle_container_path_set", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconEditOutline16, { size: 14 }), summaryKeys: ["container"] },
3528
+ container_path_add: { titleKey: "toolTitle_container_path_add", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlusOutline16, { size: 14 }), summaryKeys: ["container", "path"] },
3529
+ container_path_remove: { titleKey: "toolTitle_container_path_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["container", "path"] },
3530
+ container_secret_add: { titleKey: "toolTitle_container_secret_add", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconLinkOutline16, { size: 14 }), summaryKeys: ["container", "env"] },
3531
+ container_secret_remove: { titleKey: "toolTitle_container_secret_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconLinkOutline16, { size: 14 }), summaryKeys: ["container", "env"] },
3532
+ image_list: { titleKey: "toolTitle_image_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconArchiveOutline20, { size: 14 }), summaryKeys: [] },
3533
+ image_get: { titleKey: "toolTitle_image_get", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconArchiveOutline20, { size: 14 }), summaryKeys: ["imageId"] },
3534
+ image_build: { titleKey: "toolTitle_image_build", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlusOutline16, { size: 14 }), summaryKeys: ["imageId", "parent"] },
3535
+ image_rebuild: { titleKey: "toolTitle_image_rebuild", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconRefreshOutline16, { size: 14 }), summaryKeys: ["imageId"] },
3536
+ image_rebuild_all: { titleKey: "toolTitle_image_rebuild_all", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconRefreshOutline16, { size: 14 }), summaryKeys: [] },
3537
+ image_remove: { titleKey: "toolTitle_image_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["imageId"] },
3538
+ volume_list: { titleKey: "toolTitle_volume_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconDataOutline16, { size: 14 }), summaryKeys: [] },
3539
+ volume_create: { titleKey: "toolTitle_volume_create", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlusOutline16, { size: 14 }), summaryKeys: ["name"] },
3540
+ volume_remove: { titleKey: "toolTitle_volume_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["name"] },
3541
+ secret_list: { titleKey: "toolTitle_secret_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconLinkOutline16, { size: 14 }), summaryKeys: [] },
3542
+ secret_create: { titleKey: "toolTitle_secret_create", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlusOutline16, { size: 14 }), summaryKeys: ["name"] },
3543
+ secret_remove: { titleKey: "toolTitle_secret_remove", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconTrashOutline16, { size: 14 }), summaryKeys: ["name"] },
3544
+ daemon_start: { titleKey: "toolTitle_daemon_start", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlayOutline16, { size: 14 }), summaryKeys: ["name"] },
3545
+ daemon_list: { titleKey: "toolTitle_daemon_list", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconPlayOutline16, { size: 14 }), summaryKeys: ["container"] },
3546
+ daemon_logs: { titleKey: "toolTitle_daemon_logs", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconBrowseOutline16, { size: 14 }), summaryKeys: ["name"] },
3547
+ daemon_restart: { titleKey: "toolTitle_daemon_restart", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconRefreshOutline16, { size: 14 }), summaryKeys: ["name"] },
3548
+ daemon_stop: { titleKey: "toolTitle_daemon_stop", icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconStopFill16, { size: 14 }), summaryKeys: ["name"] }
3549
+ };
3550
+ var TOOL_VIEW_KEYS = Object.keys(TOOL_PRESENTATION);
3551
+ var sepStyle = {
3552
+ flex: "none",
3553
+ width: "2px",
3554
+ height: "2px",
3555
+ borderRadius: "1px",
3556
+ margin: "0 8px",
3557
+ background: "var(--dsw-alias-label-caption)"
3558
+ };
3559
+ var summaryStyle = {
3560
+ flex: "1 1 auto",
3561
+ minWidth: 0,
3562
+ overflow: "hidden",
3563
+ textOverflow: "ellipsis",
3564
+ whiteSpace: "nowrap",
3565
+ fontSize: "14px",
3566
+ lineHeight: "24px",
3567
+ color: "var(--dsw-alias-label-tertiary)"
3568
+ };
3569
+ var errorSummaryStyle = {
3570
+ ...summaryStyle,
3571
+ color: "var(--dsw-alias-state-error-primary)"
3572
+ };
3573
+ var bodyStyle = {
3574
+ margin: 0,
3575
+ padding: "8px 10px",
3576
+ maxHeight: "320px",
3577
+ overflow: "auto",
3578
+ fontFamily: "var(--dsw-font-mono, monospace)",
3579
+ fontSize: "12px",
3580
+ lineHeight: 1.5,
3581
+ whiteSpace: "pre-wrap",
3582
+ wordBreak: "break-word",
3583
+ background: "var(--dsw-alias-bg-layer-3)",
3584
+ border: "1px solid var(--dsw-alias-border-l2)",
3585
+ borderRadius: "8px"
3586
+ };
3587
+ var errorBodyStyle = {
3588
+ ...bodyStyle,
3589
+ color: "var(--dsw-alias-state-error-primary)"
3590
+ };
3591
+ function firstLine(text) {
3592
+ const newline = text.indexOf("\n");
3593
+ return newline === -1 ? text : text.slice(0, newline);
3594
+ }
3595
+ function parseArgs(argsRaw) {
3596
+ try {
3597
+ const parsed = JSON.parse(argsRaw);
3598
+ return typeof parsed === "object" && parsed !== null ? parsed : {};
3599
+ } catch {
3600
+ return {};
3601
+ }
3602
+ }
3603
+ function argSummary(args, keys, fallback) {
3604
+ for (const key of keys) {
3605
+ const value = args[key];
3606
+ if (typeof value === "string" && value !== "") return firstLine(value);
3607
+ if (Array.isArray(value) && value.length > 0) {
3608
+ return firstLine(value.map((item) => String(item)).join(" "));
3609
+ }
3610
+ }
3611
+ return fallback;
3612
+ }
3613
+ function resultText(block) {
3614
+ if (!("kind" in block)) return null;
3615
+ const parts = [];
3616
+ for (const item of block.content) {
3617
+ parts.push(item.type === "text" ? item.text : JSON.stringify(item, null, 2));
3618
+ }
3619
+ if (parts.length === 0 && block.error !== void 0) {
3620
+ parts.push(`${block.error.name}: ${block.error.code}`);
3621
+ }
3622
+ return parts.join("\n") || null;
3623
+ }
3624
+ function prettyOutput(text) {
3625
+ if (text === null) return null;
3626
+ try {
3627
+ const data = JSON.parse(text);
3628
+ if (typeof data === "object" && data !== null) {
3629
+ const record = data;
3630
+ if ("stdout" in record || "stderr" in record) {
3631
+ return [record.stdout, record.stderr].filter((value) => typeof value === "string" && value !== "").join("");
3632
+ }
3633
+ }
3634
+ } catch {
3635
+ }
3636
+ return text;
3637
+ }
3638
+ function terminalCard(toolName, args, block, cwd) {
3639
+ if (toolName !== "container_bash" && toolName !== "container_exec") return null;
3640
+ const command = toolName === "container_bash" ? typeof args.command === "string" ? args.command : "" : Array.isArray(args.argv) ? args.argv.map((word) => String(word)).join(" ") : "";
3641
+ const workdir = typeof args.workdir === "string" && args.workdir !== "" ? args.workdir : void 0;
3642
+ const base = {
3643
+ command,
3644
+ cwd: workdir ?? cwd,
3645
+ running: !("kind" in block)
3646
+ };
3647
+ if (!("kind" in block)) return base;
3648
+ if (block.isError) return null;
3649
+ const text = resultText(block);
3650
+ if (text === null) return null;
3651
+ try {
3652
+ const data = JSON.parse(text);
3653
+ if (typeof data !== "object" || data === null) return null;
3654
+ const record = data;
3655
+ const output = [record.stdout, record.stderr].filter((value) => typeof value === "string" && value !== "").join("");
3656
+ const signal = typeof record.signal === "string" && record.signal !== "" ? record.signal : void 0;
3657
+ return {
3658
+ ...base,
3659
+ output,
3660
+ ...signal !== void 0 ? { signal } : { exitCode: typeof record.exitCode === "number" ? record.exitCode : 0 }
3661
+ };
3662
+ } catch {
3663
+ return null;
3664
+ }
3665
+ }
3666
+ function terminalLabels(t) {
3667
+ return {
3668
+ signal: (signal) => t("terminalSignal", { signal }),
3669
+ exitCode: (code) => t("terminalExitCode", { code }),
3670
+ running: t("terminalRunning"),
3671
+ failed: t("terminalFailed"),
3672
+ done: t("terminalDone"),
3673
+ copy: t("copy"),
3674
+ copied: t("copied"),
3675
+ noOutput: t("terminalNoOutput"),
3676
+ collapseAria: t("terminalCollapseAria"),
3677
+ collapse: t("collapse"),
3678
+ expandAria: (hidden) => t("terminalExpandAria", { n: hidden }),
3679
+ expand: (hidden) => t("terminalExpandRest", { n: hidden })
3680
+ };
3681
+ }
3682
+ function PodmanToolRow({
3683
+ toolName,
3684
+ block,
3685
+ cwd,
3686
+ home,
3687
+ inspect,
3688
+ t
3689
+ }) {
3690
+ const presentation = TOOL_PRESENTATION[toolName];
3691
+ const title = presentation === void 0 ? toolName : t(presentation.titleKey);
3692
+ const settled = "kind" in block;
3693
+ const argsRaw = (settled ? block.call?.argsRaw : block.argsRaw) ?? "";
3694
+ const args = parseArgs(argsRaw);
3695
+ const terminal = terminalCard(toolName, args, block, cwd);
3696
+ const state = !settled ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError ? "error" : "done";
3697
+ const output = prettyOutput(resultText(block));
3698
+ const failureLine = state === "error" && output !== null && output !== "" ? firstLine(output) : null;
3699
+ const summary = failureLine ?? argSummary(args, presentation?.summaryKeys ?? [], firstLine(argsRaw) || block.callId);
3700
+ const [expanded, setExpanded] = (0, import_react13.useState)(false);
3701
+ const expandable = terminal !== null || output !== null && output !== "";
3702
+ const leading = state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.StateDot, { state: "error" }) : state === "stopped" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.StateDot, { state: "warning" }) : presentation?.icon ?? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives13.IconSparkle16, { size: 14 });
3703
+ void inspect;
3704
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3705
+ import_dsh_client_ui_primitives13.DisclosureRow,
3706
+ {
3707
+ icon: leading,
3708
+ title,
3709
+ open: expanded && expandable,
3710
+ expandable,
3711
+ onToggle: () => setExpanded((value) => !value),
3712
+ expandOnRowClick: true,
3713
+ keepContentWhenOpen: true,
3714
+ collapsedContent: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3715
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: sepStyle, "aria-hidden": true }),
3716
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: failureLine !== null ? errorSummaryStyle : summaryStyle, children: summary })
3717
+ ] }),
3718
+ children: terminal !== null ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3719
+ import_dsh_client_ui_primitives13.TerminalBlock,
3720
+ {
3721
+ command: terminal.command,
3722
+ cwd: terminal.cwd,
3723
+ home,
3724
+ output: terminal.output,
3725
+ exitCode: terminal.exitCode,
3726
+ signal: terminal.signal,
3727
+ running: terminal.running,
3728
+ maxLines: Infinity,
3729
+ className: TERMINAL_CLASS,
3730
+ labels: terminalLabels(t)
3731
+ }
3732
+ ) : expandable ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { style: state === "error" ? errorBodyStyle : bodyStyle, children: output }) : null
3733
+ }
3734
+ );
3735
+ }
3736
+
3737
+ // src/client/container-card-controller.ts
3738
+ var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
3739
+
3740
+ // src/client/card-protocol.ts
3741
+ var CARD_PATH = "/api/podman/card";
3742
+
3743
+ // src/client/card-client.ts
3744
+ var CARD_URL = CARD_PATH;
3745
+ async function failure(response) {
3746
+ try {
3747
+ const body = await response.json();
3748
+ if (typeof body.error === "string" && body.error !== "") {
3749
+ return new Error(body.error);
3750
+ }
3751
+ } catch {
3752
+ }
3753
+ return new Error(`card request failed (${response.status})`);
3754
+ }
3755
+ function createCardClient() {
3756
+ return {
3757
+ async snapshot() {
3758
+ const response = await fetch(CARD_URL, {
3759
+ headers: { accept: "application/json" }
3760
+ });
3761
+ if (!response.ok) throw await failure(response);
3762
+ return await response.json();
3763
+ },
3764
+ async command(request) {
3765
+ const response = await fetch(CARD_URL, {
3766
+ method: "POST",
3767
+ headers: {
3768
+ accept: "application/json",
3769
+ "content-type": "application/json"
3770
+ },
3771
+ body: JSON.stringify({ command: request })
3772
+ });
3773
+ if (!response.ok) throw await failure(response);
3774
+ return await response.json();
3775
+ }
3776
+ };
3777
+ }
3778
+
3779
+ // src/client/container-card-controller.ts
3780
+ var CONTAINER_NS = "podman";
3781
+ var EMPTY_SNAPSHOT = {
3782
+ version: "",
3783
+ commit: "",
3784
+ projectsRoot: "",
3785
+ workspaces: [],
3786
+ containers: [],
3787
+ images: [],
3788
+ volumes: [],
3789
+ secrets: [],
3790
+ caches: []
3791
+ };
3792
+ var ContainerCardController = class {
3793
+ constructor(scope, client = createCardClient()) {
3794
+ __publicField(this, "scope", scope);
3795
+ __publicField(this, "store");
3796
+ __publicField(this, "drafts", /* @__PURE__ */ new Map());
3797
+ __publicField(this, "client");
3798
+ __publicField(this, "snapshot", EMPTY_SNAPSHOT);
3799
+ __publicField(this, "busy", false);
3800
+ __publicField(this, "notice", "");
3801
+ __publicField(this, "directoryPicker");
3802
+ this.client = client;
3803
+ this.store = (0, import_dsh_client_store.createSnapshotStore)(this.project());
3804
+ scope.subscribe(() => {
3805
+ this.publish();
3806
+ });
3807
+ void this.reload();
3808
+ }
3809
+ draft(field, current) {
3810
+ return this.drafts.get(field) ?? current;
3811
+ }
3812
+ project() {
3813
+ const snapshot = this.scope.getSnapshot();
3814
+ const value = snapshot.value;
3815
+ return {
3816
+ available: snapshot.status === "ready" && value !== void 0,
3817
+ writable: snapshot.writable,
3818
+ busy: this.busy,
3819
+ notice: this.notice,
3820
+ version: this.snapshot.version,
3821
+ commit: this.snapshot.commit,
3822
+ defaultImage: value?.defaultImage ?? "",
3823
+ defaultImageDraft: this.draft("defaultImage", value?.defaultImage ?? ""),
3824
+ socketsRoot: value?.socketsRoot ?? "",
3825
+ socketsRootDraft: this.draft("socketsRoot", value?.socketsRoot ?? ""),
3826
+ projectsRoot: this.snapshot.projectsRoot,
3827
+ ...this.directoryPicker === void 0 ? {} : { directoryPicker: this.directoryPicker },
3828
+ workspaces: this.snapshot.workspaces,
3829
+ containers: this.snapshot.containers,
3830
+ images: this.snapshot.images,
3831
+ volumes: this.snapshot.volumes,
3832
+ secrets: this.snapshot.secrets,
3833
+ caches: this.snapshot.caches
3834
+ };
3835
+ }
3836
+ publish() {
3837
+ this.store.set(this.project());
3838
+ }
3839
+ // setDirectoryPicker records the harness's directory picker (or clears it)
3840
+ // and republishes, so the card shows or hides the browse affordance.
3841
+ setDirectoryPicker(picker) {
3842
+ this.directoryPicker = picker;
3843
+ this.publish();
3844
+ }
3845
+ command(op, workspace, image, extra = {}) {
3846
+ void this.dispatch({
3847
+ op,
3848
+ workspace,
3849
+ image,
3850
+ projectName: extra.projectName ?? "",
3851
+ mounts: extra.mounts ?? [],
3852
+ paths: extra.paths ?? [],
3853
+ value: extra.value ?? "",
3854
+ env: extra.env ?? {},
3855
+ container: extra.container ?? "",
3856
+ secret: extra.secret ?? "",
3857
+ secretEnv: extra.secretEnv ?? "",
3858
+ length: extra.length ?? 0,
3859
+ charset: extra.charset ?? "",
3860
+ packages: extra.packages ?? [],
3861
+ secretEnvMap: extra.secretEnvMap ?? {},
3862
+ cacheMode: extra.cacheMode ?? "",
3863
+ mount: extra.mount ?? null
3864
+ });
3865
+ }
3866
+ async dispatch(request) {
3867
+ this.busy = true;
3868
+ this.notice = "";
3869
+ this.publish();
3870
+ try {
3871
+ const result = await this.client.command(request);
3872
+ this.notice = result.notice ?? "";
3873
+ this.snapshot = await this.client.snapshot();
3874
+ } catch (error) {
3875
+ this.notice = error instanceof Error ? error.message : String(error);
3876
+ } finally {
3877
+ this.busy = false;
3878
+ this.publish();
3879
+ }
3880
+ }
3881
+ async reload() {
3882
+ try {
3883
+ this.snapshot = await this.client.snapshot();
3884
+ this.notice = "";
3885
+ } catch (error) {
3886
+ this.notice = error instanceof Error ? error.message : String(error);
3887
+ }
3888
+ this.publish();
3889
+ }
3890
+ edit(field, text) {
3891
+ this.drafts.set(field, text);
3892
+ this.publish();
3893
+ }
3894
+ save(field) {
3895
+ const draft = this.drafts.get(field);
3896
+ if (draft === void 0) return;
3897
+ void this.scope.set(field, draft);
3898
+ }
3899
+ discard(field) {
3900
+ this.drafts.delete(field);
3901
+ this.publish();
3902
+ }
3903
+ inject() {
3904
+ return {
3905
+ hooks: { containerCard: this.store },
3906
+ reload: () => {
3907
+ void this.reload();
3908
+ },
3909
+ remove: (workspace) => this.command("remove", workspace, ""),
3910
+ cleanCaches: (mode) => this.command("cache_clean", "", "", { cacheMode: mode }),
3911
+ removeWorkspace: (workspace) => this.command("workspace_remove", workspace, ""),
3912
+ recreate: (workspace, image, env) => this.command("recreate", workspace, image, { ...env ? { env } : {} }),
3913
+ createContainer: (workspace, config) => this.command(
3914
+ "create",
3915
+ workspace.workspaceSlug,
3916
+ config?.image ?? (workspace.imageId || this.defaultImage() || ""),
3917
+ {
3918
+ projectName: workspace.projectName,
3919
+ ...config?.mounts && config.mounts.length > 0 ? { mounts: config.mounts } : {},
3920
+ ...config?.env && Object.keys(config.env).length > 0 ? { env: config.env } : {},
3921
+ ...config?.paths && config.paths.length > 0 ? { paths: config.paths } : {},
3922
+ ...config?.secretEnv && Object.keys(config.secretEnv).length > 0 ? { secretEnvMap: config.secretEnv } : {}
3923
+ }
3924
+ ),
3925
+ startContainer: (workspace, container, config) => this.command(
3926
+ "create",
3927
+ workspace.workspaceSlug,
3928
+ config?.image ?? (workspace.imageId || this.defaultImage() || ""),
3929
+ {
3930
+ container,
3931
+ ...config?.mounts && config.mounts.length > 0 ? { mounts: config.mounts } : {},
3932
+ ...config?.env && Object.keys(config.env).length > 0 ? { env: config.env } : {},
3933
+ ...config?.paths && config.paths.length > 0 ? { paths: config.paths } : {},
3934
+ ...config?.secretEnv && Object.keys(config.secretEnv).length > 0 ? { secretEnvMap: config.secretEnv } : {}
3935
+ }
3936
+ ),
3937
+ addContainerMount: (workspace, container, mount) => this.command("container_mount_add", workspace, "", { container, mount }),
3938
+ removeContainerMount: (workspace, container, mount) => this.command("container_mount_remove", workspace, "", { container, mount }),
3939
+ updateContainerMount: (workspace, container, mount) => this.command("container_mount_update", workspace, "", { container, mount }),
3940
+ setContainerPaths: (workspace, container, paths) => this.command("container_path_set", workspace, "", { container, paths }),
3941
+ createVolume: (name2) => this.command("volume_create", name2, ""),
3942
+ removeVolume: (name2) => this.command("volume_remove", name2, ""),
3943
+ removeImage: (imageId) => this.command("image_remove", imageId, ""),
3944
+ rebuildImage: (imageId) => this.command("image_rebuild", imageId, ""),
3945
+ rebuildAllImages: () => this.command("image_rebuild_all", "", ""),
3946
+ buildImage: (imageId, parent, packages) => this.command("image_build", imageId, parent, { packages }),
3947
+ rebuildBaseImage: (name2) => this.command("image_base_rebuild", name2, ""),
3948
+ pullBaseImage: (name2) => this.command("image_base_pull", name2, ""),
3949
+ setDefaultImage: (name2) => {
3950
+ this.edit("defaultImage", name2);
3951
+ this.save("defaultImage");
3952
+ },
3953
+ createSecret: (name2, length, charset) => this.command("secret_create", name2, "", {
3954
+ ...length ? { length } : {},
3955
+ ...charset ? { charset } : {}
3956
+ }),
3957
+ removeSecret: (name2) => this.command("secret_remove", name2, ""),
3958
+ setSecret: (name2, value) => this.command("secret_set", name2, "", { value }),
3959
+ addContainerSecret: (workspace, envVar, secret) => this.command("container_secret_add", workspace, "", {
3960
+ container: "default",
3961
+ secretEnv: envVar,
3962
+ secret
3963
+ }),
3964
+ removeContainerSecret: (workspace, envVar) => this.command("container_secret_remove", workspace, "", {
3965
+ container: "default",
3966
+ secretEnv: envVar
3967
+ }),
3968
+ editDefaultImage: (text) => this.edit("defaultImage", text),
3969
+ saveDefaultImage: () => this.save("defaultImage"),
3970
+ discardDefaultImage: () => this.discard("defaultImage"),
3971
+ editSocketsRoot: (text) => this.edit("socketsRoot", text),
3972
+ saveSocketsRoot: () => this.save("socketsRoot"),
3973
+ discardSocketsRoot: () => this.discard("socketsRoot")
3974
+ };
3975
+ }
3976
+ defaultImage() {
3977
+ return this.scope.getSnapshot().value?.defaultImage ?? "";
3978
+ }
3979
+ };
3980
+
3981
+ // src/client/locales.ts
3982
+ var NS = "podman";
3983
+ var en = {
3984
+ cardTitle: "dsh-podman",
3985
+ cardDescription: "Manage the guest containers and their images.",
3986
+ reload: "Reload this view",
3987
+ reloading: "Reloading\u2026",
3988
+ notice: "Notice",
3989
+ configTitle: "Configuration",
3990
+ defaultImage: "Default image",
3991
+ socketsRoot: "Sockets root",
3992
+ projectsRoot: "Projects root",
3993
+ defaultImageHint: "Image used when a workspace has no image of its own.",
3994
+ save: "Save",
3995
+ discard: "Discard",
3996
+ workspacesTitle: "Workspaces",
3997
+ noContainers: "This workspace has no containers yet.",
3998
+ createContainer: "Create container",
3999
+ containersTitle: "Containers",
4000
+ containerName: "Container",
4001
+ workspace: "Workspace",
4002
+ image: "Image",
4003
+ status: "Status",
4004
+ created: "Created",
4005
+ projects: "Projects",
4006
+ remove: "Remove",
4007
+ removePod: "Remove pod",
4008
+ confirmRemovePod: "Remove this workspace's pod and all its containers? Volume and project data is kept.",
4009
+ recreate: "Recreate",
4010
+ recreateWithImage: "Recreate with image",
4011
+ imagesTitle: "Images",
4012
+ imageId: "Image ID",
4013
+ baseImage: "Base image",
4014
+ imageTag: "Tag",
4015
+ builtAt: "Built at",
4016
+ packages: "Packages",
4017
+ volumesTitle: "Volumes",
4018
+ createVolume: "Create volume",
4019
+ removeVolume: "Remove",
4020
+ volumeName: "Volume name",
4021
+ secretsTitle: "Secrets",
4022
+ createSecret: "Create secret",
4023
+ secretName: "Secret name",
4024
+ secretCharset: "Charset",
4025
+ setSecret: "Set value",
4026
+ removeSecret: "Remove",
4027
+ removeImage: "Remove",
4028
+ rebuildImage: "Rebuild",
4029
+ rebuildAllImages: "Rebuild all",
4030
+ buildImage: "Build image",
4031
+ build: "Build",
4032
+ buildImageTitle: "Build an image",
4033
+ pullImage: "Pull",
4034
+ setDefaultImage: "Set default",
4035
+ setDefaultImageTitle: "Set default image",
4036
+ baseImagesTitle: "Base images",
4037
+ customImagesTitle: "Custom images",
4038
+ primitive: "Primitive",
4039
+ packageManager: "Package manager",
4040
+ parent: "Parent",
4041
+ selectImage: "Select an image",
4042
+ cancel: "Cancel",
4043
+ removeTag: "Remove",
4044
+ env: "Env",
4045
+ secretEnv: "Secret env",
4046
+ envTitle: "Environment variables",
4047
+ envKey: "Key",
4048
+ envValue: "Value",
4049
+ addEnv: "Add",
4050
+ removeEnv: "Remove",
4051
+ secretLength: "Length",
4052
+ containerSecretsTitle: "Secret env vars",
4053
+ attachSecret: "Attach",
4054
+ secretEnvName: "Env var",
4055
+ detachSecret: "Detach",
4056
+ none: "None",
4057
+ unavailable: "The container plugin is not available.",
4058
+ busy: "Working\u2026",
4059
+ confirmTitle: "Confirm action",
4060
+ confirm: "Confirm",
4061
+ confirmRemoveContainer: "Remove the default container of this workspace?",
4062
+ confirmRecreate: "Recreate this container? Its ephemeral state is lost.",
4063
+ confirmRemoveImage: "Remove this image? Containers using it must be recreated from another image.",
4064
+ confirmRebuildImage: "Rebuild this image in place?",
4065
+ confirmRebuildAllImages: "Rebuild every image in dependency order (base first)?",
4066
+ confirmRemoveVolume: "Remove this volume and its data?",
4067
+ confirmSetSecret: "Overwrite this secret's value?",
4068
+ confirmRemoveSecret: "Remove this secret? Containers using it must drop it first.",
4069
+ confirmDetachSecret: "Detach this secret environment variable from the container?",
4070
+ mountsTitle: "Mounts",
4071
+ addMount: "Add mount",
4072
+ mountKind: "Kind",
4073
+ mountProject: "Project",
4074
+ mountProjectPath: "Project path",
4075
+ browse: "Browse\u2026",
4076
+ browseTitle: "Select a project directory",
4077
+ browseSelect: "Select this directory",
4078
+ browseLoading: "Loading\u2026",
4079
+ browseError: "Could not read this directory.",
4080
+ browseUnavailable: "This deployment has no directory picker.",
4081
+ browseHidden: "Show hidden",
4082
+ browseTruncated: "Too many folders to list; only the beginning is shown.",
4083
+ browseOutsideRoot: "Choose a directory inside the projects root.",
4084
+ mountDestination: "Destination",
4085
+ pathsTitle: "PATH additions",
4086
+ noPaths: "No PATH additions.",
4087
+ editPaths: "Edit PATH additions",
4088
+ addPath: "Path to add",
4089
+ add: "Add",
4090
+ moveUp: "Move up",
4091
+ moveDown: "Move down",
4092
+ apply: "Apply",
4093
+ dragToReorder: "Drag to reorder",
4094
+ remountWaiting: "Waiting for approval",
4095
+ remountApprove: "Remount & run",
4096
+ remountReject: "Reject",
4097
+ mountVolume: "Volume",
4098
+ mountSecret: "Secret",
4099
+ mountMode: "Mode",
4100
+ readOnly: "Read-only",
4101
+ readWrite: "Read-write",
4102
+ remountReadOnly: "Remount as read-only",
4103
+ remountReadWrite: "Remount as read-write",
4104
+ confirmRemountReadOnly: "Remount this mount as read-only and recreate the container?",
4105
+ confirmRemountReadWrite: "Remount this mount as read-write and recreate the container?",
4106
+ confirmRemoveMount: "Remove this mount from the container and recreate it?",
4107
+ cachesTitle: "Package caches",
4108
+ noCaches: "No package cache is configured.",
4109
+ cacheUsage: "{size} \xB7 {n} files",
4110
+ cacheKeepLatest: "Keep latest versions",
4111
+ confirmCacheKeepLatest: "Remove older cached package versions? Current versions are kept.",
4112
+ cacheRemoveAll: "Remove all",
4113
+ confirmCacheRemoveAll: "Remove every cached package? The next build re-downloads what it needs.",
4114
+ addContainer: "Add container",
4115
+ invalidContainerName: "Invalid container name",
4116
+ containerNameTaken: "Container name already exists",
4117
+ invalidName: "Start with a letter or digit; only letters, digits, '.', '_', '-' (max 64).",
4118
+ invalidImageId: "Start with a letter, digit, or '_'; only letters, digits, '.', '_', '-', '/', ':' (max 128).",
4119
+ terminalSignal: "signal {signal}",
4120
+ terminalExitCode: "exit code {code}",
4121
+ terminalRunning: "Running",
4122
+ terminalFailed: "Failed",
4123
+ terminalDone: "Done",
4124
+ terminalNoOutput: "No output",
4125
+ terminalCollapseAria: "Collapse output",
4126
+ terminalExpandAria: "Expand the remaining {n} output lines",
4127
+ terminalExpandRest: "\u2026 {n} more lines",
4128
+ toolTitle_container_bash: "Container bash",
4129
+ toolTitle_container_exec: "Container exec",
4130
+ toolTitle_container_read: "Container read",
4131
+ toolTitle_container_write: "Container write",
4132
+ toolTitle_container_edit: "Container edit",
4133
+ toolTitle_container_glob: "Container glob",
4134
+ toolTitle_container_grep: "Container grep",
4135
+ toolTitle_container_list: "List containers",
4136
+ toolTitle_container_start: "Start container",
4137
+ toolTitle_container_recreate: "Recreate container",
4138
+ toolTitle_container_remove: "Remove container",
4139
+ toolTitle_container_mount_list: "List mounts",
4140
+ toolTitle_container_mount_add: "Add mount",
4141
+ toolTitle_container_mount_remove: "Remove mount",
4142
+ toolTitle_container_mount_update: "Change mount mode",
4143
+ toolTitle_container_path_set: "Set PATH additions",
4144
+ toolTitle_container_path_add: "Add PATH entry",
4145
+ toolTitle_container_path_remove: "Remove PATH entry",
4146
+ toolTitle_container_secret_add: "Attach secret",
4147
+ toolTitle_container_secret_remove: "Detach secret",
4148
+ toolTitle_image_list: "List images",
4149
+ toolTitle_image_get: "Inspect image",
4150
+ toolTitle_image_build: "Build image",
4151
+ toolTitle_image_rebuild: "Rebuild image",
4152
+ toolTitle_image_rebuild_all: "Rebuild all images",
4153
+ toolTitle_image_remove: "Remove image",
4154
+ toolTitle_volume_list: "List volumes",
4155
+ toolTitle_volume_create: "Create volume",
4156
+ toolTitle_volume_remove: "Remove volume",
4157
+ toolTitle_secret_list: "List secrets",
4158
+ toolTitle_secret_create: "Create secret",
4159
+ toolTitle_secret_remove: "Remove secret",
4160
+ toolTitle_daemon_start: "Start daemon",
4161
+ toolTitle_daemon_list: "List daemons",
4162
+ toolTitle_daemon_logs: "Daemon logs",
4163
+ toolTitle_daemon_restart: "Restart daemon",
4164
+ toolTitle_daemon_stop: "Stop daemon"
4165
+ };
4166
+ var zh = {
4167
+ cardTitle: "dsh-podman",
4168
+ cardDescription: "\u7BA1\u7406\u5DE5\u4F5C\u533A\u5BB9\u5668\u53CA\u5176\u955C\u50CF\u3002",
4169
+ reload: "\u5237\u65B0\u6B64\u89C6\u56FE",
4170
+ reloading: "\u5237\u65B0\u4E2D\u2026",
4171
+ notice: "\u63D0\u793A",
4172
+ configTitle: "\u914D\u7F6E",
4173
+ defaultImage: "\u9ED8\u8BA4\u955C\u50CF",
4174
+ socketsRoot: "\u5957\u63A5\u5B57\u6839\u76EE\u5F55",
4175
+ projectsRoot: "\u9879\u76EE\u6839\u76EE\u5F55",
4176
+ defaultImageHint: "\u5DE5\u4F5C\u533A\u6CA1\u6709\u81EA\u5E26\u955C\u50CF\u65F6\u4F7F\u7528\u7684\u955C\u50CF\u3002",
4177
+ save: "\u4FDD\u5B58",
4178
+ discard: "\u653E\u5F03",
4179
+ workspacesTitle: "\u5DE5\u4F5C\u533A",
4180
+ noContainers: "\u8BE5\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u5BB9\u5668\u3002",
4181
+ createContainer: "\u521B\u5EFA\u5BB9\u5668",
4182
+ containersTitle: "\u5BB9\u5668",
4183
+ containerName: "\u5BB9\u5668",
4184
+ workspace: "\u5DE5\u4F5C\u533A",
4185
+ image: "\u955C\u50CF",
4186
+ status: "\u72B6\u6001",
4187
+ created: "\u521B\u5EFA\u65F6\u95F4",
4188
+ projects: "\u9879\u76EE",
4189
+ remove: "\u79FB\u9664",
4190
+ removePod: "\u79FB\u9664 Pod",
4191
+ confirmRemovePod: "\u79FB\u9664\u8BE5\u5DE5\u4F5C\u533A\u7684 Pod \u53CA\u5176\u6240\u6709\u5BB9\u5668\uFF1F\u5377\u548C\u9879\u76EE\u6570\u636E\u4F1A\u4FDD\u7559\u3002",
4192
+ recreate: "\u91CD\u5EFA",
4193
+ recreateWithImage: "\u4F7F\u7528\u955C\u50CF\u91CD\u5EFA",
4194
+ imagesTitle: "\u955C\u50CF",
4195
+ imageId: "\u955C\u50CF ID",
4196
+ baseImage: "\u57FA\u7840\u955C\u50CF",
4197
+ imageTag: "\u6807\u7B7E",
4198
+ builtAt: "\u6784\u5EFA\u65F6\u95F4",
4199
+ packages: "\u8F6F\u4EF6\u5305",
4200
+ volumesTitle: "\u5377",
4201
+ createVolume: "\u521B\u5EFA\u5377",
4202
+ removeVolume: "\u79FB\u9664",
4203
+ volumeName: "\u5377\u540D\u79F0",
4204
+ secretsTitle: "\u673A\u5BC6",
4205
+ createSecret: "\u521B\u5EFA\u673A\u5BC6",
4206
+ secretName: "\u673A\u5BC6\u540D\u79F0",
4207
+ secretCharset: "\u5B57\u7B26\u96C6",
4208
+ setSecret: "\u8BBE\u7F6E\u503C",
4209
+ removeSecret: "\u79FB\u9664",
4210
+ removeImage: "\u79FB\u9664",
4211
+ rebuildImage: "\u91CD\u5EFA",
4212
+ rebuildAllImages: "\u91CD\u5EFA\u5168\u90E8",
4213
+ buildImage: "\u6784\u5EFA\u955C\u50CF",
4214
+ build: "\u6784\u5EFA",
4215
+ buildImageTitle: "\u6784\u5EFA\u955C\u50CF",
4216
+ pullImage: "\u62C9\u53D6",
4217
+ setDefaultImage: "\u8BBE\u4E3A\u9ED8\u8BA4",
4218
+ setDefaultImageTitle: "\u8BBE\u7F6E\u9ED8\u8BA4\u955C\u50CF",
4219
+ baseImagesTitle: "\u57FA\u7840\u955C\u50CF",
4220
+ customImagesTitle: "\u81EA\u5B9A\u4E49\u955C\u50CF",
4221
+ primitive: "\u6E90\u955C\u50CF",
4222
+ packageManager: "\u5305\u7BA1\u7406\u5668",
4223
+ parent: "\u7236\u955C\u50CF",
4224
+ selectImage: "\u9009\u62E9\u955C\u50CF",
4225
+ cancel: "\u53D6\u6D88",
4226
+ removeTag: "\u79FB\u9664",
4227
+ env: "\u73AF\u5883\u53D8\u91CF",
4228
+ secretEnv: "\u673A\u5BC6\u73AF\u5883\u53D8\u91CF",
4229
+ envTitle: "\u73AF\u5883\u53D8\u91CF",
4230
+ envKey: "\u952E",
4231
+ envValue: "\u503C",
4232
+ addEnv: "\u6DFB\u52A0",
4233
+ removeEnv: "\u79FB\u9664",
4234
+ secretLength: "\u957F\u5EA6",
4235
+ containerSecretsTitle: "\u673A\u5BC6\u73AF\u5883\u53D8\u91CF",
4236
+ attachSecret: "\u6CE8\u5165",
4237
+ secretEnvName: "\u53D8\u91CF\u540D",
4238
+ detachSecret: "\u79FB\u9664",
4239
+ none: "\u65E0",
4240
+ unavailable: "\u5BB9\u5668\u63D2\u4EF6\u4E0D\u53EF\u7528\u3002",
4241
+ busy: "\u5904\u7406\u4E2D\u2026",
4242
+ confirmTitle: "\u786E\u8BA4\u64CD\u4F5C",
4243
+ confirm: "\u786E\u8BA4",
4244
+ confirmRemoveContainer: "\u79FB\u9664\u8BE5\u5DE5\u4F5C\u533A\u7684\u9ED8\u8BA4\u5BB9\u5668\uFF1F",
4245
+ confirmRecreate: "\u91CD\u5EFA\u8BE5\u5BB9\u5668\uFF1F\u5176\u4E34\u65F6\u72B6\u6001\u5C06\u4E22\u5931\u3002",
4246
+ confirmRemoveImage: "\u79FB\u9664\u8BE5\u955C\u50CF\uFF1F\u4F7F\u7528\u5B83\u7684\u5BB9\u5668\u9700\u8981\u7528\u5176\u4ED6\u955C\u50CF\u91CD\u5EFA\u3002",
4247
+ confirmRebuildImage: "\u5C31\u5730\u91CD\u5EFA\u8BE5\u955C\u50CF\uFF1F",
4248
+ confirmRebuildAllImages: "\u6309\u4F9D\u8D56\u987A\u5E8F\u91CD\u5EFA\u5168\u90E8\u955C\u50CF\uFF08\u5148\u57FA\u7840\u955C\u50CF\uFF09\uFF1F",
4249
+ confirmRemoveVolume: "\u79FB\u9664\u8BE5\u5377\u53CA\u5176\u6570\u636E\uFF1F",
4250
+ confirmSetSecret: "\u8986\u76D6\u8BE5\u673A\u5BC6\u7684\u503C\uFF1F",
4251
+ confirmRemoveSecret: "\u79FB\u9664\u8BE5\u673A\u5BC6\uFF1F\u4F7F\u7528\u5B83\u7684\u5BB9\u5668\u9700\u5148\u79FB\u9664\u6CE8\u5165\u3002",
4252
+ confirmDetachSecret: "\u4ECE\u5BB9\u5668\u4E0A\u79FB\u9664\u8BE5\u673A\u5BC6\u73AF\u5883\u53D8\u91CF\uFF1F",
4253
+ mountsTitle: "\u6302\u8F7D",
4254
+ addMount: "\u6DFB\u52A0\u6302\u8F7D",
4255
+ mountKind: "\u7C7B\u578B",
4256
+ mountProject: "\u9879\u76EE",
4257
+ mountProjectPath: "\u9879\u76EE\u8DEF\u5F84",
4258
+ browse: "\u6D4F\u89C8\u2026",
4259
+ browseTitle: "\u9009\u62E9\u9879\u76EE\u76EE\u5F55",
4260
+ browseSelect: "\u9009\u62E9\u6B64\u76EE\u5F55",
4261
+ browseLoading: "\u52A0\u8F7D\u4E2D\u2026",
4262
+ browseError: "\u65E0\u6CD5\u8BFB\u53D6\u6B64\u76EE\u5F55\u3002",
4263
+ browseUnavailable: "\u6B64\u90E8\u7F72\u6CA1\u6709\u76EE\u5F55\u9009\u62E9\u5668\u3002",
4264
+ browseHidden: "\u663E\u793A\u9690\u85CF\u9879",
4265
+ browseTruncated: "\u6587\u4EF6\u5939\u8FC7\u591A\uFF0C\u4EC5\u663E\u793A\u5F00\u5934\u90E8\u5206\u3002",
4266
+ browseOutsideRoot: "\u8BF7\u9009\u62E9\u9879\u76EE\u6839\u76EE\u5F55\u5185\u7684\u76EE\u5F55\u3002",
4267
+ mountDestination: "\u76EE\u6807\u8DEF\u5F84",
4268
+ pathsTitle: "PATH \u9644\u52A0\u9879",
4269
+ noPaths: "\u6CA1\u6709 PATH \u9644\u52A0\u9879\u3002",
4270
+ editPaths: "\u7F16\u8F91 PATH \u9644\u52A0\u9879",
4271
+ addPath: "\u8981\u6DFB\u52A0\u7684\u8DEF\u5F84",
4272
+ add: "\u6DFB\u52A0",
4273
+ moveUp: "\u4E0A\u79FB",
4274
+ moveDown: "\u4E0B\u79FB",
4275
+ apply: "\u5E94\u7528",
4276
+ dragToReorder: "\u62D6\u52A8\u4EE5\u91CD\u65B0\u6392\u5E8F",
4277
+ remountWaiting: "\u7B49\u5F85\u5BA1\u6279",
4278
+ remountApprove: "\u91CD\u65B0\u6302\u8F7D\u5E76\u8FD0\u884C",
4279
+ remountReject: "\u62D2\u7EDD",
4280
+ mountVolume: "\u5377",
4281
+ mountSecret: "\u673A\u5BC6",
4282
+ mountMode: "\u6A21\u5F0F",
4283
+ readOnly: "\u53EA\u8BFB",
4284
+ readWrite: "\u8BFB\u5199",
4285
+ remountReadOnly: "\u91CD\u65B0\u6302\u8F7D\u4E3A\u53EA\u8BFB",
4286
+ remountReadWrite: "\u91CD\u65B0\u6302\u8F7D\u4E3A\u8BFB\u5199",
4287
+ confirmRemountReadOnly: "\u5C06\u8BE5\u6302\u8F7D\u91CD\u65B0\u6302\u8F7D\u4E3A\u53EA\u8BFB\u5E76\u91CD\u5EFA\u5BB9\u5668\uFF1F",
4288
+ confirmRemountReadWrite: "\u5C06\u8BE5\u6302\u8F7D\u91CD\u65B0\u6302\u8F7D\u4E3A\u8BFB\u5199\u5E76\u91CD\u5EFA\u5BB9\u5668\uFF1F",
4289
+ confirmRemoveMount: "\u4ECE\u5BB9\u5668\u4E2D\u79FB\u9664\u8BE5\u6302\u8F7D\u5E76\u91CD\u5EFA\u5BB9\u5668\uFF1F",
4290
+ cachesTitle: "\u8F6F\u4EF6\u5305\u7F13\u5B58",
4291
+ noCaches: "\u672A\u914D\u7F6E\u8F6F\u4EF6\u5305\u7F13\u5B58\u3002",
4292
+ cacheUsage: "{size} \xB7 {n} \u4E2A\u6587\u4EF6",
4293
+ cacheKeepLatest: "\u4FDD\u7559\u6700\u65B0\u7248\u672C",
4294
+ confirmCacheKeepLatest: "\u79FB\u9664\u8F83\u65E7\u7684\u7F13\u5B58\u8F6F\u4EF6\u5305\u7248\u672C\uFF1F\u5F53\u524D\u7248\u672C\u4F1A\u4FDD\u7559\u3002",
4295
+ cacheRemoveAll: "\u5168\u90E8\u79FB\u9664",
4296
+ confirmCacheRemoveAll: "\u79FB\u9664\u6240\u6709\u7F13\u5B58\u7684\u8F6F\u4EF6\u5305\uFF1F\u4E0B\u6B21\u6784\u5EFA\u4F1A\u91CD\u65B0\u4E0B\u8F7D\u6240\u9700\u5185\u5BB9\u3002",
4297
+ addContainer: "\u6DFB\u52A0\u5BB9\u5668",
4298
+ invalidContainerName: "\u5BB9\u5668\u540D\u79F0\u65E0\u6548",
4299
+ containerNameTaken: "\u5BB9\u5668\u540D\u79F0\u5DF2\u5B58\u5728",
4300
+ invalidName: "\u4EE5\u5B57\u6BCD\u6216\u6570\u5B57\u5F00\u5934\uFF0C\u4EC5\u53EF\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001'.'\u3001'_'\u3001'-'\uFF08\u6700\u957F 64 \u4E2A\u5B57\u7B26\uFF09\u3002",
4301
+ invalidImageId: "\u4EE5\u5B57\u6BCD\u3001\u6570\u5B57\u6216 '_' \u5F00\u5934\uFF0C\u4EC5\u53EF\u4F7F\u7528\u5B57\u6BCD\u3001\u6570\u5B57\u3001'.'\u3001'_'\u3001'-'\u3001'/'\u3001':'\uFF08\u6700\u957F 128 \u4E2A\u5B57\u7B26\uFF09\u3002",
4302
+ terminalSignal: "\u4FE1\u53F7 {signal}",
4303
+ terminalExitCode: "\u9000\u51FA\u7801 {code}",
4304
+ terminalRunning: "\u8FD0\u884C\u4E2D",
4305
+ terminalFailed: "\u5931\u8D25",
4306
+ terminalDone: "\u5DF2\u5B8C\u6210",
4307
+ terminalNoOutput: "\u65E0\u8F93\u51FA",
4308
+ terminalCollapseAria: "\u6536\u8D77\u8F93\u51FA",
4309
+ terminalExpandAria: "\u5C55\u5F00\u5176\u4F59 {n} \u884C\u8F93\u51FA",
4310
+ terminalExpandRest: "\u2026 \u5176\u4F59 {n} \u884C",
4311
+ toolTitle_container_bash: "\u5BB9\u5668 Bash",
4312
+ toolTitle_container_exec: "\u5BB9\u5668\u6267\u884C",
4313
+ toolTitle_container_read: "\u8BFB\u53D6\u5BB9\u5668\u6587\u4EF6",
4314
+ toolTitle_container_write: "\u5199\u5165\u5BB9\u5668\u6587\u4EF6",
4315
+ toolTitle_container_edit: "\u7F16\u8F91\u5BB9\u5668\u6587\u4EF6",
4316
+ toolTitle_container_glob: "\u5BB9\u5668\u6587\u4EF6\u5339\u914D",
4317
+ toolTitle_container_grep: "\u5BB9\u5668\u6587\u4EF6\u641C\u7D22",
4318
+ toolTitle_container_list: "\u5217\u51FA\u5BB9\u5668",
4319
+ toolTitle_container_start: "\u542F\u52A8\u5BB9\u5668",
4320
+ toolTitle_container_recreate: "\u91CD\u5EFA\u5BB9\u5668",
4321
+ toolTitle_container_remove: "\u79FB\u9664\u5BB9\u5668",
4322
+ toolTitle_container_mount_list: "\u5217\u51FA\u6302\u8F7D",
4323
+ toolTitle_container_mount_add: "\u6DFB\u52A0\u6302\u8F7D",
4324
+ toolTitle_container_mount_remove: "\u79FB\u9664\u6302\u8F7D",
4325
+ toolTitle_container_mount_update: "\u66F4\u6539\u6302\u8F7D\u6A21\u5F0F",
4326
+ toolTitle_container_path_set: "\u8BBE\u7F6E PATH \u9644\u52A0\u9879",
4327
+ toolTitle_container_path_add: "\u6DFB\u52A0 PATH \u6761\u76EE",
4328
+ toolTitle_container_path_remove: "\u79FB\u9664 PATH \u6761\u76EE",
4329
+ toolTitle_container_secret_add: "\u6CE8\u5165\u673A\u5BC6",
4330
+ toolTitle_container_secret_remove: "\u79FB\u9664\u673A\u5BC6\u6CE8\u5165",
4331
+ toolTitle_image_list: "\u5217\u51FA\u955C\u50CF",
4332
+ toolTitle_image_get: "\u67E5\u770B\u955C\u50CF",
4333
+ toolTitle_image_build: "\u6784\u5EFA\u955C\u50CF",
4334
+ toolTitle_image_rebuild: "\u91CD\u5EFA\u955C\u50CF",
4335
+ toolTitle_image_rebuild_all: "\u91CD\u5EFA\u5168\u90E8\u955C\u50CF",
4336
+ toolTitle_image_remove: "\u79FB\u9664\u955C\u50CF",
4337
+ toolTitle_volume_list: "\u5217\u51FA\u5377",
4338
+ toolTitle_volume_create: "\u521B\u5EFA\u5377",
4339
+ toolTitle_volume_remove: "\u79FB\u9664\u5377",
4340
+ toolTitle_secret_list: "\u5217\u51FA\u673A\u5BC6",
4341
+ toolTitle_secret_create: "\u521B\u5EFA\u673A\u5BC6",
4342
+ toolTitle_secret_remove: "\u79FB\u9664\u673A\u5BC6",
4343
+ toolTitle_daemon_start: "\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B",
4344
+ toolTitle_daemon_list: "\u5217\u51FA\u5B88\u62A4\u8FDB\u7A0B",
4345
+ toolTitle_daemon_logs: "\u5B88\u62A4\u8FDB\u7A0B\u65E5\u5FD7",
4346
+ toolTitle_daemon_restart: "\u91CD\u542F\u5B88\u62A4\u8FDB\u7A0B",
4347
+ toolTitle_daemon_stop: "\u505C\u6B62\u5B88\u62A4\u8FDB\u7A0B"
4348
+ };
4349
+
4350
+ // src/client/index.ts
4351
+ var name = "podman";
4352
+ var inject = ["slots", "locale", "settingsScope"];
4353
+ function apply(ctx) {
4354
+ installTerminalStyles(ctx);
4355
+ installDirectoryStyles(ctx);
4356
+ ctx.effect(
4357
+ () => ctx.locale.register(NS, { en, zh }),
4358
+ "podman: dictionaries"
4359
+ );
4360
+ const scope = ctx.settingsScope.bind({
4361
+ namespace: CONTAINER_NS,
4362
+ decode: (section) => typeof section === "object" && section !== null ? section : void 0
4363
+ });
4364
+ const syncLocale = () => {
4365
+ const snapshot = scope.getSnapshot();
4366
+ if (snapshot.status !== "ready" || !snapshot.writable) return;
4367
+ const active = ctx.locale.getSnapshot().active;
4368
+ if (snapshot.value?.uiLocale === active) return;
4369
+ void scope.set("uiLocale", active);
4370
+ };
4371
+ syncLocale();
4372
+ scope.subscribe(syncLocale);
4373
+ ctx.effect(() => ctx.on("locale/change", syncLocale), "podman: locale sync");
4374
+ const controller = new ContainerCardController(scope);
4375
+ ctx.inject(["remote", "remote.directoryPicker"], (pickerCtx) => {
4376
+ controller.setDirectoryPicker(buildDirectoryPicker(pickerCtx.remote));
4377
+ pickerCtx.effect(() => () => {
4378
+ controller.setDirectoryPicker(void 0);
4379
+ }, "podman: directory picker");
4380
+ });
4381
+ ctx.slots.inject(
4382
+ "settings.plugin.item",
4383
+ () => ctx.slots.register(
4384
+ {
4385
+ name: "settings.plugin.item",
4386
+ key: CONTAINER_NS,
4387
+ locale: NS,
4388
+ inject: () => controller.inject()
4389
+ },
4390
+ ContainerCard
4391
+ )
4392
+ );
4393
+ for (const key of TOOL_VIEW_KEYS) {
4394
+ ctx.slots.inject(
4395
+ "tool.call.toolview",
4396
+ () => ctx.slots.register(
4397
+ { name: "tool.call.toolview", key, locale: NS },
4398
+ PodmanToolRow
4399
+ )
4400
+ );
4401
+ }
4402
+ ctx.slots.inject(
4403
+ "conversation.composer",
4404
+ () => ctx.slots.register(
4405
+ {
4406
+ name: "conversation.composer",
4407
+ priority: 0,
4408
+ locale: NS,
4409
+ select: ({ pendingInteraction }) => {
4410
+ const pending = pendingInteraction;
4411
+ return pending?.kind === "approval" && typeof pending.toolName === "string" && pending.toolName.startsWith(BUILTIN_PROMPT_PREFIX) ? pending : null;
4412
+ }
4413
+ },
4414
+ ReadOnlyApprovalPanel
4415
+ )
4416
+ );
4417
+ }
4418
+
4419
+ return module.exports; } });