@aixnn/aixautots 0.0.0-stage → 0.5.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 (67) hide show
  1. package/README.md +239 -2
  2. package/dist/ScriptStudio-DaCqOF5H.d.ts +43 -0
  3. package/dist/agent-runner-V60B0is1.d.ts +57 -0
  4. package/dist/automation-queue-8HqRJV_K.d.ts +72 -0
  5. package/dist/chunk-536WVCTB.js +5744 -0
  6. package/dist/chunk-5BMFMDQR.js +18 -0
  7. package/dist/chunk-64Q7BBIQ.js +1347 -0
  8. package/dist/chunk-6YUAACW6.js +866 -0
  9. package/dist/chunk-AIUOLJZA.js +412 -0
  10. package/dist/chunk-CVV7FOMQ.js +175 -0
  11. package/dist/chunk-EHF2WQUR.js +2042 -0
  12. package/dist/chunk-EVHTAXQG.js +273 -0
  13. package/dist/chunk-FW23FLAF.js +56 -0
  14. package/dist/chunk-GKEPMDXO.js +410 -0
  15. package/dist/chunk-H7MHGYF3.js +341 -0
  16. package/dist/chunk-MRQ7VJFJ.js +1074 -0
  17. package/dist/chunk-NWFYTFMI.js +65 -0
  18. package/dist/chunk-OEZFYKL6.js +1 -0
  19. package/dist/chunk-PCYERBNZ.js +1564 -0
  20. package/dist/chunk-PUPVZRKZ.js +668 -0
  21. package/dist/chunk-SUKFJ73W.js +217 -0
  22. package/dist/config-Bm1hmXhD.d.ts +1380 -0
  23. package/dist/coords-LPR_MPyp.d.ts +22 -0
  24. package/dist/core/index.d.ts +135 -0
  25. package/dist/core/index.js +5 -0
  26. package/dist/device-normalize-BaThgnH7.d.ts +43 -0
  27. package/dist/device-session-KZVGLPOI.js +2 -0
  28. package/dist/i18n/index.d.ts +30 -0
  29. package/dist/i18n/index.js +1 -0
  30. package/dist/mirror-session-C_1vFkRV.d.ts +108 -0
  31. package/dist/nav/index.d.ts +19 -0
  32. package/dist/nav/index.js +1 -0
  33. package/dist/react/index.d.ts +487 -0
  34. package/dist/react/index.js +7 -0
  35. package/dist/script-debugger-Cw5jVRoz.d.ts +114 -0
  36. package/dist/task-agent-runner-eD9-SCJz.d.ts +160 -0
  37. package/dist/types-C2WXVcam.d.ts +1005 -0
  38. package/dist/ui/billing.d.ts +48 -0
  39. package/dist/ui/billing.js +425 -0
  40. package/dist/ui/device-create.d.ts +55 -0
  41. package/dist/ui/device-create.js +9 -0
  42. package/dist/ui/device-mirror.d.ts +42 -0
  43. package/dist/ui/device-mirror.js +10 -0
  44. package/dist/ui/devices.d.ts +223 -0
  45. package/dist/ui/devices.js +15 -0
  46. package/dist/ui/editor.d.ts +64 -0
  47. package/dist/ui/editor.js +344 -0
  48. package/dist/ui/index.d.ts +104 -0
  49. package/dist/ui/index.js +676 -0
  50. package/dist/ui/inspector.d.ts +5 -0
  51. package/dist/ui/inspector.js +1250 -0
  52. package/dist/ui/market.d.ts +10 -0
  53. package/dist/ui/market.js +60 -0
  54. package/dist/ui/mirror.d.ts +52 -0
  55. package/dist/ui/mirror.js +3 -0
  56. package/dist/ui/primitives/index.d.ts +101 -0
  57. package/dist/ui/primitives/index.js +1 -0
  58. package/dist/ui/script-studio.d.ts +85 -0
  59. package/dist/ui/script-studio.js +10 -0
  60. package/dist/ui/scripts.d.ts +18 -0
  61. package/dist/ui/scripts.js +210 -0
  62. package/dist/ui/tasks.d.ts +10 -0
  63. package/dist/ui/tasks.js +1039 -0
  64. package/dist/use-script-run-Diay7ibY.d.ts +50 -0
  65. package/package.json +76 -4
  66. package/styles.css +97 -0
  67. package/tailwind-preset.cjs +84 -0
@@ -0,0 +1,676 @@
1
+ export { ControlBar, MirrorView } from '../chunk-CVV7FOMQ.js';
2
+ import { Button, Input } from '../chunk-EVHTAXQG.js';
3
+ import { useScript, useEnvRun, useClient } from '../chunk-SUKFJ73W.js';
4
+ import '../chunk-GKEPMDXO.js';
5
+ import { envBlocker, summarizeEnv, detectEnvOs } from '../chunk-PCYERBNZ.js';
6
+ import '../chunk-NWFYTFMI.js';
7
+ import React4, { useState, useId, useRef, useEffect, useMemo } from 'react';
8
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
+ import CodeMirror, { EditorView } from '@uiw/react-codemirror';
10
+ import { javascript } from '@codemirror/lang-javascript';
11
+
12
+ var box = {
13
+ background: "var(--aix-bg, #161616)",
14
+ color: "var(--aix-fg, #e6e6e6)",
15
+ border: "1px solid var(--aix-border, #2a2a2a)",
16
+ borderRadius: "var(--aix-radius, 6px)",
17
+ font: "var(--aix-font, 13px/1.5 system-ui, sans-serif)",
18
+ display: "flex",
19
+ flexDirection: "column"
20
+ };
21
+ var mono = {
22
+ fontFamily: "var(--aix-mono, ui-monospace, Menlo, monospace)",
23
+ whiteSpace: "pre-wrap",
24
+ wordBreak: "break-all"
25
+ };
26
+ function DebugConsole({ events, onCall, onClear, className }) {
27
+ const [method, setMethod] = useState("");
28
+ const [argsText, setArgsText] = useState("[]");
29
+ const [err, setErr] = useState(null);
30
+ const doCall = () => {
31
+ if (!onCall) return;
32
+ let args;
33
+ try {
34
+ args = argsText.trim() === "" ? [] : JSON.parse(argsText);
35
+ } catch {
36
+ setErr("Invalid JSON in args");
37
+ return;
38
+ }
39
+ setErr(null);
40
+ onCall(method, args);
41
+ };
42
+ return /* @__PURE__ */ jsxs("div", { style: box, className, children: [
43
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "6px 10px", borderBottom: "1px solid var(--aix-border, #2a2a2a)" }, children: [
44
+ /* @__PURE__ */ jsx("strong", { children: "Events" }),
45
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onClear?.(), style: btn, children: "Clear" })
46
+ ] }),
47
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto", padding: "8px 10px", minHeight: 80 }, children: events.length === 0 ? /* @__PURE__ */ jsx("div", { style: { color: "var(--aix-muted, #888)" }, children: "No events yet." }) : events.map((e, i) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 6 }, children: [
48
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--aix-accent, #4f9cff)" }, children: e.name }),
49
+ /* @__PURE__ */ jsx("span", { style: { ...mono, marginLeft: 8 }, children: JSON.stringify(e.data) })
50
+ ] }, i)) }),
51
+ onCall && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, padding: "8px 10px", borderTop: "1px solid var(--aix-border, #2a2a2a)" }, children: [
52
+ /* @__PURE__ */ jsx("input", { placeholder: "method", value: method, onChange: (ev) => setMethod(ev.target.value), style: input }),
53
+ /* @__PURE__ */ jsx("input", { placeholder: "args (JSON array)", value: argsText, onChange: (ev) => setArgsText(ev.target.value), style: { ...input, ...mono, flex: 1 } }),
54
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: doCall, style: btn, children: "Call" })
55
+ ] }),
56
+ err && /* @__PURE__ */ jsx("div", { style: { color: "var(--aix-danger, #ff6b6b)", padding: "0 10px 8px" }, children: err })
57
+ ] });
58
+ }
59
+ var btn = {
60
+ background: "var(--aix-accent, #2d6cdf)",
61
+ color: "#fff",
62
+ border: "none",
63
+ borderRadius: "var(--aix-radius, 6px)",
64
+ padding: "4px 10px",
65
+ cursor: "pointer"
66
+ };
67
+ var input = {
68
+ background: "var(--aix-editor-bg, #1e1e1e)",
69
+ color: "var(--aix-editor-fg, #ddd)",
70
+ border: "1px solid var(--aix-border, #2a2a2a)",
71
+ borderRadius: "var(--aix-radius, 6px)",
72
+ padding: "4px 8px"
73
+ };
74
+ var AIX_CSS_VARS = [
75
+ "--aix-bg",
76
+ "--aix-fg",
77
+ "--aix-muted",
78
+ "--aix-accent",
79
+ "--aix-danger",
80
+ "--aix-border",
81
+ "--aix-radius",
82
+ "--aix-font",
83
+ "--aix-mono",
84
+ "--aix-editor-bg",
85
+ "--aix-editor-fg"
86
+ ];
87
+ function aixCodeMirrorTheme() {
88
+ return EditorView.theme({
89
+ "&": {
90
+ backgroundColor: "var(--aix-editor-bg, #1e1e1e)",
91
+ color: "var(--aix-editor-fg, #d4d4d4)",
92
+ fontFamily: "var(--aix-mono, ui-monospace, SFMono-Regular, Menlo, monospace)",
93
+ borderRadius: "var(--aix-radius, 6px)"
94
+ },
95
+ ".cm-gutters": {
96
+ backgroundColor: "var(--aix-editor-bg, #1e1e1e)",
97
+ color: "var(--aix-muted, #858585)",
98
+ border: "none"
99
+ },
100
+ ".cm-content": { caretColor: "var(--aix-accent, #4f9cff)" },
101
+ "&.cm-focused": { outline: "none" }
102
+ });
103
+ }
104
+ var wrap = {
105
+ background: "var(--aix-bg, #161616)",
106
+ border: "1px solid var(--aix-border, #2a2a2a)",
107
+ borderRadius: "var(--aix-radius, 6px)",
108
+ display: "flex",
109
+ flexDirection: "column",
110
+ overflow: "hidden"
111
+ };
112
+ var bar = {
113
+ display: "flex",
114
+ alignItems: "center",
115
+ gap: 8,
116
+ padding: "6px 10px",
117
+ borderBottom: "1px solid var(--aix-border, #2a2a2a)",
118
+ color: "var(--aix-fg, #e6e6e6)",
119
+ font: "var(--aix-font, 13px system-ui, sans-serif)"
120
+ };
121
+ var btn2 = {
122
+ background: "var(--aix-accent, #2d6cdf)",
123
+ color: "#fff",
124
+ border: "none",
125
+ borderRadius: "var(--aix-radius, 6px)",
126
+ padding: "4px 14px",
127
+ cursor: "pointer"
128
+ };
129
+ function ScriptEditor(props) {
130
+ const engineId = useId();
131
+ const engines = props.engines ?? ["frida", "scriptlet"];
132
+ return /* @__PURE__ */ jsxs("div", { style: wrap, className: props.className, children: [
133
+ /* @__PURE__ */ jsxs("div", { style: bar, children: [
134
+ /* @__PURE__ */ jsx("label", { htmlFor: engineId, children: "Engine" }),
135
+ /* @__PURE__ */ jsx(
136
+ "select",
137
+ {
138
+ id: engineId,
139
+ "aria-label": "engine",
140
+ value: props.engine,
141
+ onChange: (e) => props.onEngineChange(e.target.value),
142
+ style: { background: "var(--aix-editor-bg, #1e1e1e)", color: "var(--aix-editor-fg, #ddd)", border: "1px solid var(--aix-border, #2a2a2a)", borderRadius: "var(--aix-radius, 6px)", padding: "2px 6px" },
143
+ children: engines.map((e) => /* @__PURE__ */ jsx("option", { value: e, children: e }, e))
144
+ }
145
+ ),
146
+ /* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
147
+ props.running ? /* @__PURE__ */ jsx("button", { type: "button", onClick: props.onCancel, style: { ...btn2, background: "#b3402f" }, children: "Cancel" }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: props.onRun, style: btn2, children: "Run" })
148
+ ] }),
149
+ /* @__PURE__ */ jsx("div", { "data-testid": "aix-cm", children: /* @__PURE__ */ jsx(
150
+ CodeMirror,
151
+ {
152
+ value: props.value,
153
+ onChange: props.onChange,
154
+ extensions: [javascript({ typescript: true }), aixCodeMirrorTheme()],
155
+ basicSetup: { lineNumbers: true, foldGutter: false },
156
+ height: "240px"
157
+ }
158
+ ) })
159
+ ] });
160
+ }
161
+ function ScriptPanel({ deviceId, defaultEngine = "scriptlet", defaultScript = "", className }) {
162
+ const [engine, setEngine] = useState(defaultEngine);
163
+ const [script, setScript] = useState(defaultScript);
164
+ const { running, events, error, run, call, cancel, clearEvents } = useScript(deviceId, { engine });
165
+ return /* @__PURE__ */ jsxs("div", { className, style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
166
+ /* @__PURE__ */ jsx(
167
+ ScriptEditor,
168
+ {
169
+ value: script,
170
+ onChange: setScript,
171
+ engine,
172
+ onEngineChange: (e) => setEngine(e),
173
+ running,
174
+ onRun: () => {
175
+ void run(engine === "frida" ? { script, target: {} } : { script }).catch(() => {
176
+ });
177
+ },
178
+ onCancel: () => {
179
+ void cancel().catch(() => {
180
+ });
181
+ }
182
+ }
183
+ ),
184
+ error && /* @__PURE__ */ jsx("div", { style: { color: "var(--aix-danger, #ff6b6b)", font: "var(--aix-font, 13px system-ui)" }, children: error.message }),
185
+ /* @__PURE__ */ jsx(
186
+ DebugConsole,
187
+ {
188
+ events,
189
+ onClear: clearEvents,
190
+ onCall: (method, args) => {
191
+ void call(method, args).catch(() => {
192
+ });
193
+ }
194
+ }
195
+ )
196
+ ] });
197
+ }
198
+ var STATE_ICON = {
199
+ ok: "\u2713",
200
+ done: "\u2713",
201
+ skipped: "\u2298",
202
+ present: "\u2713",
203
+ running: "\u23F3",
204
+ missing: "\xB7",
205
+ pending: "\xB7",
206
+ failed: "\u2715",
207
+ error: "\u2715"
208
+ };
209
+ var stateColor = (s) => s === "failed" || s === "error" ? "var(--aix-danger, #e5484d)" : s === "ok" || s === "done" || s === "present" ? "var(--aix-accent, #2d6cdf)" : s === "running" ? "var(--aix-fg, #e6e6e6)" : "var(--aix-muted, #8a8a8a)";
210
+ var overlay = {
211
+ position: "fixed",
212
+ inset: 0,
213
+ background: "rgba(0,0,0,0.55)",
214
+ display: "flex",
215
+ alignItems: "center",
216
+ justifyContent: "center",
217
+ zIndex: 1e3
218
+ };
219
+ var card = {
220
+ width: "min(560px, 92vw)",
221
+ maxHeight: "86vh",
222
+ overflow: "auto",
223
+ background: "var(--aix-bg, #14161a)",
224
+ color: "var(--aix-fg, #e6e6e6)",
225
+ border: "1px solid var(--aix-border, #2a2e35)",
226
+ borderRadius: "var(--aix-radius, 10px)",
227
+ padding: "20px 22px",
228
+ font: "var(--aix-font, 14px/1.5 system-ui, sans-serif)",
229
+ boxShadow: "0 12px 40px rgba(0,0,0,0.5)"
230
+ };
231
+ var btn3 = (primary) => ({
232
+ background: primary ? "var(--aix-accent, #2d6cdf)" : "transparent",
233
+ color: primary ? "#fff" : "var(--aix-fg, #e6e6e6)",
234
+ border: primary ? "none" : "1px solid var(--aix-border, #2a2e35)",
235
+ borderRadius: "var(--aix-radius, 8px)",
236
+ padding: "7px 16px",
237
+ cursor: "pointer",
238
+ fontSize: 13
239
+ });
240
+ function EnvInitDialog(props) {
241
+ const { open, onClose, nodeId, os, route, mode = "prompt", seedEvents, onReady, onInstallWsl, title } = props;
242
+ const { events, finished, done, error, setup } = useEnvRun();
243
+ const [started, setStarted] = useState(false);
244
+ const [showLogs, setShowLogs] = useState(false);
245
+ const [installing, setInstalling] = useState(false);
246
+ const [wslFailed, setWslFailed] = useState(false);
247
+ const readyFired = useRef(false);
248
+ const wslTried = useRef(false);
249
+ useEffect(() => {
250
+ if (open) {
251
+ setStarted(false);
252
+ setShowLogs(false);
253
+ setInstalling(false);
254
+ setWslFailed(false);
255
+ readyFired.current = false;
256
+ wslTried.current = false;
257
+ }
258
+ }, [open, nodeId]);
259
+ const wslBlocked = done && envBlocker(finished) === "wsl-missing" && !!onInstallWsl;
260
+ const installWsl = React4.useCallback(async () => {
261
+ if (!onInstallWsl) return;
262
+ setInstalling(true);
263
+ setWslFailed(false);
264
+ try {
265
+ await onInstallWsl();
266
+ } catch {
267
+ setInstalling(false);
268
+ setWslFailed(true);
269
+ }
270
+ }, [onInstallWsl]);
271
+ useEffect(() => {
272
+ if (wslBlocked && !installing && !wslFailed && !wslTried.current) {
273
+ wslTried.current = true;
274
+ void installWsl();
275
+ }
276
+ }, [wslBlocked, installing, wslFailed, installWsl]);
277
+ const begin = React4.useCallback(() => {
278
+ setStarted(true);
279
+ void setup(nodeId, { os, route }).catch(() => {
280
+ });
281
+ }, [setup, nodeId, os, route]);
282
+ useEffect(() => {
283
+ if (open && mode === "auto" && !started) begin();
284
+ }, [open, mode, started, begin]);
285
+ useEffect(() => {
286
+ if (done && finished?.ok && !readyFired.current) {
287
+ readyFired.current = true;
288
+ onReady?.();
289
+ }
290
+ }, [done, finished, onReady]);
291
+ const summary = useMemo(
292
+ () => summarizeEnv(started ? events : seedEvents ?? []),
293
+ [started, events, seedEvents]
294
+ );
295
+ if (!open) return null;
296
+ const pct = summary.steps.length ? Math.round(summary.steps.reduce((a, s) => a + (s.state === "ok" || s.state === "done" || s.state === "skipped" || s.state === "present" ? 100 : s.pct), 0) / summary.steps.length) : 0;
297
+ const failed = !!error || done && !!finished && !finished.ok;
298
+ const success = done && finished?.ok;
299
+ return /* @__PURE__ */ jsx("div", { style: overlay, role: "dialog", "aria-modal": "true", onClick: (e) => {
300
+ if (e.target === e.currentTarget && !started) onClose();
301
+ }, children: /* @__PURE__ */ jsxs("div", { style: card, children: [
302
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 16, fontWeight: 600, marginBottom: 4 }, children: title ?? (os === "win" ? "Set up the Android host base (WSL2)" : "Set up the Android host base") }),
303
+ /* @__PURE__ */ jsx("div", { style: { color: "var(--aix-muted, #8a8a8a)", fontSize: 13, marginBottom: 16 }, children: success ? "Done \u2014 this machine can now run cloud phones." : wslBlocked && wslFailed ? "\u81EA\u52A8\u5B89\u88C5 WSL \u8FD0\u884C\u65F6\u5931\u8D25\uFF08\u53EF\u80FD\u5185\u7F51\u65E0\u6CD5\u4E0B\u8F7D\uFF09\u3002\u8BF7\u6309\u4E0B\u65B9\u6B65\u9AA4\u624B\u52A8\u4E0B\u8F7D\u5B89\u88C5\u540E\u91CD\u8BD5\u3002" : wslBlocked ? '\u9700\u8981\u5148\u5B89\u88C5 WSL \u8FD0\u884C\u65F6\uFF1A\u6B63\u5728\u81EA\u52A8\u4E0B\u8F7D\u5E76\u5B89\u88C5\uFF08\u9700\u5728 UAC \u5F39\u7A97\u70B9"\u662F"\uFF0C\u7EA6 250MB\uFF09\uFF0C\u5B8C\u6210\u540E\u4F1A\u81EA\u52A8\u91CD\u542F\u5E76\u7EE7\u7EED\u3002' : failed ? "Setup failed. Review the steps below and retry." : started ? "Installing the redroid base. This downloads ~1\u20132 GB and may take several minutes." : "This machine needs a one-time base (kernel + container runtime + image) to host cloud phones." }),
304
+ (started || summary.steps.length > 0) && /* @__PURE__ */ jsxs(Fragment, { children: [
305
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }, children: [
306
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 6, background: "var(--aix-border, #2a2e35)", borderRadius: 999, overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { width: `${pct}%`, height: "100%", background: failed ? "var(--aix-danger, #e5484d)" : "var(--aix-accent, #2d6cdf)", transition: "width .3s" } }) }),
307
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: "var(--aix-muted, #8a8a8a)", minWidth: 36, textAlign: "right", fontVariantNumeric: "tabular-nums" }, children: [
308
+ pct,
309
+ "%"
310
+ ] })
311
+ ] }),
312
+ started && events.length === 0 && !failed && /* @__PURE__ */ jsx("div", { role: "status", style: { color: "var(--aix-muted, #8a8a8a)", fontSize: 13, marginBottom: 12 }, children: "\u6B63\u5728\u8FDE\u63A5\u8282\u70B9\u5E76\u7B49\u5F85\u521D\u59CB\u5316\u6B65\u9AA4\u2026" }),
313
+ /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 8 }, children: summary.steps.map((s) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", alignItems: "baseline", gap: 10, fontSize: 13 }, children: [
314
+ /* @__PURE__ */ jsx("span", { style: { color: stateColor(s.state), width: 16, textAlign: "center" }, children: STATE_ICON[s.state] ?? "\xB7" }),
315
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1 }, children: [
316
+ s.label,
317
+ s.detail ? /* @__PURE__ */ jsxs("span", { style: { color: "var(--aix-muted, #8a8a8a)" }, children: [
318
+ " \u2014 ",
319
+ s.detail
320
+ ] }) : null
321
+ ] }),
322
+ s.state === "running" && /* @__PURE__ */ jsxs("span", { style: { color: "var(--aix-muted, #8a8a8a)" }, children: [
323
+ s.pct,
324
+ "%"
325
+ ] })
326
+ ] }, s.index)) })
327
+ ] }),
328
+ failed && finished?.error && /* @__PURE__ */ jsxs("div", { style: { marginTop: 12, padding: 10, background: "rgba(229,72,77,0.1)", border: "1px solid var(--aix-danger, #e5484d)", borderRadius: 8, fontSize: 13 }, children: [
329
+ finished.error,
330
+ finished.hint ? /* @__PURE__ */ jsxs("div", { style: { color: "var(--aix-muted, #8a8a8a)", marginTop: 4 }, children: [
331
+ "Hint: ",
332
+ finished.hint
333
+ ] }) : null
334
+ ] }),
335
+ error && !finished && /* @__PURE__ */ jsxs("div", { style: { marginTop: 12, color: "var(--aix-danger, #e5484d)", fontSize: 13 }, children: [
336
+ "Could not start setup: ",
337
+ error.message
338
+ ] }),
339
+ wslBlocked && wslFailed && /* @__PURE__ */ jsxs("div", { style: { marginTop: 12, padding: 12, background: "var(--aix-editor-bg, #0e0f12)", border: "1px solid var(--aix-border, #2a2e35)", borderRadius: 8, fontSize: 12.5, lineHeight: 1.6 }, children: [
340
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "\u624B\u52A8\u5B89\u88C5 WSL \u8FD0\u884C\u65F6\uFF08\u9700 Win10 21H2/19044+\uFF09" }),
341
+ /* @__PURE__ */ jsxs("ol", { style: { margin: 0, paddingLeft: 18 }, children: [
342
+ /* @__PURE__ */ jsxs("li", { children: [
343
+ "\u4E0B\u8F7D\uFF08\u7EA6 250MB\uFF09\uFF1A",
344
+ /* @__PURE__ */ jsx("br", {}),
345
+ /* @__PURE__ */ jsx("code", { style: { fontFamily: "var(--aix-mono, ui-monospace, Menlo, monospace)", wordBreak: "break-all" }, children: "https://github.com/microsoft/WSL/releases/latest" }),
346
+ /* @__PURE__ */ jsx("br", {}),
347
+ "\u9009 ",
348
+ /* @__PURE__ */ jsx("code", { children: "wsl.<\u7248\u672C>.x64.msi" }),
349
+ "\uFF08\u5185\u7F51\u673A\u53EF\u5728\u80FD\u8054\u7F51\u7684\u7535\u8111\u4E0B\u597D\u518D\u62F7\u8FC7\u6765\uFF09\u3002"
350
+ ] }),
351
+ /* @__PURE__ */ jsxs("li", { style: { marginTop: 4 }, children: [
352
+ "\u7BA1\u7406\u5458\u8FD0\u884C\uFF1A",
353
+ /* @__PURE__ */ jsx("br", {}),
354
+ /* @__PURE__ */ jsx("code", { style: { fontFamily: "var(--aix-mono, ui-monospace, Menlo, monospace)" }, children: "msiexec /i wsl.<\u7248\u672C>.x64.msi /quiet" }),
355
+ "\uFF08\u6216\u53CC\u51FB\u5B89\u88C5\uFF09\u3002"
356
+ ] }),
357
+ /* @__PURE__ */ jsxs("li", { style: { marginTop: 4 }, children: [
358
+ "\u91CD\u542F\u540E ",
359
+ /* @__PURE__ */ jsx("code", { children: "wsl --version" }),
360
+ " \u80FD\u663E\u793A\u7248\u672C\u5373\u6210\u529F\uFF0C\u518D\u70B9\u4E0B\u65B9\u300C\u91CD\u8BD5\u300D\u3002"
361
+ ] })
362
+ ] })
363
+ ] }),
364
+ started && summary.logs.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 12 }, children: [
365
+ /* @__PURE__ */ jsxs("button", { style: { ...btn3(), padding: "2px 0", border: "none", color: "var(--aix-muted, #8a8a8a)", fontSize: 12 }, onClick: () => setShowLogs((v) => !v), children: [
366
+ showLogs ? "\u25BE Hide logs" : "\u25B8 Show logs",
367
+ " (",
368
+ summary.logs.length,
369
+ ")"
370
+ ] }),
371
+ showLogs && /* @__PURE__ */ jsx("pre", { style: { marginTop: 6, maxHeight: 160, overflow: "auto", background: "var(--aix-editor-bg, #0e0f12)", color: "var(--aix-editor-fg, #cfcfcf)", padding: 10, borderRadius: 8, fontSize: 12, fontFamily: "var(--aix-mono, ui-monospace, Menlo, monospace)" }, children: summary.logs.slice(-200).join("\n") })
372
+ ] }),
373
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 18 }, children: success ? /* @__PURE__ */ jsx("button", { style: btn3(true), onClick: onClose, children: "Done" }) : wslBlocked && wslFailed ? /* @__PURE__ */ jsxs(Fragment, { children: [
374
+ /* @__PURE__ */ jsx("button", { style: btn3(), onClick: onClose, children: "\u5173\u95ED" }),
375
+ /* @__PURE__ */ jsx("button", { style: btn3(true), onClick: begin, children: "\u91CD\u8BD5\uFF08\u5DF2\u624B\u52A8\u88C5\u597D\uFF09" })
376
+ ] }) : wslBlocked ? /* @__PURE__ */ jsx("button", { style: btn3(), disabled: true, onClick: () => {
377
+ }, children: installing ? "\u6B63\u5728\u4E0B\u8F7D\u5B89\u88C5 WSL \u8FD0\u884C\u65F6\u2026" : "\u51C6\u5907\u5B89\u88C5\u2026" }) : failed ? /* @__PURE__ */ jsxs(Fragment, { children: [
378
+ /* @__PURE__ */ jsx("button", { style: btn3(), onClick: onClose, children: "Close" }),
379
+ /* @__PURE__ */ jsx("button", { style: btn3(true), onClick: begin, children: "Retry" })
380
+ ] }) : started ? /* @__PURE__ */ jsx("button", { style: btn3(), disabled: true, onClick: () => {
381
+ }, children: "Installing\u2026" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
382
+ /* @__PURE__ */ jsx("button", { style: btn3(), onClick: onClose, children: "Not now" }),
383
+ /* @__PURE__ */ jsx("button", { style: btn3(true), onClick: begin, children: "Start setup" })
384
+ ] }) })
385
+ ] }) });
386
+ }
387
+ function installedTags(node) {
388
+ const v = node.reported_caps?.installed_images;
389
+ return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
390
+ }
391
+ var str = (v) => typeof v === "string" && v ? v : "\u2014";
392
+ var sys = (node, k) => node.reported_caps?.system?.[k];
393
+ var capBool = (node, k) => node.reported_caps?.[k] === true;
394
+ function supportsRuntimeDataRoot(node) {
395
+ const capability = node.reported_caps?.runtime_data_root;
396
+ return capability?.supported === true;
397
+ }
398
+ function envOsOf(node) {
399
+ const os = str(sys(node, "os"));
400
+ return os === "macos" ? "mac" : os === "windows" ? "win" : null;
401
+ }
402
+ function withLocalEnvOs(node, os) {
403
+ if (!node.is_owner || !os || envOsOf(node) || sys(node, "os")) return node;
404
+ return {
405
+ ...node,
406
+ reported_caps: {
407
+ ...node.reported_caps,
408
+ system: {
409
+ ...node.reported_caps?.system,
410
+ os: os === "win" ? "windows" : "macos"
411
+ }
412
+ }
413
+ };
414
+ }
415
+ function vmPlan(node) {
416
+ const eff = node.effective_caps;
417
+ const os = str(sys(node, "os"));
418
+ const out = [];
419
+ if (eff?.android) {
420
+ const imageReady = node.reported_caps?.android_image_ready !== false;
421
+ if (imageReady) {
422
+ out.push({ key: "android", label: "Android \u4E91\u624B\u673A", state: "available" });
423
+ } else {
424
+ out.push({
425
+ key: "android",
426
+ label: "Android \u4E91\u624B\u673A",
427
+ state: "needs-image",
428
+ reason: "\u8FD0\u884C\u73AF\u5883\u5DF2\u5C31\u7EEA\uFF0CAndroid \u955C\u50CF\u5C1A\u672A\u4E0B\u8F7D\uFF08\u8282\u70B9\u542F\u52A8\u65F6\u81EA\u52A8\u62C9\u53D6\uFF0C\u4E5F\u53EF\u624B\u52A8\u89E6\u53D1\uFF09"
429
+ });
430
+ }
431
+ } else if (os === "windows" || os === "macos") {
432
+ out.push({
433
+ key: "android",
434
+ label: "Android \u4E91\u624B\u673A",
435
+ state: "needs-init",
436
+ reason: `\u9700\u5B89\u88C5 redroid \u73AF\u5883\u5E95\u5EA7\uFF08${os === "windows" ? "WSL2" : "lima"}\uFF09\u540E\u53EF\u7528`
437
+ });
438
+ } else if (os === "linux") {
439
+ out.push({
440
+ key: "android",
441
+ label: "Android \u4E91\u624B\u673A",
442
+ state: "unavailable",
443
+ reason: "\u8BE5 Linux \u8282\u70B9\u4E8C\u8FDB\u5236\u672A\u542F\u7528 redroid \u80FD\u529B\uFF08\u9700\u91CD\u88C5\u8282\u70B9\uFF09"
444
+ });
445
+ } else {
446
+ out.push({ key: "android", label: "Android \u4E91\u624B\u673A", state: "unavailable", reason: "\u672C\u673A\u4E0D\u652F\u6301" });
447
+ }
448
+ if (capBool(node, "vphone_capable") && eff?.ios) {
449
+ out.push({ key: "ios", label: "iOS \u865A\u62DF\u673A", state: "available" });
450
+ } else {
451
+ const arch = str(sys(node, "arch"));
452
+ const reason = os === "macos" ? arch === "aarch64" ? "\u672A\u68C0\u6D4B\u5230 vphone \u80FD\u529B\uFF08\u9700\u5728\u6B64 Mac \u4E0A\u542F\u7528\uFF09" : "iOS \u865A\u62DF\u673A\u4EC5 Apple Silicon Mac \u652F\u6301\uFF08\u6B64 Mac \u4E3A Intel\uFF09" : "iOS \u865A\u62DF\u673A\u4EC5 Apple Silicon Mac \u652F\u6301\uFF0C\u672C\u673A\u4E0D\u53EF\u7528";
453
+ out.push({ key: "ios", label: "iOS \u865A\u62DF\u673A", state: "unavailable", reason });
454
+ }
455
+ if (eff?.real_devices && (os === "windows" || os === "macos")) {
456
+ out.push({ key: "ios-real", label: "iOS \u771F\u673A", state: "available" });
457
+ } else {
458
+ out.push({
459
+ key: "ios-real",
460
+ label: "iOS \u771F\u673A",
461
+ state: "unavailable",
462
+ reason: !eff?.real_devices ? "\u8282\u70B9\u672A\u542F\u7528\u771F\u673A\u63A5\u5165" : "iOS \u771F\u673A\u9700 Windows/macOS \u5BBF\u4E3B\uFF08\u7ECF go-ios \u9A71\u52A8\uFF09"
463
+ });
464
+ }
465
+ out.push(
466
+ eff?.real_devices ? { key: "android-real", label: "Android \u771F\u673A", state: "available" } : { key: "android-real", label: "Android \u771F\u673A", state: "unavailable", reason: "\u8282\u70B9\u672A\u542F\u7528\u771F\u673A\u63A5\u5165" }
467
+ );
468
+ return out;
469
+ }
470
+ function ImagePullProgress({
471
+ events,
472
+ done,
473
+ finished,
474
+ error,
475
+ onClose
476
+ }) {
477
+ const failed = !!error || done && finished !== null && !finished.ok;
478
+ const stepsMeta = [];
479
+ const stepState = /* @__PURE__ */ new Map();
480
+ const logs = [];
481
+ for (const e of events) {
482
+ if (e.kind === "started") stepsMeta.push(...e.steps);
483
+ if (e.kind === "step") stepState.set(e.id, { state: e.state, pct: e.pct, detail: e.detail });
484
+ if (e.kind === "log") logs.push(e.line);
485
+ }
486
+ const recentLogs = logs.slice(-6);
487
+ const activeStep = stepsMeta.find((s) => stepState.get(s.id)?.state === "running");
488
+ return /* @__PURE__ */ jsxs("div", { className: "rounded border border-border bg-card/60 p-3 text-[11px] space-y-2", children: [
489
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
490
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-xs text-foreground", children: done ? failed ? "\u4E0B\u8F7D\u5931\u8D25" : "\u4E0B\u8F7D\u5B8C\u6210" : activeStep ? `\u6B63\u5728\u6267\u884C\uFF1A${activeStep.label}` : "\u6B63\u5728\u8FDE\u63A5\u8282\u70B9\u2026" }),
491
+ done && /* @__PURE__ */ jsx("button", { onClick: onClose, className: "text-muted-foreground hover:text-foreground text-[11px] ml-2", children: "\u5173\u95ED" })
492
+ ] }),
493
+ stepsMeta.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-1", children: stepsMeta.map((s) => {
494
+ const st = stepState.get(s.id);
495
+ const dotClass = st?.state === "ok" ? "bg-success" : st?.state === "running" ? "bg-warning animate-pulse" : st?.state === "failed" ? "bg-destructive" : "bg-muted-foreground/30";
496
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
497
+ /* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${dotClass}` }),
498
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-muted-foreground", children: s.label }),
499
+ st?.state === "running" && st.pct > 0 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground whitespace-nowrap", children: [
500
+ st.pct,
501
+ "%",
502
+ st.detail ? ` \xB7 ${st.detail}` : ""
503
+ ] }),
504
+ st?.detail && st.state !== "running" && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground truncate max-w-[180px]", children: st.detail })
505
+ ] }, s.id);
506
+ }) }),
507
+ activeStep && (() => {
508
+ const pct = stepState.get(activeStep.id)?.pct ?? 0;
509
+ return pct > 0 ? /* @__PURE__ */ jsx("div", { className: "h-1 w-full rounded-full bg-muted overflow-hidden", children: /* @__PURE__ */ jsx(
510
+ "div",
511
+ {
512
+ className: "h-full bg-primary rounded-full transition-all duration-300",
513
+ style: { width: `${pct}%` }
514
+ }
515
+ ) }) : null;
516
+ })(),
517
+ recentLogs.length > 0 && /* @__PURE__ */ jsx("pre", { className: "text-[10px] font-mono text-muted-foreground bg-muted/20 rounded p-2 max-h-24 overflow-y-auto leading-relaxed whitespace-pre-wrap break-all", children: recentLogs.join("\n") }),
518
+ done && failed && /* @__PURE__ */ jsx("p", { className: "text-destructive", children: error?.message ?? finished?.error ?? "\u955C\u50CF\u62C9\u53D6\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u6B65\u9AA4\u8BE6\u60C5\u540E\u91CD\u8BD5" })
519
+ ] });
520
+ }
521
+ function VmCapRow({
522
+ node,
523
+ vm,
524
+ onInit,
525
+ onDownload,
526
+ downloading
527
+ }) {
528
+ const canInit = vm.state === "needs-init" && node.is_owner && envOsOf(node) !== null;
529
+ const canDownload = vm.state === "needs-image" && node.is_owner;
530
+ const dot = vm.state === "available" ? "bg-success" : vm.state === "needs-init" ? "bg-warning" : vm.state === "needs-image" ? "bg-warning" : "bg-muted-foreground/40";
531
+ const badge = vm.state === "available" ? "\u53EF\u7528" : vm.state === "needs-init" ? "\u9700\u521D\u59CB\u5316" : vm.state === "needs-image" ? "\u955C\u50CF\u672A\u5C31\u7EEA" : "\u672C\u673A\u4E0D\u53EF\u7528";
532
+ const badgeClass = vm.state === "available" ? "text-success" : vm.state === "needs-init" ? "text-warning" : vm.state === "needs-image" ? "text-warning" : "text-muted-foreground";
533
+ return /* @__PURE__ */ jsxs("div", { className: "rounded border border-border px-3 py-2", children: [
534
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
535
+ /* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${dot}` }),
536
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-xs text-foreground", children: vm.label }),
537
+ /* @__PURE__ */ jsx("span", { className: `text-[11px] ${badgeClass}`, children: badge }),
538
+ canInit && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "primary", onClick: onInit, className: "ml-2", children: "\u521D\u59CB\u5316" }),
539
+ canDownload && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "primary", onClick: onDownload, disabled: downloading, className: "ml-2", children: downloading ? "\u91CD\u542F\u4E2D\u2026" : "\u4E0B\u8F7D\u955C\u50CF" })
540
+ ] }),
541
+ vm.reason && /* @__PURE__ */ jsx("p", { className: "mt-1 pl-3.5 text-[11px] text-muted-foreground", children: vm.reason })
542
+ ] });
543
+ }
544
+ function DataRootConfig({ node }) {
545
+ const client = useClient();
546
+ const [dataRoot, setDataRoot] = useState("");
547
+ const [saving, setSaving] = useState(false);
548
+ const [message, setMessage] = useState(null);
549
+ if (!supportsRuntimeDataRoot(node)) {
550
+ return /* @__PURE__ */ jsx("p", { className: "mt-3 text-[11px] text-muted-foreground", children: "\u6570\u636E\u6839\u76EE\u5F55\u914D\u7F6E\u9700\u8981\u652F\u6301\u6B64\u529F\u80FD\u7684\u65B0\u7248 Linux \u8282\u70B9\u3002" });
551
+ }
552
+ const save = async () => {
553
+ if (!dataRoot.trim() || saving) return;
554
+ setSaving(true);
555
+ setMessage(null);
556
+ try {
557
+ const receipt = await client.nodes.setDataRoot(node.id, dataRoot);
558
+ setMessage(
559
+ receipt.restart_required ? `\u5DF2\u4FDD\u5B58 ${receipt.data_root}\u3002\u8BF7\u91CD\u542F\u8282\u70B9\u540E\uFF0C\u65B0\u5EFA Redroid \u5BB9\u5668\u624D\u4F1A\u4F7F\u7528\u6B64\u76EE\u5F55\u3002` : `\u5DF2\u4FDD\u5B58 ${receipt.data_root}\u3002`
560
+ );
561
+ } catch (error) {
562
+ setMessage(error instanceof Error ? error.message : String(error));
563
+ } finally {
564
+ setSaving(false);
565
+ }
566
+ };
567
+ return /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded border border-border p-3 space-y-2", children: [
568
+ /* @__PURE__ */ jsxs("div", { children: [
569
+ /* @__PURE__ */ jsx("h4", { className: "text-xs font-medium text-foreground", children: "Redroid \u6570\u636E\u6839\u76EE\u5F55" }),
570
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-muted-foreground", children: "\u4EC5\u63A5\u53D7\u8282\u70B9\u539F\u751F\u6587\u4EF6\u7CFB\u7EDF\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4E0D\u4F1A\u8FC1\u79FB\u6216\u5220\u9664\u73B0\u6709\u6570\u636E\uFF0C\u4FDD\u5B58\u540E\u9700\u624B\u52A8\u91CD\u542F\u8282\u70B9\u3002" })
571
+ ] }),
572
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
573
+ /* @__PURE__ */ jsx(
574
+ Input,
575
+ {
576
+ value: dataRoot,
577
+ onChange: (event) => setDataRoot(event.target.value),
578
+ placeholder: "/var/lib/aixautobot/instances",
579
+ "aria-label": "Redroid \u6570\u636E\u6839\u76EE\u5F55"
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "primary", disabled: saving || !dataRoot.trim(), onClick: () => void save(), children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58" })
583
+ ] }),
584
+ message && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: message })
585
+ ] });
586
+ }
587
+ function AndroidImageRows({ images, installed }) {
588
+ return /* @__PURE__ */ jsx("div", { className: "mt-1.5 ml-3.5 space-y-1 border-l border-border/60 pl-3", children: images.map((img) => {
589
+ const has = installed.includes(img.image_tag);
590
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
591
+ /* @__PURE__ */ jsx("span", { className: `h-1 w-1 shrink-0 rounded-full ${has ? "bg-success" : "bg-muted-foreground/40"}` }),
592
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] text-muted-foreground", children: img.label }),
593
+ /* @__PURE__ */ jsx("span", { className: `text-[10px] ${has ? "text-success" : "text-muted-foreground"}`, children: has ? "\u5DF2\u5B89\u88C5" : "\u672A\u5B89\u88C5" })
594
+ ] }, img.id);
595
+ }) });
596
+ }
597
+ function NodeCapabilityPanel({ node: reportedNode, isTauri, onInstallWsl, localEnvOs }) {
598
+ const client = useClient();
599
+ const localOs = localEnvOs ?? (client.localNode?.nodeId === reportedNode.id ? client.localNode.envOs ?? detectEnvOs() : null);
600
+ const node = withLocalEnvOs(reportedNode, localOs);
601
+ const [init, setInit] = useState(null);
602
+ const initOs = envOsOf(node);
603
+ const envRun = useEnvRun();
604
+ const imagePulling = envRun.reqId !== null && !envRun.done;
605
+ const showImagePanel = envRun.reqId !== null;
606
+ const handleDownload = async () => {
607
+ if (!initOs || imagePulling) return;
608
+ try {
609
+ await envRun.setup(node.id, { os: initOs });
610
+ } catch {
611
+ }
612
+ };
613
+ const [androidImages, setAndroidImages] = useState([]);
614
+ useEffect(() => {
615
+ let cancelled = false;
616
+ client.images.options("android").then((imgs) => {
617
+ if (!cancelled) setAndroidImages(imgs);
618
+ }).catch(() => {
619
+ });
620
+ return () => {
621
+ cancelled = true;
622
+ };
623
+ }, [client]);
624
+ const installed = installedTags(node);
625
+ return /* @__PURE__ */ jsxs("section", { children: [
626
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2", children: "\u865A\u62DF\u673A\u4E0E\u8BBE\u5907\u80FD\u529B" }),
627
+ !node.reported_caps ? /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "\u80FD\u529B\u672A\u77E5\uFF1A\u8282\u70B9\u5C1A\u672A\u8FDE\u63A5\u6216\u4E3A\u65E7\u7248\u672C\uFF08\u9700\u5347\u7EA7\u4EE5\u4E0A\u62A5\u80FD\u529B\uFF09\u3002" }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
628
+ !reportedNode.reported_caps && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "\u5DF2\u8BC6\u522B\u672C\u673A\u7CFB\u7EDF\uFF0C\u53EF\u521D\u59CB\u5316\u73AF\u5883\uFF1B\u8282\u70B9\u80FD\u529B\u5C1A\u672A\u4E0A\u62A5\uFF0C\u8BF7\u786E\u4FDD\u8282\u70B9\u5DF2\u8FDE\u63A5\u8BBE\u5907\u7F51\u5173\u3002" }),
629
+ vmPlan(node).map((vm) => /* @__PURE__ */ jsxs("div", { children: [
630
+ /* @__PURE__ */ jsx(
631
+ VmCapRow,
632
+ {
633
+ node,
634
+ vm,
635
+ onInit: () => setInit(vm),
636
+ onDownload: handleDownload,
637
+ downloading: imagePulling
638
+ }
639
+ ),
640
+ vm.key === "android" && vm.state !== "unavailable" && androidImages.length > 0 && /* @__PURE__ */ jsx(AndroidImageRows, { images: androidImages, installed })
641
+ ] }, vm.key)),
642
+ showImagePanel && /* @__PURE__ */ jsx(
643
+ ImagePullProgress,
644
+ {
645
+ events: envRun.events,
646
+ done: envRun.done,
647
+ finished: envRun.finished,
648
+ error: envRun.error,
649
+ onClose: () => envRun.close()
650
+ }
651
+ )
652
+ ] }),
653
+ node.is_owner && (supportsRuntimeDataRoot(node) || sys(node, "os") === "linux") && /* @__PURE__ */ jsx(DataRootConfig, { node }),
654
+ init && initOs && /* @__PURE__ */ jsx(
655
+ EnvInitDialog,
656
+ {
657
+ open: true,
658
+ nodeId: node.id,
659
+ os: initOs,
660
+ mode: "prompt",
661
+ title: `\u521D\u59CB\u5316 ${init.label} \u73AF\u5883\u5E95\u5EA7`,
662
+ onInstallWsl: isTauri ? onInstallWsl : void 0,
663
+ onClose: () => setInit(null),
664
+ onReady: async () => {
665
+ try {
666
+ await client.nodes.restart(node.id);
667
+ } catch {
668
+ }
669
+ setInit(null);
670
+ }
671
+ }
672
+ )
673
+ ] });
674
+ }
675
+
676
+ export { AIX_CSS_VARS, DebugConsole, EnvInitDialog, NodeCapabilityPanel, ScriptEditor, ScriptPanel, aixCodeMirrorTheme, vmPlan };