@bobfrankston/msger 0.1.129 → 0.1.131

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 (45) hide show
  1. package/cruft/clean.d.ts +3 -0
  2. package/cruft/clean.d.ts.map +1 -0
  3. package/cruft/clean.js +71 -0
  4. package/cruft/clean.js.map +1 -0
  5. package/cruft/postinstall.ts +107 -0
  6. package/docs/README.md +26 -0
  7. package/msger-native/builder/README.md +69 -0
  8. package/msger-native/builder/build-config.json +3 -1
  9. package/msger-native/builder/build-under-wsl.ts +210 -0
  10. package/msger-native/builder/builder.ts +289 -73
  11. package/msger-native/builder/clean.ts +86 -0
  12. package/msger-native/builder/postinstall.js +107 -0
  13. package/msger-native/package.json +1 -4
  14. package/msger-native/pibuild/README.md +42 -0
  15. package/package.json +5 -10
  16. /package/{msger-native → cruft}/apply-zoom-fix.js +0 -0
  17. /package/{msger-native → cruft}/build-arm64.ts +0 -0
  18. /package/{msger-native → cruft}/build-pi.ts +0 -0
  19. /package/{msger-native → cruft}/build-pi.ts.backup +0 -0
  20. /package/{msger-native → cruft}/build-pi.ts.old +0 -0
  21. /package/{msger-native → cruft}/build-wsl.ts +0 -0
  22. /package/{msger-native → cruft}/build.js +0 -0
  23. /package/{msger-native → cruft}/build.ts +0 -0
  24. /package/{msgernative-linux-x64 → cruft/msgernative-linux-x64} +0 -0
  25. /package/{msgernative-win32-x64.exe → cruft/msgernative-win32-x64.exe} +0 -0
  26. /package/{postinstall.js → cruft/postinstall.js} +0 -0
  27. /package/{test-size.d.ts → cruft/test-size.d.ts} +0 -0
  28. /package/{CHANGELOG.md → docs/CHANGELOG.md} +0 -0
  29. /package/{CLOSE-API.md → docs/CLOSE-API.md} +0 -0
  30. /package/{DEVELOPERS.md → docs/DEVELOPERS.md} +0 -0
  31. /package/{FULLSCREEN-FEATURE.md → docs/FULLSCREEN-FEATURE.md} +0 -0
  32. /package/{IMPLEMENTATION-SUMMARY.md → docs/IMPLEMENTATION-SUMMARY.md} +0 -0
  33. /package/{KNOWN-BUGS.md → docs/KNOWN-BUGS.md} +0 -0
  34. /package/{MSGER-API-SUMMARY.md → docs/MSGER-API-SUMMARY.md} +0 -0
  35. /package/{MSGER-API.md → docs/MSGER-API.md} +0 -0
  36. /package/{PI-RENDERING-NOTES.md → docs/PI-RENDERING-NOTES.md} +0 -0
  37. /package/{RELEASE-NOTES.md → docs/RELEASE-NOTES.md} +0 -0
  38. /package/{TODO.md → docs/TODO.md} +0 -0
  39. /package/{SESSION-2025-11-06.md → docs/sessions/SESSION-2025-11-06.md} +0 -0
  40. /package/{SESSION-NOTES.md → docs/sessions/SESSION-NOTES.md} +0 -0
  41. /package/{SESSION-RESUME-NOTES.md → docs/sessions/SESSION-RESUME-NOTES.md} +0 -0
  42. /package/msger-native/{build-on-pi.sh → pibuild/build-on-pi.sh} +0 -0
  43. /package/msger-native/{build-pi.ps1 → pibuild/build-pi.ps1} +0 -0
  44. /package/msger-native/{pi-diagnostics.ts → pibuild/pi-diagnostics.ts} +0 -0
  45. /package/msger-native/{setup-arm64-toolchain.sh → pibuild/setup-arm64-toolchain.sh} +0 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=clean.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["clean.js"],"names":[],"mappings":""}
package/cruft/clean.js ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cross-platform clean script
4
+ * Removes build artifacts
5
+ */
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { execSync } from 'child_process';
9
+ const rootDir = process.cwd();
10
+ console.log('🧹 Cleaning build artifacts...\n');
11
+ // Files to delete in root directory
12
+ const rootPatterns = [
13
+ '*.js',
14
+ '*.d.ts',
15
+ '*.d.ts.map',
16
+ '*.js.map'
17
+ ];
18
+ // Directories to exclude
19
+ const excludeDirs = ['node_modules', '.git', 'msger-native'];
20
+ function deleteFile(filePath) {
21
+ try {
22
+ fs.unlinkSync(filePath);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ function matchesPattern(filename, pattern) {
30
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*').replace(/\./g, '\\.') + '$');
31
+ return regex.test(filename);
32
+ }
33
+ // Clean root directory
34
+ let deletedCount = 0;
35
+ const files = fs.readdirSync(rootDir);
36
+ for (const file of files) {
37
+ const filePath = path.join(rootDir, file);
38
+ const stat = fs.statSync(filePath);
39
+ if (stat.isDirectory())
40
+ continue;
41
+ for (const pattern of rootPatterns) {
42
+ if (matchesPattern(file, pattern)) {
43
+ if (deleteFile(filePath)) {
44
+ console.log(` ✓ Deleted: ${file}`);
45
+ deletedCount++;
46
+ }
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ console.log(`\n📁 Cleaned ${deletedCount} files from root directory`);
52
+ // Clean Rust build artifacts
53
+ console.log('\n🦀 Cleaning Rust build artifacts...');
54
+ const nativeDir = path.join(rootDir, 'msger-native');
55
+ if (fs.existsSync(nativeDir)) {
56
+ try {
57
+ execSync('cargo clean', {
58
+ cwd: nativeDir,
59
+ stdio: 'inherit'
60
+ });
61
+ console.log(' ✓ Rust artifacts cleaned');
62
+ }
63
+ catch (error) {
64
+ console.error(' ✗ Failed to run cargo clean');
65
+ }
66
+ }
67
+ else {
68
+ console.log(' ⚠️ msger-native directory not found');
69
+ }
70
+ console.log('\n✨ Clean complete!\n');
71
+ //# sourceMappingURL=clean.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean.js","sourceRoot":"","sources":["clean.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;AAE9B,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAEhD,oCAAoC;AACpC,MAAM,YAAY,GAAG;IACjB,MAAM;IACN,QAAQ;IACR,YAAY;IACZ,UAAU;CACb,CAAC;AAEF,yBAAyB;AACzB,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;AAE7D,SAAS,UAAU,CAAC,QAAgB;IAChC,IAAI,CAAC;QACD,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB,EAAE,OAAe;IACrD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;IACzF,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,uBAAuB;AACvB,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAEtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,WAAW,EAAE;QAAE,SAAS;IAEjC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACjC,IAAI,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YAChC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;gBACpC,YAAY,EAAE,CAAC;YACnB,CAAC;YACD,MAAM;QACV,CAAC;IACL,CAAC;AACL,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,4BAA4B,CAAC,CAAC;AAEtE,6BAA6B;AAC7B,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;AACrD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAErD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAC3B,IAAI,CAAC;QACD,QAAQ,CAAC,aAAa,EAAE;YACpB,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,SAAS;SACnB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;AACL,CAAC;KAAM,CAAC;IACJ,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;AAC1D,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Post-install script to set executable permissions on Linux binaries
4
+ * and check for required system dependencies
5
+ */
6
+
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ import { execSync } from 'child_process';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ function detectDistro(): string {
16
+ if (!fs.existsSync('/etc/os-release')) {
17
+ return 'unknown';
18
+ }
19
+
20
+ try {
21
+ const osRelease = fs.readFileSync('/etc/os-release', 'utf8').toLowerCase();
22
+
23
+ if (osRelease.includes('ubuntu') || osRelease.includes('debian')) {
24
+ return 'debian';
25
+ }
26
+ if (osRelease.includes('fedora') || osRelease.includes('rhel') || osRelease.includes('centos')) {
27
+ return 'fedora';
28
+ }
29
+ if (osRelease.includes('arch')) {
30
+ return 'arch';
31
+ }
32
+
33
+ return 'unknown';
34
+ } catch {
35
+ return 'unknown';
36
+ }
37
+ }
38
+
39
+ function showDependencyInstallCommand(distro: string): void {
40
+ console.warn('\n⚠️ Missing system dependencies detected!');
41
+ console.warn(' Install required libraries with:\n');
42
+
43
+ switch (distro) {
44
+ case 'debian':
45
+ console.warn(' sudo apt update');
46
+ console.warn(' sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0\n');
47
+ break;
48
+ case 'fedora':
49
+ console.warn(' sudo dnf install webkit2gtk4.1 gtk3\n');
50
+ break;
51
+ case 'arch':
52
+ console.warn(' sudo pacman -S webkit2gtk gtk3\n');
53
+ break;
54
+ default:
55
+ console.warn(' Install webkit2gtk and gtk3 for your distribution\n');
56
+ }
57
+ }
58
+
59
+ function checkSystemDependencies(binaryPath: string): void {
60
+ try {
61
+ const lddOutput = execSync(`ldd "${binaryPath}" 2>&1`, { encoding: 'utf8' });
62
+
63
+ if (lddOutput.includes('not found')) {
64
+ const distro = detectDistro();
65
+ showDependencyInstallCommand(distro);
66
+ }
67
+ } catch {
68
+ // ldd command failed or not installed - skip check
69
+ }
70
+ }
71
+
72
+ function setExecutePermissions(binaryPath: string, binaryName: string): void {
73
+ try {
74
+ fs.chmodSync(binaryPath, 0o755);
75
+ console.log(`✅ Set execute permissions on ${binaryName} binary`);
76
+ } catch (error: any) {
77
+ console.warn(`⚠️ Could not set execute permission on ${binaryPath}: ${error.message}`);
78
+ console.warn(` You may need to run: sudo chmod +x ${binaryPath}`);
79
+ }
80
+ }
81
+
82
+ function main(): void {
83
+ // Windows doesn't need executable permissions
84
+ if (process.platform === 'win32') {
85
+ return;
86
+ }
87
+
88
+ // Determine binary name based on architecture
89
+ const arch = process.arch;
90
+ const binaryName = arch === 'arm64' ? 'msgernative-linux-aarch64' : 'msgernative';
91
+ const binaryPath = path.join(__dirname, '..', 'bin', binaryName);
92
+
93
+ // Binary doesn't exist - warn user
94
+ if (!fs.existsSync(binaryPath)) {
95
+ console.warn(`⚠️ Binary not found at ${binaryPath}`);
96
+ console.warn(` The msger package may not support your platform (${process.platform} ${arch})`);
97
+ return;
98
+ }
99
+
100
+ // Set executable permissions
101
+ setExecutePermissions(binaryPath, binaryName);
102
+
103
+ // Check for required system libraries
104
+ checkSystemDependencies(binaryPath);
105
+ }
106
+
107
+ main();
package/docs/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # msger Documentation
2
+
3
+ ## User Documentation
4
+ - [README.md](../README.md) - Main project README (in root)
5
+ - [MSGER-API.md](MSGER-API.md) - JavaScript API for message box content
6
+ - [MSGER-API-SUMMARY.md](MSGER-API-SUMMARY.md) - Quick API reference
7
+ - [CLOSE-API.md](CLOSE-API.md) - Programmatic close API
8
+
9
+ ## Release Information
10
+ - [CHANGELOG.md](CHANGELOG.md) - Version history and changes
11
+ - [RELEASE-NOTES.md](RELEASE-NOTES.md) - User-facing release notes
12
+ - [KNOWN-BUGS.md](KNOWN-BUGS.md) - Known issues and limitations
13
+
14
+ ## Features
15
+ - [DETACH-FEATURE.md](DETACH-FEATURE.md) - Detached window mode
16
+ - [FULLSCREEN-FEATURE.md](FULLSCREEN-FEATURE.md) - Fullscreen mode
17
+ - [MOUSE-ZOOM-FEATURE.md](MOUSE-ZOOM-FEATURE.md) - Mouse wheel zoom
18
+
19
+ ## Developer Documentation
20
+ - [DEVELOPERS.md](DEVELOPERS.md) - Developer guide
21
+ - [IMPLEMENTATION-SUMMARY.md](IMPLEMENTATION-SUMMARY.md) - Implementation details
22
+ - [PI-RENDERING-NOTES.md](PI-RENDERING-NOTES.md) - Raspberry Pi specific notes
23
+ - [TODO.md](TODO.md) - Future plans and tasks
24
+
25
+ ## Session Notes
26
+ Development session notes are in [sessions/](sessions/)
@@ -0,0 +1,69 @@
1
+ # msger-native Builder
2
+
3
+ Unified build system for msger-native that uses JSON configuration to control which platforms to build.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ cd msger-native
9
+ npm run build
10
+ ```
11
+
12
+ ## Configuration
13
+
14
+ Edit `builder/build-config.json` to control which platforms are built:
15
+
16
+ ```json
17
+ {
18
+ "platforms": {
19
+ "windows": true, // Build Windows x64 binary
20
+ "wsl": false, // Build Linux x64 binary (via WSL)
21
+ "pi": false, // Build Raspberry Pi ARM64 binary (remote build on Pi)
22
+ "arm64": false // Build Linux ARM64 binary (cross-compile via WSL)
23
+ },
24
+ "options": {
25
+ "release": true, // Use release mode (optimized)
26
+ "verbose": false, // Show detailed cargo output
27
+ "piHost": "pi4c", // Raspberry Pi hostname for SSH
28
+ "piProjectPath": "/home/pi/dev/msger/msger-native" // Project path on Pi
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Build Targets
34
+
35
+ | Platform | Output | Method | Requirements |
36
+ |----------|--------|--------|--------------|
37
+ | `windows` | `bin/msgernative.exe` | Native build on Windows | Windows, Visual Studio Build Tools |
38
+ | `wsl` | `bin/msgernative` | Native build in WSL | WSL with Rust toolchain |
39
+ | `pi` | `bin/msgernative-linux-aarch64` | **Remote build on Pi** (slower, guaranteed compatible) | SSH access to Raspberry Pi |
40
+ | `arm64` | `bin/msgernative-linux-aarch64` | **Cross-compile on WSL** (faster, requires setup) | WSL with ARM64 cross-compilation toolchain |
41
+
42
+ **Pi vs ARM64:**
43
+ - **`pi`**: Builds on the actual Raspberry Pi via SSH - slower but guaranteed to work
44
+ - **`arm64`**: Cross-compiles locally using WSL - faster but requires cross-toolchain setup
45
+
46
+ ## Features
47
+
48
+ - **JSON-driven configuration**: Simply edit JSON file to enable/disable platforms
49
+ - **Build summary**: Shows which builds succeeded/failed
50
+ - **Size reporting**: Displays binary size for each platform
51
+ - **TypeScript**: Uses Node's native TypeScript support (no compilation needed)
52
+ - **Conservative defaults**: Only builds Windows by default
53
+
54
+ ## Legacy Scripts
55
+
56
+ The old individual build scripts are still available:
57
+ - `npm run build:legacy` - Original Windows build script
58
+ - `npm run build:wsl` - WSL Linux build
59
+ - `npm run build:pi` - Raspberry Pi build
60
+ - `npm run build:arm64` - ARM64 cross-compile
61
+
62
+ ## Future Enhancements
63
+
64
+ Potential additions:
65
+ - Custom Cargo features/flags configuration
66
+ - Parallel builds
67
+ - Post-build verification/testing
68
+ - Binary signing/notarization
69
+ - Deployment automation
@@ -7,6 +7,8 @@
7
7
  },
8
8
  "options": {
9
9
  "release": true,
10
- "verbose": false
10
+ "verbose": false,
11
+ "piHost": "pi4c",
12
+ "piProjectPath": "/home/pi/dev/msger/msger-native"
11
13
  }
12
14
  }
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Build script to run natively inside WSL
4
+ * Handles both x64 and ARM64 builds
5
+ * Reads configuration from build-config.json
6
+ *
7
+ * Usage from WSL:
8
+ * node builder/build-under-wsl.ts
9
+ */
10
+
11
+ import { execSync } from 'child_process';
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+
19
+ interface BuildConfig {
20
+ platforms: {
21
+ windows?: boolean;
22
+ wsl?: boolean;
23
+ pi?: boolean;
24
+ arm64?: boolean;
25
+ };
26
+ options?: {
27
+ release?: boolean;
28
+ verbose?: boolean;
29
+ piHost?: string;
30
+ piProjectPath?: string;
31
+ };
32
+ }
33
+
34
+ function timestamp(): string {
35
+ const now = new Date();
36
+ return now.toTimeString().split(' ')[0];
37
+ }
38
+
39
+ interface BuildTarget {
40
+ name: string;
41
+ rustTarget: string;
42
+ outputName: string;
43
+ description: string;
44
+ }
45
+
46
+ const targets: Record<string, BuildTarget> = {
47
+ x64: {
48
+ name: 'x64',
49
+ rustTarget: 'x86_64-unknown-linux-gnu',
50
+ outputName: 'msgernative',
51
+ description: 'Linux x64'
52
+ },
53
+ arm64: {
54
+ name: 'arm64',
55
+ rustTarget: 'aarch64-unknown-linux-gnu',
56
+ outputName: 'msgernative-linux-aarch64',
57
+ description: 'Linux ARM64'
58
+ }
59
+ };
60
+
61
+ function checkToolchain(target: BuildTarget): boolean {
62
+ try {
63
+ const installed = execSync('rustup target list --installed', { encoding: 'utf-8' });
64
+ return installed.includes(target.rustTarget);
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ function installToolchain(target: BuildTarget): boolean {
71
+ console.log(` [${timestamp()}] 📦 Installing ${target.description} toolchain...`);
72
+
73
+ try {
74
+ // Add Rust target
75
+ execSync(`rustup target add ${target.rustTarget}`, { stdio: 'inherit' });
76
+
77
+ // For ARM64, also install cross-compiler
78
+ if (target.name === 'arm64') {
79
+ console.log(` [${timestamp()}] 📦 Installing ARM64 cross-compiler...`);
80
+ execSync('sudo apt update && sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross', {
81
+ stdio: 'inherit'
82
+ });
83
+ }
84
+
85
+ console.log(` [${timestamp()}] ✅ Toolchain installed`);
86
+ return true;
87
+ } catch (error: any) {
88
+ console.error(` [${timestamp()}] ❌ Failed to install toolchain: ${error.message}`);
89
+ return false;
90
+ }
91
+ }
92
+
93
+ function build(target: BuildTarget, verbose: boolean): boolean {
94
+ console.log(`\n[${timestamp()}] 📦 Building ${target.description} binary...`);
95
+
96
+ // Check toolchain
97
+ if (!checkToolchain(target)) {
98
+ console.log(` [${timestamp()}] ⚙️ ${target.description} toolchain not found`);
99
+ if (!installToolchain(target)) {
100
+ return false;
101
+ }
102
+ }
103
+
104
+ const nativeDir = path.join(__dirname, '..');
105
+ const binDir = path.join(nativeDir, 'bin');
106
+ const binaryPath = path.join(binDir, target.outputName);
107
+
108
+ try {
109
+ console.log(` [${timestamp()}] 🔨 Compiling with cargo...`);
110
+ execSync(`cargo build --release --target ${target.rustTarget}`, {
111
+ cwd: nativeDir,
112
+ stdio: verbose ? 'inherit' : 'pipe'
113
+ });
114
+
115
+ // Copy to bin directory
116
+ if (!fs.existsSync(binDir)) {
117
+ fs.mkdirSync(binDir, { recursive: true });
118
+ }
119
+
120
+ const sourcePath = path.join(nativeDir, 'target', target.rustTarget, 'release', 'msgernative');
121
+ fs.copyFileSync(sourcePath, binaryPath);
122
+ fs.chmodSync(binaryPath, 0o755);
123
+
124
+ const stats = fs.statSync(binaryPath);
125
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
126
+ console.log(` [${timestamp()}] ✅ ${target.description} binary completed`);
127
+ console.log(` [${timestamp()}] 📊 Binary size: ${sizeMB} MB`);
128
+ console.log(` [${timestamp()}] 📁 Output: ${binaryPath}`);
129
+ return true;
130
+ } catch (error: any) {
131
+ console.error(` [${timestamp()}] ❌ Build failed: ${error.message}`);
132
+ return false;
133
+ }
134
+ }
135
+
136
+ function loadConfig(): BuildConfig {
137
+ const configPath = path.join(__dirname, 'build-config.json');
138
+
139
+ if (!fs.existsSync(configPath)) {
140
+ console.error('❌ build-config.json not found');
141
+ process.exit(1);
142
+ }
143
+
144
+ try {
145
+ const content = fs.readFileSync(configPath, 'utf-8');
146
+ return JSON.parse(content);
147
+ } catch (error: any) {
148
+ console.error(`❌ Failed to parse build-config.json: ${error.message}`);
149
+ process.exit(1);
150
+ }
151
+ }
152
+
153
+ function main() {
154
+ console.log('🚀 WSL Native Builder\n');
155
+
156
+ const config = loadConfig();
157
+ const verboseFlag = config.options?.verbose ?? false;
158
+
159
+ // Determine which targets to build based on config
160
+ const requestedTargets: string[] = [];
161
+ if (config.platforms.wsl) requestedTargets.push('x64');
162
+ if (config.platforms.arm64) requestedTargets.push('arm64');
163
+
164
+ if (requestedTargets.length === 0) {
165
+ console.log('⚠️ No WSL platforms enabled in build-config.json');
166
+ console.log(' Enable "wsl" for x64 or "arm64" for ARM64 builds');
167
+ process.exit(0);
168
+ }
169
+
170
+ console.log(`📋 Configuration:`);
171
+ console.log(` Mode: ${config.options?.release ? 'release' : 'debug'}`);
172
+ console.log(` Targets: ${requestedTargets.join(', ')}`);
173
+ console.log(` Verbose: ${verboseFlag}\n`);
174
+
175
+ const results: { target: string; success: boolean }[] = [];
176
+
177
+ for (const targetName of requestedTargets) {
178
+ const target = targets[targetName];
179
+ if (!target) {
180
+ console.error(`❌ Unknown target: ${targetName}`);
181
+ console.error(` Available targets: x64, arm64, all`);
182
+ process.exit(1);
183
+ }
184
+
185
+ const success = build(target, verboseFlag);
186
+ results.push({ target: targetName, success });
187
+ }
188
+
189
+ // Summary
190
+ console.log('\n' + '='.repeat(50));
191
+ console.log('📊 Build Summary:');
192
+ console.log('='.repeat(50));
193
+
194
+ for (const result of results) {
195
+ const status = result.success ? '✅' : '❌';
196
+ console.log(`${status} ${result.target}`);
197
+ }
198
+
199
+ const successCount = results.filter(r => r.success).length;
200
+ const totalCount = results.length;
201
+
202
+ console.log('='.repeat(50));
203
+ console.log(`\n🎉 Completed: ${successCount}/${totalCount} builds successful\n`);
204
+
205
+ if (successCount < totalCount) {
206
+ process.exit(1);
207
+ }
208
+ }
209
+
210
+ main();