esp32tool 1.6.6 → 1.6.7
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/apple-touch-icon.png +0 -0
- package/css/style.css +325 -25
- package/dist/util/console-color.js +3 -3
- package/dist/util/timestamp-transformer.js +24 -1
- package/electron/cli-main.cjs +19 -19
- package/electron/main.cjs +167 -148
- package/electron/preload.js +16 -18
- package/icons/icon-128.png +0 -0
- package/icons/icon-144.png +0 -0
- package/icons/icon-152.png +0 -0
- package/icons/icon-192.png +0 -0
- package/icons/icon-384.png +0 -0
- package/icons/icon-512.png +0 -0
- package/icons/icon-72.png +0 -0
- package/icons/icon-96.png +0 -0
- package/js/console.js +21 -12
- package/js/hex-editor.js +216 -163
- package/js/improv.js +59 -21
- package/js/nvs-editor.js +1189 -182
- package/js/script.js +1048 -845
- package/js/util/console-color.js +3 -3
- package/js/util/timestamp-transformer.js +24 -1
- package/js/webusb-serial.js +1075 -950
- package/package.cli.json +2 -2
- package/package.json +11 -12
- package/screenshots/desktop.png +0 -0
- package/screenshots/mobile.png +0 -0
- package/src/util/console-color.ts +3 -3
- package/src/util/timestamp-transformer.ts +27 -1
- package/sw.js +1 -1
package/electron/main.cjs
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const {
|
|
2
|
+
app,
|
|
3
|
+
BrowserWindow,
|
|
4
|
+
Menu,
|
|
5
|
+
session,
|
|
6
|
+
ipcMain,
|
|
7
|
+
dialog,
|
|
8
|
+
} = require("electron");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const fs = require("fs");
|
|
4
11
|
|
|
5
12
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
|
6
13
|
// Only required for Windows Squirrel installer
|
|
7
|
-
if (process.platform ===
|
|
14
|
+
if (process.platform === "win32") {
|
|
8
15
|
try {
|
|
9
|
-
if (require(
|
|
16
|
+
if (require("electron-squirrel-startup")) {
|
|
10
17
|
app.quit();
|
|
11
18
|
}
|
|
12
19
|
} catch (e) {
|
|
@@ -28,22 +35,22 @@ function createWindow() {
|
|
|
28
35
|
webPreferences: {
|
|
29
36
|
nodeIntegration: false,
|
|
30
37
|
contextIsolation: true,
|
|
31
|
-
preload: path.join(__dirname,
|
|
38
|
+
preload: path.join(__dirname, "preload.js"),
|
|
32
39
|
},
|
|
33
|
-
icon: path.join(__dirname,
|
|
34
|
-
title:
|
|
40
|
+
icon: path.join(__dirname, "icons", "icon.png"),
|
|
41
|
+
title: "ESP32Tool",
|
|
35
42
|
autoHideMenuBar: false,
|
|
36
43
|
});
|
|
37
44
|
|
|
38
45
|
// Load the index.html of the app
|
|
39
|
-
mainWindow.loadFile(path.join(__dirname,
|
|
46
|
+
mainWindow.loadFile(path.join(__dirname, "..", "index.html"));
|
|
40
47
|
|
|
41
48
|
// Open DevTools in development
|
|
42
|
-
if (process.env.NODE_ENV ===
|
|
49
|
+
if (process.env.NODE_ENV === "development") {
|
|
43
50
|
mainWindow.webContents.openDevTools();
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
mainWindow.on(
|
|
53
|
+
mainWindow.on("closed", () => {
|
|
47
54
|
mainWindow = null;
|
|
48
55
|
});
|
|
49
56
|
|
|
@@ -53,51 +60,56 @@ function createWindow() {
|
|
|
53
60
|
|
|
54
61
|
function setupSerialPortHandlers(ses) {
|
|
55
62
|
const isLikelyEspPort = (port) => {
|
|
56
|
-
const name =
|
|
63
|
+
const name =
|
|
64
|
+
`${port?.displayName || ""} ${port?.portName || ""}`.toLowerCase();
|
|
57
65
|
return (
|
|
58
|
-
name.includes(
|
|
59
|
-
name.includes(
|
|
60
|
-
name.includes(
|
|
61
|
-
name.includes(
|
|
62
|
-
name.includes(
|
|
63
|
-
name.includes(
|
|
64
|
-
name.includes(
|
|
65
|
-
name.includes(
|
|
66
|
-
name.includes(
|
|
67
|
-
name.includes(
|
|
68
|
-
name.includes(
|
|
69
|
-
name.includes(
|
|
70
|
-
name.includes(
|
|
71
|
-
name.includes(
|
|
72
|
-
name.includes(
|
|
73
|
-
name.includes(
|
|
74
|
-
name.includes(
|
|
75
|
-
name.includes(
|
|
66
|
+
name.includes("cp2102") ||
|
|
67
|
+
name.includes("cp2103") ||
|
|
68
|
+
name.includes("cp2104") ||
|
|
69
|
+
name.includes("cp2105") ||
|
|
70
|
+
name.includes("cp2108") ||
|
|
71
|
+
name.includes("ch9102") ||
|
|
72
|
+
name.includes("ch9104") ||
|
|
73
|
+
name.includes("ch340") ||
|
|
74
|
+
name.includes("ch341") ||
|
|
75
|
+
name.includes("ch343") ||
|
|
76
|
+
name.includes("ftdi") ||
|
|
77
|
+
name.includes("ft232") ||
|
|
78
|
+
name.includes("usb") ||
|
|
79
|
+
name.includes("uart") ||
|
|
80
|
+
name.includes("silicon labs") ||
|
|
81
|
+
name.includes("esp32") ||
|
|
82
|
+
name.includes("esp8266") ||
|
|
83
|
+
name.includes("esp")
|
|
76
84
|
);
|
|
77
85
|
};
|
|
78
86
|
|
|
79
|
-
const getPortLabel = (port) =>
|
|
87
|
+
const getPortLabel = (port) =>
|
|
88
|
+
port?.displayName || port?.portName || port?.portId || "Unknown port";
|
|
80
89
|
|
|
81
90
|
const getPortButtonLabel = (port, isRecommended = false) => {
|
|
82
|
-
const shortId =
|
|
91
|
+
const shortId =
|
|
92
|
+
port?.portName || port?.displayName || port?.portId || "Unknown";
|
|
83
93
|
return isRecommended ? `${shortId} (Recommended)` : shortId;
|
|
84
94
|
};
|
|
85
95
|
|
|
86
96
|
const toHexId = (value) =>
|
|
87
|
-
typeof value ===
|
|
97
|
+
typeof value === "number"
|
|
98
|
+
? `0x${value.toString(16).toUpperCase().padStart(4, "0")}`
|
|
99
|
+
: null;
|
|
88
100
|
|
|
89
101
|
// Guard against Electron re-firing select-serial-port while a dialog is open
|
|
90
102
|
let activeSelectionId = 0;
|
|
91
103
|
|
|
92
104
|
// Handle serial port selection - shows when navigator.serial.requestPort() is called
|
|
93
|
-
ses.on(
|
|
105
|
+
ses.on("select-serial-port", (event, portList, webContents, callback) => {
|
|
94
106
|
event.preventDefault();
|
|
95
107
|
|
|
96
108
|
// Filter to only show ESP-compatible ports
|
|
97
109
|
const espPorts = (portList || []).filter(isLikelyEspPort);
|
|
98
110
|
|
|
99
111
|
if (espPorts.length === 0) {
|
|
100
|
-
callback(
|
|
112
|
+
callback("");
|
|
101
113
|
return;
|
|
102
114
|
}
|
|
103
115
|
|
|
@@ -113,35 +125,38 @@ function setupSerialPortHandlers(ses) {
|
|
|
113
125
|
const buttonLabels = espPorts.map((port) => getPortButtonLabel(port));
|
|
114
126
|
const cancelIndex = buttonLabels.length;
|
|
115
127
|
|
|
116
|
-
const ownerWindow =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const ownerWindow =
|
|
129
|
+
BrowserWindow.fromWebContents(webContents) || mainWindow;
|
|
130
|
+
dialog
|
|
131
|
+
.showMessageBox(ownerWindow, {
|
|
132
|
+
type: "question",
|
|
133
|
+
title: "ESP32Tool",
|
|
134
|
+
message: "Select the serial port for your ESP device.",
|
|
135
|
+
buttons: [...buttonLabels, "Cancel"],
|
|
136
|
+
defaultId: 0,
|
|
137
|
+
cancelId: cancelIndex,
|
|
138
|
+
noLink: true,
|
|
139
|
+
})
|
|
140
|
+
.then((result) => {
|
|
141
|
+
// Ignore if a newer select-serial-port event superseded this one
|
|
142
|
+
if (mySelectionId !== activeSelectionId) return;
|
|
143
|
+
const selectedPort = espPorts[result.response];
|
|
144
|
+
callback(selectedPort ? selectedPort.portId : "");
|
|
145
|
+
});
|
|
131
146
|
});
|
|
132
147
|
|
|
133
|
-
ses.on(
|
|
134
|
-
console.log(
|
|
148
|
+
ses.on("serial-port-added", (event, port) => {
|
|
149
|
+
console.log("Serial port added:", port);
|
|
135
150
|
});
|
|
136
151
|
|
|
137
|
-
ses.on(
|
|
138
|
-
console.log(
|
|
152
|
+
ses.on("serial-port-removed", (event, port) => {
|
|
153
|
+
console.log("Serial port removed:", port);
|
|
139
154
|
});
|
|
140
155
|
|
|
141
156
|
ses.setPermissionCheckHandler(() => true);
|
|
142
157
|
|
|
143
158
|
ses.setDevicePermissionHandler((details) => {
|
|
144
|
-
if (details.deviceType ===
|
|
159
|
+
if (details.deviceType === "serial" && details.device) {
|
|
145
160
|
grantedDevices.set(details.device.deviceId, details.device);
|
|
146
161
|
}
|
|
147
162
|
return true;
|
|
@@ -152,73 +167,71 @@ function setupSerialPortHandlers(ses) {
|
|
|
152
167
|
function createMenu() {
|
|
153
168
|
const template = [
|
|
154
169
|
{
|
|
155
|
-
label:
|
|
156
|
-
submenu: [
|
|
157
|
-
{ role: 'quit' }
|
|
158
|
-
]
|
|
170
|
+
label: "File",
|
|
171
|
+
submenu: [{ role: "quit" }],
|
|
159
172
|
},
|
|
160
173
|
{
|
|
161
|
-
label:
|
|
174
|
+
label: "Edit",
|
|
162
175
|
submenu: [
|
|
163
|
-
{ role:
|
|
164
|
-
{ role:
|
|
165
|
-
{ type:
|
|
166
|
-
{ role:
|
|
167
|
-
{ role:
|
|
168
|
-
{ role:
|
|
169
|
-
{ role:
|
|
170
|
-
]
|
|
176
|
+
{ role: "undo" },
|
|
177
|
+
{ role: "redo" },
|
|
178
|
+
{ type: "separator" },
|
|
179
|
+
{ role: "cut" },
|
|
180
|
+
{ role: "copy" },
|
|
181
|
+
{ role: "paste" },
|
|
182
|
+
{ role: "selectAll" },
|
|
183
|
+
],
|
|
171
184
|
},
|
|
172
185
|
{
|
|
173
|
-
label:
|
|
186
|
+
label: "View",
|
|
174
187
|
submenu: [
|
|
175
|
-
{ role:
|
|
176
|
-
{ role:
|
|
177
|
-
{ role:
|
|
178
|
-
{ type:
|
|
179
|
-
{ role:
|
|
180
|
-
{ role:
|
|
181
|
-
{ role:
|
|
182
|
-
{ type:
|
|
183
|
-
{ role:
|
|
184
|
-
]
|
|
188
|
+
{ role: "reload" },
|
|
189
|
+
{ role: "forceReload" },
|
|
190
|
+
{ role: "toggleDevTools" },
|
|
191
|
+
{ type: "separator" },
|
|
192
|
+
{ role: "resetZoom" },
|
|
193
|
+
{ role: "zoomIn" },
|
|
194
|
+
{ role: "zoomOut" },
|
|
195
|
+
{ type: "separator" },
|
|
196
|
+
{ role: "togglefullscreen" },
|
|
197
|
+
],
|
|
185
198
|
},
|
|
186
199
|
{
|
|
187
|
-
label:
|
|
200
|
+
label: "Help",
|
|
188
201
|
submenu: [
|
|
189
202
|
{
|
|
190
|
-
label:
|
|
203
|
+
label: "About ESP32Tool",
|
|
191
204
|
click: async () => {
|
|
192
|
-
const { shell } = require(
|
|
193
|
-
await shell.openExternal(
|
|
194
|
-
}
|
|
205
|
+
const { shell } = require("electron");
|
|
206
|
+
await shell.openExternal("https://github.com/Jason2866/esp32tool");
|
|
207
|
+
},
|
|
195
208
|
},
|
|
196
209
|
{
|
|
197
|
-
label:
|
|
210
|
+
label: "ESP32 Documentation",
|
|
198
211
|
click: async () => {
|
|
199
|
-
const { shell } = require(
|
|
200
|
-
await shell.openExternal(
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
]
|
|
204
|
-
}
|
|
212
|
+
const { shell } = require("electron");
|
|
213
|
+
await shell.openExternal("https://docs.espressif.com/");
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
},
|
|
205
218
|
];
|
|
206
219
|
|
|
207
220
|
// macOS specific menu adjustments
|
|
208
|
-
if (process.platform ===
|
|
221
|
+
if (process.platform === "darwin") {
|
|
209
222
|
template.unshift({
|
|
210
223
|
label: app.getName(),
|
|
211
224
|
submenu: [
|
|
212
|
-
{ role:
|
|
213
|
-
{ type:
|
|
214
|
-
{ role:
|
|
215
|
-
{ type:
|
|
216
|
-
{ role:
|
|
217
|
-
{ role:
|
|
218
|
-
{ role:
|
|
219
|
-
{ type:
|
|
220
|
-
{ role:
|
|
221
|
-
]
|
|
225
|
+
{ role: "about" },
|
|
226
|
+
{ type: "separator" },
|
|
227
|
+
{ role: "services" },
|
|
228
|
+
{ type: "separator" },
|
|
229
|
+
{ role: "hide" },
|
|
230
|
+
{ role: "hideOthers" },
|
|
231
|
+
{ role: "unhide" },
|
|
232
|
+
{ type: "separator" },
|
|
233
|
+
{ role: "quit" },
|
|
234
|
+
],
|
|
222
235
|
});
|
|
223
236
|
}
|
|
224
237
|
|
|
@@ -231,7 +244,7 @@ app.whenReady().then(() => {
|
|
|
231
244
|
createMenu();
|
|
232
245
|
createWindow();
|
|
233
246
|
|
|
234
|
-
app.on(
|
|
247
|
+
app.on("activate", () => {
|
|
235
248
|
// On macOS re-create a window when dock icon is clicked and no windows are open
|
|
236
249
|
if (BrowserWindow.getAllWindows().length === 0) {
|
|
237
250
|
createWindow();
|
|
@@ -240,8 +253,8 @@ app.whenReady().then(() => {
|
|
|
240
253
|
});
|
|
241
254
|
|
|
242
255
|
// Quit when all windows are closed, except on macOS
|
|
243
|
-
app.on(
|
|
244
|
-
if (process.platform !==
|
|
256
|
+
app.on("window-all-closed", () => {
|
|
257
|
+
if (process.platform !== "darwin") {
|
|
245
258
|
app.quit();
|
|
246
259
|
}
|
|
247
260
|
});
|
|
@@ -251,37 +264,40 @@ app.on('window-all-closed', () => {
|
|
|
251
264
|
// ============================================
|
|
252
265
|
|
|
253
266
|
// Save file dialog and write data
|
|
254
|
-
ipcMain.handle(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
267
|
+
ipcMain.handle(
|
|
268
|
+
"save-file",
|
|
269
|
+
async (event, { data, defaultFilename, filters }) => {
|
|
270
|
+
const result = await dialog.showSaveDialog(mainWindow, {
|
|
271
|
+
defaultPath: defaultFilename,
|
|
272
|
+
filters: filters || [
|
|
273
|
+
{ name: "Binary Files", extensions: ["bin"] },
|
|
274
|
+
{ name: "All Files", extensions: ["*"] },
|
|
275
|
+
],
|
|
276
|
+
});
|
|
262
277
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
278
|
+
if (result.canceled || !result.filePath) {
|
|
279
|
+
return { success: false, canceled: true };
|
|
280
|
+
}
|
|
266
281
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
282
|
+
try {
|
|
283
|
+
// Convert data to Buffer if it's a Uint8Array
|
|
284
|
+
const buffer = Buffer.from(data);
|
|
285
|
+
fs.writeFileSync(result.filePath, buffer);
|
|
286
|
+
return { success: true, filePath: result.filePath };
|
|
287
|
+
} catch (error) {
|
|
288
|
+
return { success: false, error: error.message };
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
);
|
|
276
292
|
|
|
277
293
|
// Open file dialog and read data
|
|
278
|
-
ipcMain.handle(
|
|
294
|
+
ipcMain.handle("open-file", async (event, { filters }) => {
|
|
279
295
|
const result = await dialog.showOpenDialog(mainWindow, {
|
|
280
|
-
properties: [
|
|
296
|
+
properties: ["openFile"],
|
|
281
297
|
filters: filters || [
|
|
282
|
-
{ name:
|
|
283
|
-
{ name:
|
|
284
|
-
]
|
|
298
|
+
{ name: "Binary Files", extensions: ["bin"] },
|
|
299
|
+
{ name: "All Files", extensions: ["*"] },
|
|
300
|
+
],
|
|
285
301
|
});
|
|
286
302
|
|
|
287
303
|
if (result.canceled || result.filePaths.length === 0) {
|
|
@@ -292,11 +308,11 @@ ipcMain.handle('open-file', async (event, { filters }) => {
|
|
|
292
308
|
const filePath = result.filePaths[0];
|
|
293
309
|
const data = fs.readFileSync(filePath);
|
|
294
310
|
const filename = path.basename(filePath);
|
|
295
|
-
return {
|
|
296
|
-
success: true,
|
|
297
|
-
filePath,
|
|
311
|
+
return {
|
|
312
|
+
success: true,
|
|
313
|
+
filePath,
|
|
298
314
|
filename,
|
|
299
|
-
data: Array.from(data) // Convert Buffer to array for IPC transfer
|
|
315
|
+
data: Array.from(data), // Convert Buffer to array for IPC transfer
|
|
300
316
|
};
|
|
301
317
|
} catch (error) {
|
|
302
318
|
return { success: false, error: error.message };
|
|
@@ -304,30 +320,33 @@ ipcMain.handle('open-file', async (event, { filters }) => {
|
|
|
304
320
|
});
|
|
305
321
|
|
|
306
322
|
// Show input dialog (replacement for prompt())
|
|
307
|
-
ipcMain.handle(
|
|
323
|
+
ipcMain.handle("show-prompt", async (event, { message, defaultValue }) => {
|
|
308
324
|
// Use a simple approach - return the default value
|
|
309
325
|
// In Electron, we use the save dialog instead of prompt
|
|
310
326
|
return defaultValue;
|
|
311
327
|
});
|
|
312
328
|
|
|
313
329
|
// Show message box
|
|
314
|
-
ipcMain.handle(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
});
|
|
330
|
+
ipcMain.handle(
|
|
331
|
+
"show-message",
|
|
332
|
+
async (event, { type, title, message, buttons }) => {
|
|
333
|
+
const result = await dialog.showMessageBox(mainWindow, {
|
|
334
|
+
type: type || "info",
|
|
335
|
+
title: title || "ESP32Tool",
|
|
336
|
+
message: message,
|
|
337
|
+
buttons: buttons || ["OK"],
|
|
338
|
+
});
|
|
339
|
+
return result.response;
|
|
340
|
+
},
|
|
341
|
+
);
|
|
323
342
|
|
|
324
343
|
// Show confirm dialog
|
|
325
|
-
ipcMain.handle(
|
|
344
|
+
ipcMain.handle("show-confirm", async (event, { message }) => {
|
|
326
345
|
const result = await dialog.showMessageBox(mainWindow, {
|
|
327
|
-
type:
|
|
328
|
-
title:
|
|
346
|
+
type: "question",
|
|
347
|
+
title: "Confirm",
|
|
329
348
|
message: message,
|
|
330
|
-
buttons: [
|
|
349
|
+
buttons: ["OK", "Cancel"],
|
|
331
350
|
});
|
|
332
351
|
return result.response === 0; // true if OK clicked
|
|
333
352
|
});
|
package/electron/preload.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Preload script for Electron
|
|
2
2
|
// This runs in a sandboxed environment with access to some Node.js APIs
|
|
3
3
|
|
|
4
|
-
const { contextBridge, ipcRenderer } = require(
|
|
4
|
+
const { contextBridge, ipcRenderer } = require("electron");
|
|
5
5
|
|
|
6
6
|
// Expose platform info and file APIs to renderer
|
|
7
|
-
contextBridge.exposeInMainWorld(
|
|
7
|
+
contextBridge.exposeInMainWorld("electronAPI", {
|
|
8
8
|
platform: process.platform,
|
|
9
9
|
isElectron: true,
|
|
10
10
|
versions: {
|
|
@@ -12,26 +12,24 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|
|
12
12
|
chrome: process.versions.chrome,
|
|
13
13
|
electron: process.versions.electron,
|
|
14
14
|
},
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
// File operations
|
|
17
|
-
saveFile: (data, defaultFilename, filters) =>
|
|
18
|
-
ipcRenderer.invoke(
|
|
19
|
-
|
|
20
|
-
openFile: (filters) =>
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
saveFile: (data, defaultFilename, filters) =>
|
|
18
|
+
ipcRenderer.invoke("save-file", { data, defaultFilename, filters }),
|
|
19
|
+
|
|
20
|
+
openFile: (filters) => ipcRenderer.invoke("open-file", { filters }),
|
|
21
|
+
|
|
23
22
|
// Dialog operations
|
|
24
23
|
showPrompt: (message, defaultValue) =>
|
|
25
|
-
ipcRenderer.invoke(
|
|
26
|
-
|
|
24
|
+
ipcRenderer.invoke("show-prompt", { message, defaultValue }),
|
|
25
|
+
|
|
27
26
|
showMessage: (type, title, message, buttons) =>
|
|
28
|
-
ipcRenderer.invoke(
|
|
29
|
-
|
|
30
|
-
showConfirm: (message) =>
|
|
31
|
-
ipcRenderer.invoke('show-confirm', { message })
|
|
27
|
+
ipcRenderer.invoke("show-message", { type, title, message, buttons }),
|
|
28
|
+
|
|
29
|
+
showConfirm: (message) => ipcRenderer.invoke("show-confirm", { message }),
|
|
32
30
|
});
|
|
33
31
|
|
|
34
32
|
// Log when preload script runs
|
|
35
|
-
console.log(
|
|
36
|
-
console.log(
|
|
37
|
-
console.log(
|
|
33
|
+
console.log("Electron preload script loaded");
|
|
34
|
+
console.log("Platform:", process.platform);
|
|
35
|
+
console.log("Electron version:", process.versions.electron);
|
package/icons/icon-128.png
CHANGED
|
Binary file
|
package/icons/icon-144.png
CHANGED
|
Binary file
|
package/icons/icon-152.png
CHANGED
|
Binary file
|
package/icons/icon-192.png
CHANGED
|
Binary file
|
package/icons/icon-384.png
CHANGED
|
Binary file
|
package/icons/icon-512.png
CHANGED
|
Binary file
|
package/icons/icon-72.png
CHANGED
|
Binary file
|
package/icons/icon-96.png
CHANGED
|
Binary file
|
package/js/console.js
CHANGED
|
@@ -133,7 +133,7 @@ export class ESP32ToolConsole {
|
|
|
133
133
|
`;
|
|
134
134
|
|
|
135
135
|
this.console = new ColoredConsole(
|
|
136
|
-
this.containerElement.querySelector(".log")
|
|
136
|
+
this.containerElement.querySelector(".log"),
|
|
137
137
|
);
|
|
138
138
|
|
|
139
139
|
// Setup event listeners
|
|
@@ -152,18 +152,22 @@ export class ESP32ToolConsole {
|
|
|
152
152
|
closeBtn.addEventListener("click", () => {
|
|
153
153
|
// Dispatch close event to parent
|
|
154
154
|
this.containerElement.dispatchEvent(
|
|
155
|
-
new CustomEvent("console-close", { bubbles: true })
|
|
155
|
+
new CustomEvent("console-close", { bubbles: true }),
|
|
156
156
|
);
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
const improvBtn = this.containerElement.querySelector(
|
|
160
|
+
const improvBtn = this.containerElement.querySelector(
|
|
161
|
+
"#console-improv-btn",
|
|
162
|
+
);
|
|
161
163
|
if (improvBtn) {
|
|
162
164
|
improvBtn.addEventListener("click", () => this._openImprov());
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
if (this.allowInput) {
|
|
166
|
-
const input = this.containerElement.querySelector(
|
|
168
|
+
const input = this.containerElement.querySelector(
|
|
169
|
+
".esp32tool-console-input",
|
|
170
|
+
);
|
|
167
171
|
|
|
168
172
|
this.containerElement.addEventListener("click", () => {
|
|
169
173
|
// Only focus input if user didn't select some text
|
|
@@ -217,10 +221,10 @@ export class ESP32ToolConsole {
|
|
|
217
221
|
this.console.addLine("");
|
|
218
222
|
this.console.addLine("");
|
|
219
223
|
this.console.addLine(
|
|
220
|
-
`Terminal disconnected: Port readable stream not available
|
|
224
|
+
`Terminal disconnected: Port readable stream not available`,
|
|
221
225
|
);
|
|
222
226
|
console.error(
|
|
223
|
-
"Port readable stream not available - port may need to be reopened at correct baudrate"
|
|
227
|
+
"Port readable stream not available - port may need to be reopened at correct baudrate",
|
|
224
228
|
);
|
|
225
229
|
return;
|
|
226
230
|
}
|
|
@@ -248,14 +252,14 @@ export class ESP32ToolConsole {
|
|
|
248
252
|
if (pat.test(chunk)) {
|
|
249
253
|
bootloaderDetected = true;
|
|
250
254
|
this.containerElement.dispatchEvent(
|
|
251
|
-
new CustomEvent("console-bootloader", { bubbles: true })
|
|
255
|
+
new CustomEvent("console-bootloader", { bubbles: true }),
|
|
252
256
|
);
|
|
253
257
|
break;
|
|
254
258
|
}
|
|
255
259
|
}
|
|
256
260
|
}
|
|
257
261
|
},
|
|
258
|
-
})
|
|
262
|
+
}),
|
|
259
263
|
);
|
|
260
264
|
if (!abortSignal.aborted) {
|
|
261
265
|
this.console.addLine("");
|
|
@@ -264,7 +268,10 @@ export class ESP32ToolConsole {
|
|
|
264
268
|
}
|
|
265
269
|
} catch (e) {
|
|
266
270
|
// Only log disconnect errors if the abort was NOT intentional
|
|
267
|
-
if (
|
|
271
|
+
if (
|
|
272
|
+
!abortSignal.aborted &&
|
|
273
|
+
!(e instanceof DOMException && e.name === "AbortError")
|
|
274
|
+
) {
|
|
268
275
|
this.console.addLine("");
|
|
269
276
|
this.console.addLine("");
|
|
270
277
|
this.console.addLine(`Terminal disconnected: ${e}`);
|
|
@@ -297,7 +304,9 @@ export class ESP32ToolConsole {
|
|
|
297
304
|
}
|
|
298
305
|
|
|
299
306
|
async _sendCommand() {
|
|
300
|
-
const input = this.containerElement.querySelector(
|
|
307
|
+
const input = this.containerElement.querySelector(
|
|
308
|
+
".esp32tool-console-input",
|
|
309
|
+
);
|
|
301
310
|
const command = input.value;
|
|
302
311
|
|
|
303
312
|
if (command.trim() !== "") {
|
|
@@ -347,8 +356,8 @@ export class ESP32ToolConsole {
|
|
|
347
356
|
|
|
348
357
|
// Only check the first 30 lines (same as _connect) to avoid false positives
|
|
349
358
|
// from bootloader patterns appearing later in normal firmware output
|
|
350
|
-
const lines = text.split(
|
|
351
|
-
const firstLines = lines.slice(0, 30).join(
|
|
359
|
+
const lines = text.split("\n");
|
|
360
|
+
const firstLines = lines.slice(0, 30).join("\n");
|
|
352
361
|
|
|
353
362
|
for (const pat of BOOTLOADER_PATTERNS) {
|
|
354
363
|
if (pat.test(firstLines)) {
|