esp32tool 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.nojekyll +0 -0
  2. package/README.md +100 -6
  3. package/apple-touch-icon.png +0 -0
  4. package/build-electron-cli.cjs +177 -0
  5. package/build-single-binary.cjs +295 -0
  6. package/css/light.css +11 -0
  7. package/css/style.css +225 -35
  8. package/dist/cli.d.ts +17 -0
  9. package/dist/cli.js +458 -0
  10. package/dist/esp_loader.d.ts +129 -21
  11. package/dist/esp_loader.js +1227 -222
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.js +37 -4
  14. package/dist/node-usb-adapter.d.ts +47 -0
  15. package/dist/node-usb-adapter.js +725 -0
  16. package/dist/stubs/index.d.ts +1 -2
  17. package/dist/stubs/index.js +4 -0
  18. package/dist/web/index.js +1 -1
  19. package/electron/cli-main.cjs +74 -0
  20. package/electron/main.cjs +338 -0
  21. package/electron/main.js +7 -2
  22. package/favicon.ico +0 -0
  23. package/fix-cli-imports.cjs +127 -0
  24. package/generate-icons.sh +89 -0
  25. package/icons/icon-128.png +0 -0
  26. package/icons/icon-144.png +0 -0
  27. package/icons/icon-152.png +0 -0
  28. package/icons/icon-192.png +0 -0
  29. package/icons/icon-384.png +0 -0
  30. package/icons/icon-512.png +0 -0
  31. package/icons/icon-72.png +0 -0
  32. package/icons/icon-96.png +0 -0
  33. package/index.html +94 -64
  34. package/install-android.html +411 -0
  35. package/js/modules/esptool.js +1 -1
  36. package/js/script.js +165 -160
  37. package/js/webusb-serial.js +1017 -0
  38. package/license.md +1 -1
  39. package/manifest.json +89 -0
  40. package/package.cli.json +29 -0
  41. package/package.json +31 -21
  42. package/screenshots/desktop.png +0 -0
  43. package/screenshots/mobile.png +0 -0
  44. package/src/cli.ts +618 -0
  45. package/src/esp_loader.ts +1438 -254
  46. package/src/index.ts +69 -3
  47. package/src/node-usb-adapter.ts +924 -0
  48. package/src/stubs/index.ts +4 -1
  49. package/sw.js +155 -0
package/.nojekyll ADDED
File without changes
package/README.md CHANGED
@@ -2,9 +2,43 @@
2
2
 
3
3
  # šŸš€ ESP32Tool – The Ultimate ESP Filesystem Powerhouse
4
4
 
5
- **Flash. Manage. Dominate. All in your browser.**
5
+ **Flash. Manage. Dominate. In your browser, on desktop, mobile, or command line.**
6
6
 
7
- Meet **ESP32Tool** – your all-in-one, next-gen solution for ESP device management. Experience seamless firmware flashing, backup, and now, full filesystem control with just a few clicks. No drivers, no command line, no limits!
7
+ Meet **ESP32Tool** – your all-in-one, next-gen solution for ESP device management. Experience seamless firmware flashing, backup, and now, full filesystem control with just a few clicks. No drivers, no command line hassle, no limits!
8
+
9
+ ---
10
+
11
+ ## šŸ“¦ Available Versions
12
+
13
+ **Choose the version that fits your workflow:**
14
+
15
+ ### 🌐 Web App (Browser)
16
+ - **Zero installation** – runs directly in your browser
17
+ - Works on any modern desktop or mobile browser
18
+ - Perfect for quick tasks and on-the-go management
19
+ - **Try it now:** [jason2866.github.io/esp32tool](https://jason2866.github.io/esp32tool)
20
+
21
+ ### šŸ“± Mobile App (Android PWA)
22
+ - **Install as native app** on Android devices
23
+ - Works with USB OTG adapters via WebUSB
24
+ - Full ESP management on your phone or tablet
25
+ - **Install:** Visit [jason2866.github.io/esp32tool](https://jason2866.github.io/esp32tool) in Chrome → "Add to Home screen"
26
+ - **Details:** See [Android Installation](#-android-installation-pwa) below
27
+
28
+ ### šŸ’» Desktop App (Electron GUI)
29
+ - **Full-featured GUI** with all web capabilities
30
+ - Offline-ready, no internet required
31
+ - Native desktop integration
32
+ - **Download:** [Latest Release](https://github.com/Jason2866/esp32tool/releases)
33
+ - Available for: macOS (Intel & Apple Silicon), Windows, Linux
34
+
35
+ ### āŒØļø Command Line Interface (CLI)
36
+ - **Standalone executable** – no Node.js required!
37
+ - Perfect for automation and scripting
38
+ - esptool.py-compatible commands
39
+ - **Download:** [Latest Release](https://github.com/Jason2866/esp32tool/releases)
40
+ - **Documentation:** [CLI-README.md](CLI-README.md)
41
+ - Available for: macOS (Intel & Apple Silicon), Windows, Linux
8
42
 
9
43
  ---
10
44
 
@@ -18,7 +52,9 @@ ESP32Tool is designed first and foremost for the entire ESP32 family – deliver
18
52
  - **Lightning Fast:** Custom, high-performance flash access – up to 10x faster than esptool.py!
19
53
  - **Rock-Solid Reliability:** Automatic resume on read errors. No more broken operations, ever.
20
54
  - **Plug & Play:** Manage your ESP directly in the browser. No software installation needed.
21
- - **Offline Ready:** Prefer desktop? Grab the Electron app from our [releases](https://github.com/Jason2866/esp32tool/releases).
55
+ - **Multi-Platform:** Available as web app, desktop app (Electron), and standalone CLI
56
+ - **Offline Ready:** Desktop and CLI versions work completely offline
57
+ - **šŸ“± Android Ready:** Install as Progressive Web App (PWA) on Android! Works with USB OTG adapters via WebUSB.
22
58
 
23
59
  - **Bonus:** ESP8266 support is now included! Manage filesystems on ESP8266 devices with the same ease.
24
60
 
@@ -26,6 +62,60 @@ ESP32Tool is designed first and foremost for the entire ESP32 family – deliver
26
62
 
27
63
  ---
28
64
 
65
+ ## šŸ“¦ Desktop & CLI Installation
66
+
67
+ ### Desktop App (GUI)
68
+
69
+ **Download from [GitHub Releases](https://github.com/Jason2866/esp32tool/releases)**
70
+
71
+ - **macOS:** Download `ESP32Tool-*.dmg`, open and drag to Applications
72
+ - **Windows:** Download and run `ESP32Tool-Setup-*.exe` installer
73
+ - **Linux:** Download `.deb` (Debian/Ubuntu) or `.rpm` (Fedora/RHEL) package
74
+
75
+ ### Command Line Interface
76
+
77
+ **Download from [GitHub Releases](https://github.com/Jason2866/esp32tool/releases)**
78
+
79
+ Look for `ESP32Tool-CLI-*` files. No Node.js installation required!
80
+
81
+ **Quick Start:**
82
+ ```bash
83
+ # macOS
84
+ /Applications/ESP32Tool.app/Contents/MacOS/esp32tool list-ports
85
+ /Applications/ESP32Tool.app/Contents/MacOS/esp32tool --port /dev/ttyUSB0 chip-id
86
+
87
+ # Linux
88
+ ./esp32tool list-ports
89
+ ./esp32tool --port /dev/ttyUSB0 chip-id
90
+
91
+ # Windows
92
+ esp32tool.exe list-ports
93
+ esp32tool.exe --port COM3 chip-id
94
+ ```
95
+
96
+ **Full CLI documentation:** [CLI-README.md](CLI-README.md)
97
+
98
+ ---
99
+
100
+ ## šŸ“± Android Installation (PWA)
101
+
102
+ ESP32Tool works natively on Android devices with USB OTG support!
103
+
104
+ **Requirements:**
105
+ - Android 5.0+ (Lollipop or higher)
106
+ - Chrome for Android 61+ (recommended: latest version)
107
+ - USB OTG adapter/cable
108
+ - ESP32/ESP8266 device
109
+
110
+ **Installation:**
111
+ 1. Open [jason2866.github.io/esp32tool](https://jason2866.github.io/esp32tool) in Chrome
112
+ 2. Tap the menu (ā‹®) → "Add to Home screen" or "Install app"
113
+ 3. Connect your ESP device via USB OTG adapter
114
+ 4. Grant USB permissions when prompted
115
+ 5. Flash and manage your ESP devices on the go!
116
+
117
+ ---
118
+
29
119
  ## šŸ› ļø Developer Quickstart
30
120
 
31
121
  1. Clone this repository
@@ -35,11 +125,15 @@ ESP32Tool is designed first and foremost for the entire ESP32 family – deliver
35
125
 
36
126
  ---
37
127
 
38
- ## šŸ† Our Story
128
+ ## šŸ† The Story
129
+
130
+ Born from the minds of [Melissa LeBlanc-Williams](https://github.com/makermelissa), Adafruit, Nabu Casa and now supercharged by Jason2866, ESP32Tool has evolved into the most advanced, browser-based ESP management suite. With every update, the boundaries are pushed of what’s possible for your ESP devices.
131
+
132
+ **Latest updates:**
39
133
 
40
- Born from the minds of [Melissa LeBlanc-Williams](https://github.com/makermelissa), [Nabu Casa](https://www.nabucasa.com), Adafruit, and now supercharged by Jason2866, ESP32Tool has evolved into the most advanced, browser-based ESP management suite. With every update, we push the boundaries of what’s possible for your ESP devices.
134
+ December 2025 – Now with full LittleFS, SPIFFS, and FATFS support, plus file add/delete magic! Available as web app and desktop GUI.
41
135
 
42
- **Latest update:** December 2025 – Now with full LittleFS, SPIFFS, and FATFS support, plus file add/delete magic!
136
+ January 2026 – Added Android mobile devices support, standalone CLI.
43
137
 
44
138
  ---
45
139
 
Binary file
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Build standalone Electron-based CLI binaries
5
+ * Creates truly standalone executables that don't require Node.js installation
6
+ *
7
+ * IMPORTANT: This script temporarily swaps package.json with package.cli.json
8
+ * during the build process, then restores the original package.json.
9
+ *
10
+ * When releasing a new version:
11
+ * 1. Update version in package.json
12
+ * 2. Update version in package.cli.json (keep in sync!)
13
+ * 3. Run this script to build CLI binaries
14
+ */
15
+
16
+ const { execSync } = require('child_process');
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ console.log('Building Electron-based CLI binaries...\n');
21
+
22
+ // Ensure dist is built
23
+ if (!fs.existsSync('dist/cli.js')) {
24
+ console.log('Building TypeScript first...');
25
+ execSync('npm run build', { stdio: 'inherit' });
26
+ }
27
+
28
+ // Read package files
29
+ const originalPackage = fs.readFileSync('package.json', 'utf8');
30
+ const cliPackageContent = fs.readFileSync('package.cli.json', 'utf8');
31
+
32
+ // Parse and sync versions
33
+ const originalPkg = JSON.parse(originalPackage);
34
+ const cliPkg = JSON.parse(cliPackageContent);
35
+
36
+ if (originalPkg.version !== cliPkg.version) {
37
+ console.log(`āš ļø Version mismatch detected!`);
38
+ console.log(` package.json: ${originalPkg.version}`);
39
+ console.log(` package.cli.json: ${cliPkg.version}`);
40
+ console.log(` Syncing package.cli.json to ${originalPkg.version}...\n`);
41
+
42
+ cliPkg.version = originalPkg.version;
43
+ }
44
+
45
+ // Sync dependencies from main package.json to CLI package.json
46
+ if (originalPkg.dependencies) {
47
+ if (JSON.stringify(originalPkg.dependencies) !== JSON.stringify(cliPkg.dependencies)) {
48
+ console.log(`āš ļø Dependencies mismatch detected!`);
49
+ console.log(` Syncing dependencies from package.json to package.cli.json...\n`);
50
+ cliPkg.dependencies = originalPkg.dependencies;
51
+ }
52
+ }
53
+
54
+ // Save synced package.cli.json if changes were made
55
+ if (originalPkg.version !== JSON.parse(cliPackageContent).version ||
56
+ JSON.stringify(originalPkg.dependencies) !== JSON.stringify(JSON.parse(cliPackageContent).dependencies)) {
57
+ fs.writeFileSync('package.cli.json', JSON.stringify(cliPkg, null, 2) + '\n');
58
+ }
59
+
60
+ const cliPackage = JSON.stringify(cliPkg, null, 2);
61
+
62
+ try {
63
+ // Backup original package.json
64
+ fs.writeFileSync('package.json.backup', originalPackage);
65
+
66
+ // Use CLI package.json
67
+ fs.writeFileSync('package.json', cliPackage);
68
+
69
+ // Temporarily swap forge configs
70
+ if (fs.existsSync('forge.config.cjs')) {
71
+ fs.renameSync('forge.config.cjs', 'forge.config.cjs.gui-backup');
72
+ }
73
+ if (fs.existsSync('forge.config.cli.cjs')) {
74
+ fs.renameSync('forge.config.cli.cjs', 'forge.config.cjs');
75
+ }
76
+
77
+ // Build for current platform
78
+ const platform = process.platform;
79
+ const arch = process.arch;
80
+
81
+ console.log(`\nBuilding CLI for ${platform}-${arch}...`);
82
+
83
+ // Backup GUI builds if they exist
84
+ let guiBackupPath = null;
85
+ if (fs.existsSync('out')) {
86
+ guiBackupPath = 'out-gui-backup-' + Date.now();
87
+ console.log(`āš ļø Backing up existing GUI builds to ${guiBackupPath}...`);
88
+ fs.renameSync('out', guiBackupPath);
89
+ }
90
+
91
+ try {
92
+ execSync(`npx electron-forge package --platform=${platform} --arch=${arch}`, {
93
+ stdio: 'inherit'
94
+ });
95
+
96
+ execSync(`npx electron-forge make --platform=${platform} --arch=${arch}`, {
97
+ stdio: 'inherit'
98
+ });
99
+
100
+ // Move CLI output to out-cli directory
101
+ if (fs.existsSync('out')) {
102
+ if (fs.existsSync('out-cli')) {
103
+ fs.rmSync('out-cli', { recursive: true, force: true });
104
+ }
105
+ fs.renameSync('out', 'out-cli');
106
+ }
107
+
108
+ // Restore GUI builds
109
+ if (guiBackupPath && fs.existsSync(guiBackupPath)) {
110
+ console.log('āœ“ Restoring GUI builds...');
111
+ fs.renameSync(guiBackupPath, 'out');
112
+ }
113
+ } catch (error) {
114
+ // Restore GUI builds even on error
115
+ if (guiBackupPath && fs.existsSync(guiBackupPath)) {
116
+ console.log('āš ļø Restoring GUI builds after error...');
117
+ if (fs.existsSync('out')) {
118
+ fs.rmSync('out', { recursive: true, force: true });
119
+ }
120
+ fs.renameSync(guiBackupPath, 'out');
121
+ }
122
+ throw error;
123
+ }
124
+
125
+
126
+ // Rename release files to add -CLI suffix
127
+ const makeDir = path.join('out-cli', 'make');
128
+ if (fs.existsSync(makeDir)) {
129
+ const renameInDir = (dir) => {
130
+ if (!fs.existsSync(dir)) return;
131
+ const files = fs.readdirSync(dir, { recursive: true, withFileTypes: true });
132
+ files.forEach(file => {
133
+ if (file.isFile()) {
134
+ const oldPath = path.join(file.path || file.parentPath, file.name);
135
+ let newName = file.name;
136
+
137
+ // Handle different file types
138
+ if (file.name.endsWith('.zip') || file.name.endsWith('.exe')) {
139
+ // Add -CLI before the platform identifier
140
+ newName = file.name.replace(/(ESP32Tool)(-darwin|-linux|-win32)/, '$1-CLI$2');
141
+ } else if (file.name.endsWith('.deb')) {
142
+ // esp32tool_1.2.0_amd64.deb -> esp32tool-cli_1.2.0_amd64.deb
143
+ newName = file.name.replace(/^esp32tool_/, 'esp32tool-cli_');
144
+ } else if (file.name.endsWith('.rpm')) {
145
+ // esp32tool-1.2.0-1.x86_64.rpm -> esp32tool-cli-1.2.0-1.x86_64.rpm
146
+ newName = file.name.replace(/^esp32tool-/, 'esp32tool-cli-');
147
+ }
148
+
149
+ const newPath = path.join(file.path || file.parentPath, newName);
150
+ if (oldPath !== newPath) {
151
+ fs.renameSync(oldPath, newPath);
152
+ console.log(`Renamed: ${file.name} -> ${newName}`);
153
+ }
154
+ }
155
+ });
156
+ };
157
+ renameInDir(makeDir);
158
+ }
159
+
160
+ console.log('\nāœ“ CLI binaries built successfully!');
161
+ console.log('Output: out-cli/make/');
162
+
163
+ } finally {
164
+ // Restore forge configs
165
+ if (fs.existsSync('forge.config.cjs')) {
166
+ fs.renameSync('forge.config.cjs', 'forge.config.cli.cjs');
167
+ }
168
+ if (fs.existsSync('forge.config.cjs.gui-backup')) {
169
+ fs.renameSync('forge.config.cjs.gui-backup', 'forge.config.cjs');
170
+ }
171
+
172
+ // Restore original package.json
173
+ fs.writeFileSync('package.json', originalPackage);
174
+ if (fs.existsSync('package.json.backup')) {
175
+ fs.unlinkSync('package.json.backup');
176
+ }
177
+ }
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Build single executable binaries for all platforms
4
+ * Creates self-contained executables that include Node.js + app + dependencies
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const { execSync } = require('child_process');
10
+ const archiver = require('archiver');
11
+
12
+ const packageJson = require('./package.json');
13
+ const VERSION = packageJson.version;
14
+ const NODE_VERSION = packageJson.engines.node.replace(/[^\d.]/g, '').split('.')[0]; // Extract major version
15
+
16
+ console.log(`Building ESP32Tool CLI v${VERSION} single executables...\n`);
17
+
18
+ // Create binaries directory
19
+ const binariesDir = path.join(__dirname, 'binaries');
20
+ if (!fs.existsSync(binariesDir)) {
21
+ fs.mkdirSync(binariesDir, { recursive: true });
22
+ }
23
+
24
+ // Build the app first
25
+ console.log('1. Building application...');
26
+ execSync('npm run build', { stdio: 'inherit' });
27
+
28
+ /**
29
+ * Get all dependencies recursively from package.json
30
+ */
31
+ function getAllDependencies() {
32
+ const dependencies = new Set();
33
+
34
+ // Add direct dependencies from package.json
35
+ if (packageJson.dependencies) {
36
+ Object.keys(packageJson.dependencies).forEach(dep => dependencies.add(dep));
37
+ }
38
+
39
+ // Add scoped packages that are dependencies of our dependencies
40
+ const nodeModulesDir = path.join(__dirname, 'node_modules');
41
+
42
+ // Helper to recursively find dependencies
43
+ function addDepsRecursively(moduleName) {
44
+ const modulePath = path.join(nodeModulesDir, moduleName);
45
+ if (!fs.existsSync(modulePath)) return;
46
+
47
+ const modulePackageJson = path.join(modulePath, 'package.json');
48
+ if (fs.existsSync(modulePackageJson)) {
49
+ try {
50
+ const pkg = JSON.parse(fs.readFileSync(modulePackageJson, 'utf8'));
51
+ if (pkg.dependencies) {
52
+ Object.keys(pkg.dependencies).forEach(dep => {
53
+ if (!dependencies.has(dep)) {
54
+ dependencies.add(dep);
55
+ addDepsRecursively(dep);
56
+ }
57
+ });
58
+ }
59
+ } catch (err) {
60
+ // Ignore invalid package.json
61
+ }
62
+ }
63
+ }
64
+
65
+ // Recursively add dependencies
66
+ Array.from(dependencies).forEach(dep => addDepsRecursively(dep));
67
+
68
+ return Array.from(dependencies);
69
+ }
70
+
71
+ /**
72
+ * Create bundle directory with all necessary files
73
+ */
74
+ function createBundle() {
75
+ const bundleDir = path.join(__dirname, '.bundle-temp');
76
+
77
+ // Clean up old bundle
78
+ if (fs.existsSync(bundleDir)) {
79
+ fs.rmSync(bundleDir, { recursive: true });
80
+ }
81
+
82
+ fs.mkdirSync(bundleDir, { recursive: true });
83
+
84
+ console.log('2. Creating bundle...');
85
+
86
+ // Copy dist
87
+ fs.cpSync(path.join(__dirname, 'dist'), path.join(bundleDir, 'dist'), { recursive: true });
88
+
89
+ // Get all dependencies from package.json
90
+ const modules = getAllDependencies();
91
+
92
+ console.log(` Bundling ${modules.length} dependencies...`);
93
+
94
+ const nodeModulesDir = path.join(bundleDir, 'node_modules');
95
+ fs.mkdirSync(nodeModulesDir, { recursive: true });
96
+
97
+ modules.forEach(mod => {
98
+ const src = path.join(__dirname, 'node_modules', mod);
99
+ const dest = path.join(nodeModulesDir, mod);
100
+ if (fs.existsSync(src)) {
101
+ // Ensure parent directory exists (for scoped packages like `@scope/pkg`)
102
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
103
+ fs.cpSync(src, dest, { recursive: true });
104
+ }
105
+ });
106
+
107
+ // Copy package.json
108
+ fs.copyFileSync(
109
+ path.join(__dirname, 'package.json'),
110
+ path.join(bundleDir, 'package.json')
111
+ );
112
+
113
+ return bundleDir;
114
+ }
115
+
116
+ /**
117
+ * Create launcher script for Unix (macOS/Linux)
118
+ */
119
+ function createUnixLauncher(bundleDir) {
120
+ const launcher = `#!/bin/bash
121
+ # ESP32Tool CLI - Self-contained launcher
122
+
123
+ # Get the directory where this script is located
124
+ DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
125
+
126
+ # Check for Node.js
127
+ if ! command -v node &> /dev/null; then
128
+ echo "Error: Node.js not found"
129
+ echo "Please install Node.js ${NODE_VERSION}+ from https://nodejs.org/"
130
+ exit 1
131
+ fi
132
+
133
+ # Check Node.js version
134
+ CURRENT_NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
135
+ if [ "$CURRENT_NODE_VERSION" -lt ${NODE_VERSION} ]; then
136
+ echo "Error: Node.js ${NODE_VERSION}+ required (found: $(node -v))"
137
+ echo "Please upgrade Node.js from https://nodejs.org/"
138
+ exit 1
139
+ fi
140
+
141
+ # Run CLI
142
+ cd "$DIR"
143
+ exec node dist/cli-fixed.js "$@"
144
+ `;
145
+
146
+ fs.writeFileSync(path.join(bundleDir, 'esp32tool'), launcher);
147
+ fs.chmodSync(path.join(bundleDir, 'esp32tool'), 0o755);
148
+ }
149
+
150
+ /**
151
+ * Create launcher script for Windows
152
+ */
153
+ function createWindowsLauncher(bundleDir) {
154
+ const launcher = `@echo off
155
+ REM ESP32Tool CLI - Self-contained launcher
156
+
157
+ REM Get the directory where this script is located
158
+ set DIR=%~dp0
159
+
160
+ REM Check for Node.js
161
+ where node >nul 2>nul
162
+ if %ERRORLEVEL% NEQ 0 (
163
+ echo Error: Node.js not found
164
+ echo Please install Node.js ${NODE_VERSION}+ from https://nodejs.org/
165
+ exit /b 1
166
+ )
167
+
168
+ REM Check Node.js version
169
+ for /f "tokens=2 delims=v." %%a in ('node -v') do (
170
+ set NODE_MAJOR=%%a
171
+ goto :check_version
172
+ )
173
+ :check_version
174
+ if %NODE_MAJOR% LSS ${NODE_VERSION} (
175
+ echo Error: Node.js ${NODE_VERSION}+ required
176
+ echo Please upgrade Node.js from https://nodejs.org/
177
+ exit /b 1
178
+ )
179
+
180
+ REM Run CLI
181
+ cd /d "%DIR%"
182
+ node dist\\cli-fixed.js %*
183
+ `;
184
+
185
+ fs.writeFileSync(path.join(bundleDir, 'esp32tool.bat'), launcher);
186
+ }
187
+
188
+ /**
189
+ * Create self-extracting archive for Unix using makeself
190
+ */
191
+ function createUnixBinary(bundleDir, platform) {
192
+ console.log(`3. Creating ${platform} binary...`);
193
+
194
+ const outputFile = path.join(binariesDir, `esp32tool-${platform}`);
195
+
196
+ try {
197
+ // Check if makeself is available
198
+ try {
199
+ execSync('which makeself', { stdio: 'pipe' });
200
+ } catch {
201
+ console.error(` āœ— Skipped: makeself not installed (install with: brew install makeself / apt install makeself)`);
202
+ return;
203
+ }
204
+
205
+ // Create makeself archive with .run extension
206
+ const runFile = `${outputFile}.run`;
207
+ execSync(
208
+ `makeself --notemp "${bundleDir}" "${runFile}" "ESP32Tool CLI v${VERSION}" ./esp32tool`,
209
+ { stdio: 'inherit' }
210
+ );
211
+
212
+ // Create wrapper script that adds -- automatically
213
+ const runFileName = path.basename(runFile);
214
+ const wrapper = `#!/bin/bash
215
+ # ESP32Tool CLI Wrapper
216
+
217
+ SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
218
+ exec "$SCRIPT_DIR/${runFileName}" -- "$@"
219
+ `;
220
+
221
+ fs.writeFileSync(outputFile, wrapper);
222
+ fs.chmodSync(outputFile, 0o755);
223
+
224
+ console.log(` āœ“ Created: ${outputFile}`);
225
+ } catch (err) {
226
+ console.error(` āœ— Failed: ${err.message}`);
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Create ZIP archive for Windows
232
+ */
233
+ function createWindowsBinary(bundleDir) {
234
+ console.log('3. Creating Windows binary...');
235
+
236
+ const outputFile = path.join(binariesDir, `esp32tool-win-x64.zip`);
237
+
238
+ return new Promise((resolve, reject) => {
239
+ const output = fs.createWriteStream(outputFile);
240
+ const archive = archiver('zip', { zlib: { level: 9 } });
241
+
242
+ output.on('close', () => {
243
+ console.log(` āœ“ Created: ${outputFile}`);
244
+ resolve();
245
+ });
246
+
247
+ output.on('error', reject);
248
+ archive.on('error', reject);
249
+ archive.pipe(output);
250
+ archive.directory(bundleDir, false);
251
+ archive.finalize();
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Main build process
257
+ */
258
+ async function main() {
259
+ try {
260
+ // Create bundle
261
+ const bundleDir = createBundle();
262
+
263
+ // Create launchers
264
+ createUnixLauncher(bundleDir);
265
+ createWindowsLauncher(bundleDir);
266
+
267
+ // Create binaries for each platform
268
+ createUnixBinary(bundleDir, 'macos');
269
+ createUnixBinary(bundleDir, 'linux-x64');
270
+ await createWindowsBinary(bundleDir);
271
+
272
+ // Clean up
273
+ fs.rmSync(bundleDir, { recursive: true });
274
+
275
+ console.log('\nāœ“ All binaries created!\n');
276
+ console.log('Files in ./binaries/:');
277
+ fs.readdirSync(binariesDir).forEach(file => {
278
+ const stats = fs.statSync(path.join(binariesDir, file));
279
+ const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
280
+ console.log(` - ${file} (${sizeMB} MB)`);
281
+ });
282
+
283
+ console.log('\nUsage:');
284
+ console.log(' macOS: ./binaries/esp32tool-macos list-ports');
285
+ console.log(' Linux: ./binaries/esp32tool-linux-x64 list-ports');
286
+ console.log(' Windows: Extract zip, then: esp32tool.bat list-ports');
287
+ console.log(`\nNote: Requires Node.js ${NODE_VERSION}+ on target system`);
288
+
289
+ } catch (error) {
290
+ console.error('\nError:', error.message);
291
+ process.exit(1);
292
+ }
293
+ }
294
+
295
+ main();
package/css/light.css CHANGED
@@ -154,3 +154,14 @@ button {
154
154
  .littlefs-fs-button:hover {
155
155
  background-color: #71ae1e;
156
156
  }
157
+
158
+ /* ESP8266 Info Box - Light Mode */
159
+ .esp8266-info .info-box {
160
+ background-color: #f8f9fa;
161
+ border-color: #00a7e9;
162
+ color: #333;
163
+ }
164
+
165
+ .esp8266-info .info-box strong {
166
+ color: #00a7e9;
167
+ }