@amd-gaia/agent-ui 0.25.3 → 0.25.4-rc.10
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.
- package/bin/gaia-ui.cjs +2 -23
- package/dist/assets/AdvancedSettings-DXf2pogI.js +1 -0
- package/dist/assets/ConnectorsPane-CzLYXGMl.css +1 -0
- package/dist/assets/ConnectorsPane-R1yvKMNT.js +1 -0
- package/dist/assets/DocumentLibrary-CM6o8j2T.css +1 -0
- package/dist/assets/DocumentLibrary-DSOiP7Ft.js +4 -0
- package/dist/assets/FileBrowser-BlVSPjD2.js +4 -0
- package/dist/assets/FileBrowser-Cna3BsT7.css +1 -0
- package/dist/assets/MemoryDashboard-D_ZVZbS_.js +1 -0
- package/dist/assets/MemoryDashboard-DwrWAXi6.css +1 -0
- package/dist/assets/MobileAccessModal-BkVDm3YG.css +1 -0
- package/dist/assets/MobileAccessModal-CPjDeIIk.js +2 -0
- package/dist/assets/ScheduleManager-CjHJ4NbD.css +1 -0
- package/dist/assets/ScheduleManager-D1DOYVQo.js +1 -0
- package/dist/assets/api-Co-B9E0t.js +4 -0
- package/dist/assets/index-CMVmIBZ8.js +78 -0
- package/dist/assets/index-Y93uvqe7.css +1 -0
- package/dist/assets/useT-tWXlG-cT.js +3 -0
- package/dist/assets/zap-D-WCZ6dX.js +1 -0
- package/dist/icons/apple-touch-icon.png +0 -0
- package/dist/icons/icon-192.png +0 -0
- package/dist/icons/icon-512.png +0 -0
- package/dist/icons/icon-maskable-192.png +0 -0
- package/dist/icons/icon-maskable-512.png +0 -0
- package/dist/index.html +8 -3
- package/dist/manifest.json +16 -0
- package/dist/sw.js +49 -0
- package/main-safety-net.cjs +106 -8
- package/main.cjs +145 -162
- package/package.json +5 -3
- package/preload.cjs +19 -9
- package/services/agent-seeder.cjs +22 -13
- package/services/auto-updater.cjs +780 -216
- package/services/backend-installer.cjs +523 -365
- package/services/engine-install.cjs +233 -0
- package/services/index-query.cjs +7 -1
- package/services/lock-holders.cjs +200 -0
- package/services/quit-guard.cjs +36 -3
- package/services/tray-manager.cjs +12 -7
- package/dist/assets/AdvancedSettings-DERzP9Jc.js +0 -1
- package/dist/assets/ConnectorsPane-Dzu2DRTc.css +0 -1
- package/dist/assets/ConnectorsPane-s0fFxmus.js +0 -1
- package/dist/assets/DocumentLibrary-CIKp6qld.css +0 -1
- package/dist/assets/DocumentLibrary-DqapN_Tr.js +0 -4
- package/dist/assets/FileBrowser-Dil1lZJ4.css +0 -1
- package/dist/assets/FileBrowser-vAJV41RT.js +0 -4
- package/dist/assets/MemoryDashboard-CP5wVWkY.js +0 -1
- package/dist/assets/MemoryDashboard-Mo721-BI.css +0 -1
- package/dist/assets/MobileAccessModal-B31mPs50.js +0 -2
- package/dist/assets/MobileAccessModal-DuVy9F1u.css +0 -1
- package/dist/assets/ScheduleManager-D5c4gVIt.css +0 -1
- package/dist/assets/ScheduleManager-b0gTAf2R.js +0 -2
- package/dist/assets/apiBase-CS6zLsJY.js +0 -1
- package/dist/assets/index-C-EM_5yl.css +0 -1
- package/dist/assets/index-Cae5Fje-.js +0 -78
- package/dist/assets/zap-BogJn9oN.js +0 -1
- package/services/backend-installer-progress-dialog.cjs +0 -510
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./apiBase-CS6zLsJY.js";var t={name:`message-square`,size:24,node:[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]};t.node;var n=e(t),r={name:`zap`,size:24,node:[[`path`,{d:`M15.914 4a1.5 1.5 0 00-2.474-1.561l-9 9A1.5 1.5 0 005.5 14h4.002a.5.5 0 01.471.666L8.086 20a1.5 1.5 0 002.475 1.56l9-9A1.5 1.5 0 0018.5 10h-3.997a.5.5 0 01-.472-.667z`,key:`1v7up4`}]]};r.node;var i=e(r);export{n,i as t};
|
|
@@ -1,510 +0,0 @@
|
|
|
1
|
-
// Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* backend-installer-progress-dialog.cjs — Electron progress UI for the
|
|
6
|
-
* first-run backend install.
|
|
7
|
-
*
|
|
8
|
-
* Owns the Electron-specific presentation layer for the install flow.
|
|
9
|
-
* The core install logic lives in `backend-installer.cjs`, which is pure
|
|
10
|
-
* Node.js; this module renders a borderless BrowserWindow with embedded
|
|
11
|
-
* HTML/JS and wires up IPC events so the install module's progress
|
|
12
|
-
* callbacks stream through to the renderer.
|
|
13
|
-
*
|
|
14
|
-
* Responsibilities:
|
|
15
|
-
* - Show a borderless progress window (stage + percent + message)
|
|
16
|
-
* - Expose an `onProgress(stage, percent, message)` callback for the
|
|
17
|
-
* install module
|
|
18
|
-
* - Show a failure dialog with Retry / Manual / Quit buttons
|
|
19
|
-
* - Surface the log file path (copy / open)
|
|
20
|
-
*
|
|
21
|
-
* Exposed API:
|
|
22
|
-
* - createProgressWindow() → { window, onProgress, close }
|
|
23
|
-
* - showFailureDialog(parentWindow, errorInfo) → Promise<'retry'|'manual'|'quit'>
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
"use strict";
|
|
27
|
-
|
|
28
|
-
const path = require("path");
|
|
29
|
-
const { BrowserWindow, dialog, ipcMain, shell, clipboard } = require("electron");
|
|
30
|
-
|
|
31
|
-
const installer = require("./backend-installer.cjs");
|
|
32
|
-
const { appIconPath } = require("./app-icon.cjs");
|
|
33
|
-
|
|
34
|
-
// IPC channels. Keep these in sync with preload.cjs.
|
|
35
|
-
const IPC_PROGRESS_EVENT = "install:progress";
|
|
36
|
-
const IPC_STATUS_REQUEST = "install:status";
|
|
37
|
-
const IPC_COPY_LOG_PATH = "install:copy-log-path";
|
|
38
|
-
const IPC_OPEN_LOG_FILE = "install:open-log-file";
|
|
39
|
-
|
|
40
|
-
// Track whether one-time IPC handlers have been registered so we don't
|
|
41
|
-
// attach them twice if createProgressWindow() runs multiple times.
|
|
42
|
-
let ipcHandlersRegistered = false;
|
|
43
|
-
|
|
44
|
-
function registerIpcHandlers() {
|
|
45
|
-
if (ipcHandlersRegistered) return;
|
|
46
|
-
ipcHandlersRegistered = true;
|
|
47
|
-
|
|
48
|
-
ipcMain.handle(IPC_STATUS_REQUEST, () => {
|
|
49
|
-
return {
|
|
50
|
-
state: installer.getState(),
|
|
51
|
-
logPath: installer.getLogPath(),
|
|
52
|
-
statePath: installer.getStatePath(),
|
|
53
|
-
};
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
ipcMain.handle(IPC_COPY_LOG_PATH, () => {
|
|
57
|
-
try {
|
|
58
|
-
clipboard.writeText(installer.getLogPath());
|
|
59
|
-
return { ok: true };
|
|
60
|
-
} catch (err) {
|
|
61
|
-
return { ok: false, message: err.message };
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
ipcMain.handle(IPC_OPEN_LOG_FILE, async () => {
|
|
66
|
-
try {
|
|
67
|
-
const logPath = installer.getLogPath();
|
|
68
|
-
const result = await shell.openPath(logPath);
|
|
69
|
-
return { ok: !result, message: result || null };
|
|
70
|
-
} catch (err) {
|
|
71
|
-
return { ok: false, message: err.message };
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ── Stage labels ────────────────────────────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
// Keyed by installer.STAGES values; the ids themselves stay in the install log.
|
|
79
|
-
const STAGE_LABELS = Object.freeze({
|
|
80
|
-
"pre-checks": "Checking your PC",
|
|
81
|
-
"ensure-uv": "Getting the installer ready",
|
|
82
|
-
"create-venv": "Preparing GAIA's workspace",
|
|
83
|
-
"install-package": "Installing GAIA",
|
|
84
|
-
"gaia-init": "Getting the AI model ready",
|
|
85
|
-
verify: "Finishing up",
|
|
86
|
-
});
|
|
87
|
-
const NEUTRAL_STAGE_LABEL = "Setting up GAIA";
|
|
88
|
-
|
|
89
|
-
const unlabeledStages = new Set();
|
|
90
|
-
|
|
91
|
-
/** What the window shows for an installer stage id. */
|
|
92
|
-
function stageLabel(stage) {
|
|
93
|
-
if (Object.prototype.hasOwnProperty.call(STAGE_LABELS, stage)) return STAGE_LABELS[stage];
|
|
94
|
-
if (stage && !unlabeledStages.has(stage)) {
|
|
95
|
-
unlabeledStages.add(stage);
|
|
96
|
-
installer.log(
|
|
97
|
-
`Warning: install stage "${stage}" has no label; the window shows "${NEUTRAL_STAGE_LABEL}"`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
return NEUTRAL_STAGE_LABEL;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ── Embedded HTML ───────────────────────────────────────────────────────────
|
|
104
|
-
|
|
105
|
-
function escapeHtml(text) {
|
|
106
|
-
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* HTML payload for the progress window. Rendered via `loadURL('data:...')`.
|
|
111
|
-
* The script uses `window.gaiaInstall` exposed by preload.cjs.
|
|
112
|
-
*/
|
|
113
|
-
function buildProgressHtml({ logPath }) {
|
|
114
|
-
const escapedLog = escapeHtml(logPath || "");
|
|
115
|
-
return `<!DOCTYPE html>
|
|
116
|
-
<html lang="en">
|
|
117
|
-
<head>
|
|
118
|
-
<meta charset="UTF-8" />
|
|
119
|
-
<title>Installing GAIA</title>
|
|
120
|
-
<style>
|
|
121
|
-
/* Standalone window: it loads from a data: URL and never sees
|
|
122
|
-
* src/styles/index.css, so the dark theme's role values are mirrored
|
|
123
|
-
* here. Keep them in step with that file; nothing below names a hex. */
|
|
124
|
-
:root {
|
|
125
|
-
--bg-primary: #1A1917;
|
|
126
|
-
--bg-tertiary: #2C2B27;
|
|
127
|
-
--border: #4A4740;
|
|
128
|
-
--text-primary: #EFECE6;
|
|
129
|
-
--text-secondary: #B3ADA5;
|
|
130
|
-
--text-muted: #958F87;
|
|
131
|
-
--accent-solid: #D4B47E;
|
|
132
|
-
}
|
|
133
|
-
html, body {
|
|
134
|
-
margin: 0;
|
|
135
|
-
padding: 0;
|
|
136
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
137
|
-
background: var(--bg-primary);
|
|
138
|
-
color: var(--text-primary);
|
|
139
|
-
user-select: none;
|
|
140
|
-
-webkit-user-select: none;
|
|
141
|
-
overflow: hidden;
|
|
142
|
-
}
|
|
143
|
-
body {
|
|
144
|
-
display: flex;
|
|
145
|
-
flex-direction: column;
|
|
146
|
-
align-items: center;
|
|
147
|
-
justify-content: center;
|
|
148
|
-
height: 100vh;
|
|
149
|
-
padding: 32px;
|
|
150
|
-
box-sizing: border-box;
|
|
151
|
-
text-align: center;
|
|
152
|
-
}
|
|
153
|
-
h1 {
|
|
154
|
-
font-size: 18px;
|
|
155
|
-
font-weight: 600;
|
|
156
|
-
margin: 0 0 8px 0;
|
|
157
|
-
color: var(--text-primary);
|
|
158
|
-
}
|
|
159
|
-
.subtitle {
|
|
160
|
-
font-size: 13px;
|
|
161
|
-
color: var(--text-secondary);
|
|
162
|
-
margin: 0 0 24px 0;
|
|
163
|
-
}
|
|
164
|
-
.stage {
|
|
165
|
-
font-size: 12px;
|
|
166
|
-
color: var(--text-secondary);
|
|
167
|
-
margin-bottom: 6px;
|
|
168
|
-
min-height: 15px;
|
|
169
|
-
}
|
|
170
|
-
/* The rule carries the track's edge: no fill clears the 1.5:1 chrome
|
|
171
|
-
* floor against the canvas, but --border does at 1.56:1. */
|
|
172
|
-
.bar {
|
|
173
|
-
width: 360px;
|
|
174
|
-
max-width: 100%;
|
|
175
|
-
height: 10px;
|
|
176
|
-
box-sizing: border-box;
|
|
177
|
-
background: var(--bg-tertiary);
|
|
178
|
-
border: 1px solid var(--border);
|
|
179
|
-
border-radius: 9999px;
|
|
180
|
-
overflow: hidden;
|
|
181
|
-
margin-bottom: 12px;
|
|
182
|
-
}
|
|
183
|
-
.fill {
|
|
184
|
-
height: 100%;
|
|
185
|
-
background: var(--accent-solid);
|
|
186
|
-
border-radius: 9999px;
|
|
187
|
-
transition: width 300ms ease-out;
|
|
188
|
-
width: 0%;
|
|
189
|
-
}
|
|
190
|
-
.fill.indeterminate {
|
|
191
|
-
width: 30% !important;
|
|
192
|
-
animation: slide 1.4s ease-in-out infinite;
|
|
193
|
-
}
|
|
194
|
-
@keyframes slide {
|
|
195
|
-
0% { margin-left: 0%; }
|
|
196
|
-
50% { margin-left: 70%; }
|
|
197
|
-
100% { margin-left: 0%; }
|
|
198
|
-
}
|
|
199
|
-
@media (prefers-reduced-motion: reduce) {
|
|
200
|
-
.fill { transition: none; }
|
|
201
|
-
.fill.indeterminate { animation: none; margin-left: 35%; }
|
|
202
|
-
}
|
|
203
|
-
.percent {
|
|
204
|
-
font-size: 12px;
|
|
205
|
-
color: var(--text-secondary);
|
|
206
|
-
margin-bottom: 16px;
|
|
207
|
-
min-height: 14px;
|
|
208
|
-
}
|
|
209
|
-
.message {
|
|
210
|
-
font-size: 13px;
|
|
211
|
-
color: var(--text-primary);
|
|
212
|
-
max-width: 420px;
|
|
213
|
-
min-height: 36px;
|
|
214
|
-
line-height: 1.4;
|
|
215
|
-
}
|
|
216
|
-
.footer {
|
|
217
|
-
position: absolute;
|
|
218
|
-
bottom: 10px;
|
|
219
|
-
left: 0;
|
|
220
|
-
right: 0;
|
|
221
|
-
text-align: center;
|
|
222
|
-
font-size: 10px;
|
|
223
|
-
color: var(--text-muted);
|
|
224
|
-
}
|
|
225
|
-
code {
|
|
226
|
-
font-family: "SF Mono", Monaco, Consolas, monospace;
|
|
227
|
-
font-size: 10px;
|
|
228
|
-
color: var(--text-muted);
|
|
229
|
-
}
|
|
230
|
-
</style>
|
|
231
|
-
</head>
|
|
232
|
-
<body>
|
|
233
|
-
<h1>Setting up GAIA</h1>
|
|
234
|
-
<p class="subtitle">First-time setup — this can take a few minutes</p>
|
|
235
|
-
<div class="stage" id="stage">Starting…</div>
|
|
236
|
-
<div class="bar"><div class="fill indeterminate" id="fill"></div></div>
|
|
237
|
-
<div class="percent" id="percent"></div>
|
|
238
|
-
<div class="message" id="message">Checking your PC…</div>
|
|
239
|
-
<div class="footer">Log: <code>${escapedLog}</code></div>
|
|
240
|
-
<script>
|
|
241
|
-
(function() {
|
|
242
|
-
const stageEl = document.getElementById('stage');
|
|
243
|
-
const fillEl = document.getElementById('fill');
|
|
244
|
-
const percentEl = document.getElementById('percent');
|
|
245
|
-
const messageEl = document.getElementById('message');
|
|
246
|
-
|
|
247
|
-
function onProgress(payload) {
|
|
248
|
-
if (!payload) return;
|
|
249
|
-
const stage = payload.label || '';
|
|
250
|
-
const percent = typeof payload.percent === 'number' ? payload.percent : null;
|
|
251
|
-
const message = payload.message || '';
|
|
252
|
-
|
|
253
|
-
if (stage) stageEl.textContent = stage;
|
|
254
|
-
if (message) messageEl.textContent = message;
|
|
255
|
-
|
|
256
|
-
if (percent != null && percent >= 0) {
|
|
257
|
-
fillEl.classList.remove('indeterminate');
|
|
258
|
-
fillEl.style.width = Math.max(0, Math.min(100, percent)) + '%';
|
|
259
|
-
percentEl.textContent = percent + '%';
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (window.gaiaInstall && typeof window.gaiaInstall.onProgress === 'function') {
|
|
264
|
-
window.gaiaInstall.onProgress(onProgress);
|
|
265
|
-
} else {
|
|
266
|
-
// Fallback: listen directly via ipcRenderer shim if preload didn't load.
|
|
267
|
-
console.warn('gaiaInstall API not available in progress window');
|
|
268
|
-
}
|
|
269
|
-
})();
|
|
270
|
-
</script>
|
|
271
|
-
</body>
|
|
272
|
-
</html>`;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// ── Progress window factory ─────────────────────────────────────────────────
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Create a borderless progress window and return an `onProgress` callback
|
|
279
|
-
* suitable for passing to `backend-installer.ensureBackend({ onProgress })`.
|
|
280
|
-
*
|
|
281
|
-
* Returns:
|
|
282
|
-
* {
|
|
283
|
-
* window: BrowserWindow,
|
|
284
|
-
* onProgress: (stage, percent, message) => void,
|
|
285
|
-
* close: () => void,
|
|
286
|
-
* }
|
|
287
|
-
*/
|
|
288
|
-
function createProgressWindow() {
|
|
289
|
-
registerIpcHandlers();
|
|
290
|
-
|
|
291
|
-
const window = new BrowserWindow({
|
|
292
|
-
width: 480,
|
|
293
|
-
height: 280,
|
|
294
|
-
resizable: false,
|
|
295
|
-
minimizable: true,
|
|
296
|
-
maximizable: false,
|
|
297
|
-
fullscreenable: false,
|
|
298
|
-
frame: false,
|
|
299
|
-
transparent: false,
|
|
300
|
-
show: false,
|
|
301
|
-
backgroundColor: "#1A1917", // --bg-primary, dark theme (see the :root block above)
|
|
302
|
-
title: "Installing GAIA",
|
|
303
|
-
icon: appIconPath(),
|
|
304
|
-
webPreferences: {
|
|
305
|
-
nodeIntegration: false,
|
|
306
|
-
contextIsolation: true,
|
|
307
|
-
preload: path.join(__dirname, "..", "preload.cjs"),
|
|
308
|
-
},
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
window.setMenuBarVisibility(false);
|
|
312
|
-
|
|
313
|
-
const html = buildProgressHtml({ logPath: installer.getLogPath() });
|
|
314
|
-
window.loadURL("data:text/html;charset=utf-8," + encodeURIComponent(html));
|
|
315
|
-
|
|
316
|
-
window.once("ready-to-show", () => {
|
|
317
|
-
if (!window.isDestroyed()) window.show();
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
// Buffer progress events until the renderer has finished loading — events
|
|
321
|
-
// sent before `did-finish-load` are lost because the renderer's IPC
|
|
322
|
-
// listener hasn't attached yet. Once loaded, the most recent state is
|
|
323
|
-
// replayed (and flushed for subsequent delivery).
|
|
324
|
-
let rendererReady = false;
|
|
325
|
-
let lastProgress = null;
|
|
326
|
-
|
|
327
|
-
window.webContents.once("did-finish-load", () => {
|
|
328
|
-
rendererReady = true;
|
|
329
|
-
if (lastProgress && !window.isDestroyed()) {
|
|
330
|
-
try {
|
|
331
|
-
window.webContents.send(IPC_PROGRESS_EVENT, lastProgress);
|
|
332
|
-
} catch {
|
|
333
|
-
// non-fatal
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const onProgress = (stage, percent, message) => {
|
|
339
|
-
lastProgress = { stage, label: stageLabel(stage), percent, message };
|
|
340
|
-
if (window.isDestroyed()) return;
|
|
341
|
-
if (!rendererReady) return; // will be replayed on did-finish-load
|
|
342
|
-
try {
|
|
343
|
-
window.webContents.send(IPC_PROGRESS_EVENT, lastProgress);
|
|
344
|
-
} catch (err) {
|
|
345
|
-
// Non-fatal
|
|
346
|
-
// eslint-disable-next-line no-console
|
|
347
|
-
console.error("[install-progress] send failed:", err.message);
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
const close = () => {
|
|
352
|
-
if (!window.isDestroyed()) {
|
|
353
|
-
try {
|
|
354
|
-
window.destroy();
|
|
355
|
-
} catch {
|
|
356
|
-
// ignore
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
window.on("closed", () => {
|
|
362
|
-
if (lastProgress) {
|
|
363
|
-
// eslint-disable-next-line no-console
|
|
364
|
-
console.log(
|
|
365
|
-
`[install-progress] window closed at stage=${lastProgress.stage} percent=${lastProgress.percent}`
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
return { window, onProgress, close };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// ── Failure dialog ──────────────────────────────────────────────────────────
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Show a modal failure dialog with Retry / Manual / Quit options.
|
|
377
|
-
* Returns 'retry', 'manual', or 'quit'.
|
|
378
|
-
*/
|
|
379
|
-
async function showFailureDialog(parentWindow, errorInfo = {}) {
|
|
380
|
-
const {
|
|
381
|
-
message = "GAIA backend install failed.",
|
|
382
|
-
stage = null,
|
|
383
|
-
suggestion = null,
|
|
384
|
-
} = errorInfo;
|
|
385
|
-
|
|
386
|
-
const logPath = installer.getLogPath();
|
|
387
|
-
const statePath = installer.getStatePath();
|
|
388
|
-
|
|
389
|
-
const detail = [
|
|
390
|
-
stage ? `Stage: ${stage}` : null,
|
|
391
|
-
suggestion ? `\n${suggestion}` : null,
|
|
392
|
-
`\nLog file: ${logPath}`,
|
|
393
|
-
`State file: ${statePath}`,
|
|
394
|
-
]
|
|
395
|
-
.filter(Boolean)
|
|
396
|
-
.join("\n");
|
|
397
|
-
|
|
398
|
-
// Copy/Open log return to the same dialog. "Install uv" is offered only
|
|
399
|
-
// when uv is what failed; for any other stage it would just repeat Retry.
|
|
400
|
-
const uvFailed = stage === "ensure-uv";
|
|
401
|
-
const actions = [
|
|
402
|
-
...(uvFailed ? [["install-uv", "Install uv (auto)"]] : []),
|
|
403
|
-
["retry", "Retry"],
|
|
404
|
-
["manual", "Manual install instructions"],
|
|
405
|
-
["copy-log", "Copy log path"],
|
|
406
|
-
["open-log", "Open log file"],
|
|
407
|
-
["quit", "Quit"],
|
|
408
|
-
];
|
|
409
|
-
const buttons = actions.map(([, label]) => label);
|
|
410
|
-
|
|
411
|
-
const show = async () => {
|
|
412
|
-
const result = await dialog.showMessageBox(parentWindow || null, {
|
|
413
|
-
type: "error",
|
|
414
|
-
title: "GAIA install failed",
|
|
415
|
-
message,
|
|
416
|
-
detail,
|
|
417
|
-
buttons,
|
|
418
|
-
defaultId: 0,
|
|
419
|
-
cancelId: buttons.length - 1,
|
|
420
|
-
noLink: true,
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
const action = (actions[result.response] || ["quit"])[0];
|
|
424
|
-
switch (action) {
|
|
425
|
-
case "install-uv": {
|
|
426
|
-
// Run the full packaged install (ensureBackend), with progress, so one
|
|
427
|
-
// click retries everything, not only uv; re-show with the new error.
|
|
428
|
-
const { onProgress, close } = createProgressWindow();
|
|
429
|
-
try {
|
|
430
|
-
await installer.ensureBackend({ onProgress, isPackaged: true });
|
|
431
|
-
try { close(); } catch {}
|
|
432
|
-
return "retry";
|
|
433
|
-
} catch (err) {
|
|
434
|
-
try { close(); } catch {}
|
|
435
|
-
const nextInfo = Object.assign({}, errorInfo, {
|
|
436
|
-
message: err.message || String(err),
|
|
437
|
-
stage: err.stage || "ensure-backend",
|
|
438
|
-
suggestion: err.suggestion || errorInfo.suggestion,
|
|
439
|
-
});
|
|
440
|
-
return showFailureDialog(parentWindow, nextInfo);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
case "retry":
|
|
444
|
-
return "retry";
|
|
445
|
-
case "manual": {
|
|
446
|
-
try {
|
|
447
|
-
await shell.openExternal("https://amd-gaia.ai/docs/quickstart#cli-install");
|
|
448
|
-
} catch {
|
|
449
|
-
// ignore
|
|
450
|
-
}
|
|
451
|
-
return "manual";
|
|
452
|
-
}
|
|
453
|
-
case "copy-log": {
|
|
454
|
-
try {
|
|
455
|
-
clipboard.writeText(logPath);
|
|
456
|
-
} catch {
|
|
457
|
-
// ignore
|
|
458
|
-
}
|
|
459
|
-
return showFailureDialog(parentWindow, errorInfo);
|
|
460
|
-
}
|
|
461
|
-
case "open-log": {
|
|
462
|
-
try {
|
|
463
|
-
await shell.openPath(logPath);
|
|
464
|
-
} catch {
|
|
465
|
-
// ignore
|
|
466
|
-
}
|
|
467
|
-
return showFailureDialog(parentWindow, errorInfo);
|
|
468
|
-
}
|
|
469
|
-
default:
|
|
470
|
-
return "quit";
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
return show();
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// ── Pre-check failure dialogs ───────────────────────────────────────────────
|
|
478
|
-
|
|
479
|
-
/**
|
|
480
|
-
* Show a simple retryable error dialog. Used for disk-space / offline errors
|
|
481
|
-
* before install begins.
|
|
482
|
-
* Returns 'retry' or 'quit'.
|
|
483
|
-
*/
|
|
484
|
-
async function showPreCheckFailureDialog(parentWindow, { title, message, detail }) {
|
|
485
|
-
const result = await dialog.showMessageBox(parentWindow || null, {
|
|
486
|
-
type: "warning",
|
|
487
|
-
title: title || "GAIA cannot start",
|
|
488
|
-
message: message || "A pre-flight check failed.",
|
|
489
|
-
detail: detail || "",
|
|
490
|
-
buttons: ["Retry", "Quit"],
|
|
491
|
-
defaultId: 0,
|
|
492
|
-
cancelId: 1,
|
|
493
|
-
noLink: true,
|
|
494
|
-
});
|
|
495
|
-
return result.response === 0 ? "retry" : "quit";
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
module.exports = {
|
|
499
|
-
createProgressWindow,
|
|
500
|
-
buildProgressHtml,
|
|
501
|
-
stageLabel,
|
|
502
|
-
STAGE_LABELS,
|
|
503
|
-
showFailureDialog,
|
|
504
|
-
showPreCheckFailureDialog,
|
|
505
|
-
// IPC channel names for preload.cjs
|
|
506
|
-
IPC_PROGRESS_EVENT,
|
|
507
|
-
IPC_STATUS_REQUEST,
|
|
508
|
-
IPC_COPY_LOG_PATH,
|
|
509
|
-
IPC_OPEN_LOG_FILE,
|
|
510
|
-
};
|