@bobfrankston/msger 0.1.22 โ†’ 0.1.23

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/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface MessageBoxOptions {
9
9
  defaultValue?: string;
10
10
  allowInput?: boolean;
11
11
  timeout?: number;
12
+ detach?: boolean;
12
13
  }
13
14
  export interface MessageBoxResult {
14
15
  button: string;
package/index.js CHANGED
@@ -10,8 +10,18 @@ import fs from 'fs';
10
10
  export async function showMessageBox(options) {
11
11
  return new Promise((resolve, reject) => {
12
12
  const isWindows = platform() === 'win32';
13
- // Determine the binary name based on platform
14
- const binaryName = isWindows ? 'msgernative.exe' : 'msgernative';
13
+ const arch = process.arch;
14
+ // Determine the binary name based on platform and architecture
15
+ let binaryName;
16
+ if (isWindows) {
17
+ binaryName = 'msgernative.exe';
18
+ }
19
+ else if (arch === 'arm64') {
20
+ binaryName = 'msgernative-arm64';
21
+ }
22
+ else {
23
+ binaryName = 'msgernative';
24
+ }
15
25
  const binaryPath = path.join(import.meta.dirname, 'msger-native', 'bin', binaryName);
16
26
  // Check if binary exists
17
27
  if (!fs.existsSync(binaryPath)) {
@@ -31,8 +41,13 @@ export async function showMessageBox(options) {
31
41
  }
32
42
  // Spawn the Rust binary
33
43
  const child = spawn(binaryPath, [], {
34
- stdio: ['pipe', 'pipe', 'pipe']
44
+ stdio: ['pipe', 'pipe', 'pipe'],
45
+ detached: options.detach || false
35
46
  });
47
+ // If detached, unref the child so parent can exit
48
+ if (options.detach) {
49
+ child.unref();
50
+ }
36
51
  let stdout = '';
37
52
  let stderr = '';
38
53
  // Collect stdout
@@ -70,6 +85,10 @@ export async function showMessageBox(options) {
70
85
  try {
71
86
  child.stdin.write(JSON.stringify(options));
72
87
  child.stdin.end();
88
+ // If detached, resolve immediately after sending options
89
+ if (options.detach) {
90
+ resolve({ button: 'detached', dismissed: false });
91
+ }
73
92
  }
74
93
  catch (error) {
75
94
  reject(new Error(`Failed to write to stdin: ${error.message}`));
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAyBpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA0B;IAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,SAAS,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAE1B,+DAA+D;QAC/D,IAAI,UAAkB,CAAC;QACvB,IAAI,SAAS,EAAE,CAAC;YACZ,UAAU,GAAG,iBAAiB,CAAC;QACnC,CAAC;aAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,UAAU,GAAG,mBAAmB,CAAC;QACrC,CAAC;aAAM,CAAC;YACJ,UAAU,GAAG,aAAa,CAAC;QAC/B,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QAErF,yBAAyB;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAC,CAAC;YACrD,OAAO;QACX,CAAC;QAED,iDAAiD;QACjD,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,IAAI,CAAC;gBACD,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,KAAK,CACZ,6BAA6B,UAAU,IAAI;oBAC3C,6BAA6B,UAAU,EAAE,CAC5C,CAAC,CAAC;gBACH,OAAO;YACX,CAAC;QACL,CAAC;QAED,wBAAwB;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE;YAChC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,QAAQ,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;SACpC,CAAC,CAAC;QAEH,kDAAkD;QAClD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,iBAAiB;QACjB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC7B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,iBAAiB;QACjB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC7B,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,4BAA4B;QAC5B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACvB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACb,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC/D,OAAO;YACX,CAAC;YAED,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAqB,CAAC;gBAC7D,OAAO,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,KAAK,CAAC,OAAO,aAAa,MAAM,EAAE,CAAC,CAAC,CAAC;YACrF,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,wBAAwB;QACxB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACxB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,0DAA0D;QAC1D,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAU,EAAE,EAAE;YACnC,kEAAkE;YAClE,uCAAuC;QAC3C,CAAC,CAAC,CAAC;QAEH,wBAAwB;QACxB,IAAI,CAAC;YACD,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAElB,yDAAyD;YACzD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,6CAA6C;AAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,OAAO,EAAE,CAAC;AACpB,CAAC"}
package/index.ts CHANGED
@@ -1,118 +1,139 @@
1
- import { spawn } from 'child_process';
2
- import { platform } from 'os';
3
- import path from 'path';
4
- import fs from 'fs';
5
-
6
- export interface MessageBoxOptions {
7
- title?: string;
8
- message: string;
9
- html?: string;
10
- url?: string;
11
- width?: number;
12
- height?: number;
13
- buttons?: string[];
14
- defaultValue?: string;
15
- allowInput?: boolean;
16
- timeout?: number;
17
- }
18
-
19
- export interface MessageBoxResult {
20
- button: string;
21
- value?: string;
22
- form?: Record<string, any>;
23
- closed?: boolean;
24
- dismissed?: boolean;
25
- timeout?: boolean;
26
- }
27
-
28
- /**
29
- * Show a message box dialog using native Rust implementation
30
- * @param options Message box configuration
31
- * @returns Promise that resolves with user's response
32
- */
33
- export async function showMessageBox(options: MessageBoxOptions): Promise<MessageBoxResult> {
34
- return new Promise((resolve, reject) => {
35
- const isWindows = platform() === 'win32';
36
-
37
- // Determine the binary name based on platform
38
- const binaryName = isWindows ? 'msgernative.exe' : 'msgernative';
39
- const binaryPath = path.join(import.meta.dirname, 'msger-native', 'bin', binaryName);
40
-
41
- // Check if binary exists
42
- if (!fs.existsSync(binaryPath)) {
43
- reject(new Error(`Binary not found: ${binaryPath}`));
44
- return;
45
- }
46
-
47
- // On Unix systems, check if binary is executable
48
- if (!isWindows) {
49
- try {
50
- fs.accessSync(binaryPath, fs.constants.X_OK);
51
- } catch (error) {
52
- reject(new Error(
53
- `Binary is not executable: ${binaryPath}\n` +
54
- `Please run: sudo chmod +x ${binaryPath}`
55
- ));
56
- return;
57
- }
58
- }
59
-
60
- // Spawn the Rust binary
61
- const child = spawn(binaryPath, [], {
62
- stdio: ['pipe', 'pipe', 'pipe']
63
- });
64
-
65
- let stdout = '';
66
- let stderr = '';
67
-
68
- // Collect stdout
69
- child.stdout.on('data', (data) => {
70
- stdout += data.toString();
71
- });
72
-
73
- // Collect stderr
74
- child.stderr.on('data', (data) => {
75
- stderr += data.toString();
76
- });
77
-
78
- // Handle process completion
79
- child.on('close', (code) => {
80
- if (code !== 0) {
81
- reject(new Error(`msger exited with code ${code}: ${stderr}`));
82
- return;
83
- }
84
-
85
- try {
86
- const result = JSON.parse(stdout.trim()) as MessageBoxResult;
87
- resolve(result);
88
- } catch (error: any) {
89
- reject(new Error(`Failed to parse result: ${error.message}\nOutput: ${stdout}`));
90
- }
91
- });
92
-
93
- // Handle process errors
94
- child.on('error', (error) => {
95
- reject(new Error(`Failed to spawn msger: ${error.message}`));
96
- });
97
-
98
- // Handle stdin errors (e.g., EPIPE when child dies early)
99
- child.stdin.on('error', (error: any) => {
100
- // Don't reject here - the 'close' or 'error' event will handle it
101
- // This prevents unhandled EPIPE errors
102
- });
103
-
104
- // Send options to stdin
105
- try {
106
- child.stdin.write(JSON.stringify(options));
107
- child.stdin.end();
108
- } catch (error: any) {
109
- reject(new Error(`Failed to write to stdin: ${error.message}`));
110
- }
111
- });
112
- }
113
-
114
- // If run directly (not imported), invoke CLI
115
- if (import.meta.main) {
116
- const { default: cliMain } = await import('./cli.js');
117
- await cliMain();
118
- }
1
+ import { spawn } from 'child_process';
2
+ import { platform } from 'os';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+
6
+ export interface MessageBoxOptions {
7
+ title?: string;
8
+ message: string;
9
+ html?: string;
10
+ url?: string;
11
+ width?: number;
12
+ height?: number;
13
+ buttons?: string[];
14
+ defaultValue?: string;
15
+ allowInput?: boolean;
16
+ timeout?: number;
17
+ detach?: boolean;
18
+ }
19
+
20
+ export interface MessageBoxResult {
21
+ button: string;
22
+ value?: string;
23
+ form?: Record<string, any>;
24
+ closed?: boolean;
25
+ dismissed?: boolean;
26
+ timeout?: boolean;
27
+ }
28
+
29
+ /**
30
+ * Show a message box dialog using native Rust implementation
31
+ * @param options Message box configuration
32
+ * @returns Promise that resolves with user's response
33
+ */
34
+ export async function showMessageBox(options: MessageBoxOptions): Promise<MessageBoxResult> {
35
+ return new Promise((resolve, reject) => {
36
+ const isWindows = platform() === 'win32';
37
+ const arch = process.arch;
38
+
39
+ // Determine the binary name based on platform and architecture
40
+ let binaryName: string;
41
+ if (isWindows) {
42
+ binaryName = 'msgernative.exe';
43
+ } else if (arch === 'arm64') {
44
+ binaryName = 'msgernative-arm64';
45
+ } else {
46
+ binaryName = 'msgernative';
47
+ }
48
+
49
+ const binaryPath = path.join(import.meta.dirname, 'msger-native', 'bin', binaryName);
50
+
51
+ // Check if binary exists
52
+ if (!fs.existsSync(binaryPath)) {
53
+ reject(new Error(`Binary not found: ${binaryPath}`));
54
+ return;
55
+ }
56
+
57
+ // On Unix systems, check if binary is executable
58
+ if (!isWindows) {
59
+ try {
60
+ fs.accessSync(binaryPath, fs.constants.X_OK);
61
+ } catch (error) {
62
+ reject(new Error(
63
+ `Binary is not executable: ${binaryPath}\n` +
64
+ `Please run: sudo chmod +x ${binaryPath}`
65
+ ));
66
+ return;
67
+ }
68
+ }
69
+
70
+ // Spawn the Rust binary
71
+ const child = spawn(binaryPath, [], {
72
+ stdio: ['pipe', 'pipe', 'pipe'],
73
+ detached: options.detach || false
74
+ });
75
+
76
+ // If detached, unref the child so parent can exit
77
+ if (options.detach) {
78
+ child.unref();
79
+ }
80
+
81
+ let stdout = '';
82
+ let stderr = '';
83
+
84
+ // Collect stdout
85
+ child.stdout.on('data', (data) => {
86
+ stdout += data.toString();
87
+ });
88
+
89
+ // Collect stderr
90
+ child.stderr.on('data', (data) => {
91
+ stderr += data.toString();
92
+ });
93
+
94
+ // Handle process completion
95
+ child.on('close', (code) => {
96
+ if (code !== 0) {
97
+ reject(new Error(`msger exited with code ${code}: ${stderr}`));
98
+ return;
99
+ }
100
+
101
+ try {
102
+ const result = JSON.parse(stdout.trim()) as MessageBoxResult;
103
+ resolve(result);
104
+ } catch (error: any) {
105
+ reject(new Error(`Failed to parse result: ${error.message}\nOutput: ${stdout}`));
106
+ }
107
+ });
108
+
109
+ // Handle process errors
110
+ child.on('error', (error) => {
111
+ reject(new Error(`Failed to spawn msger: ${error.message}`));
112
+ });
113
+
114
+ // Handle stdin errors (e.g., EPIPE when child dies early)
115
+ child.stdin.on('error', (error: any) => {
116
+ // Don't reject here - the 'close' or 'error' event will handle it
117
+ // This prevents unhandled EPIPE errors
118
+ });
119
+
120
+ // Send options to stdin
121
+ try {
122
+ child.stdin.write(JSON.stringify(options));
123
+ child.stdin.end();
124
+
125
+ // If detached, resolve immediately after sending options
126
+ if (options.detach) {
127
+ resolve({ button: 'detached', dismissed: false });
128
+ }
129
+ } catch (error: any) {
130
+ reject(new Error(`Failed to write to stdin: ${error.message}`));
131
+ }
132
+ });
133
+ }
134
+
135
+ // If run directly (not imported), invoke CLI
136
+ if (import.meta.main) {
137
+ const { default: cliMain } = await import('./cli.js');
138
+ await cliMain();
139
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ console.log('๐Ÿฆพ Building ARM64 binary via WSL...');
11
+
12
+ // Get the WSL path
13
+ const windowsPath = __dirname.replace(/\\/g, '/');
14
+ const driveLetter = windowsPath.charAt(0).toLowerCase();
15
+ const pathWithoutDrive = windowsPath.substring(2);
16
+ const wslPath = `/mnt/${driveLetter}${pathWithoutDrive}`;
17
+
18
+ console.log(`๐Ÿ“ WSL path: ${wslPath}`);
19
+
20
+ // Check for Rust in WSL
21
+ console.log('๐Ÿ” Checking for Rust/Cargo in WSL...');
22
+ try {
23
+ execSync('wsl bash -c "command -v cargo"', { stdio: 'pipe' });
24
+ console.log('โœ… Rust/Cargo found');
25
+ } catch {
26
+ console.log('โš ๏ธ Rust/Cargo not found in WSL, installing...');
27
+ execSync('wsl bash -c "curl --proto \'=https\' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"', { stdio: 'inherit' });
28
+ console.log('โœ… Rust installed successfully');
29
+ }
30
+
31
+ // Check for ARM64 target
32
+ console.log('๐Ÿ” Checking for ARM64 cross-compilation target...');
33
+ try {
34
+ const targets = execSync('wsl bash -c ". $HOME/.cargo/env && rustup target list --installed"', { encoding: 'utf8' });
35
+ if (!targets.includes('aarch64-unknown-linux-gnu')) {
36
+ console.log('๐Ÿ“ฆ Adding ARM64 target...');
37
+ execSync('wsl bash -c ". $HOME/.cargo/env && rustup target add aarch64-unknown-linux-gnu"', { stdio: 'inherit' });
38
+ console.log('โœ… ARM64 target added');
39
+ } else {
40
+ console.log('โœ… ARM64 target already installed');
41
+ }
42
+ } catch (error) {
43
+ console.log('๐Ÿ“ฆ Adding ARM64 target...');
44
+ execSync('wsl bash -c ". $HOME/.cargo/env && rustup target add aarch64-unknown-linux-gnu"', { stdio: 'inherit' });
45
+ console.log('โœ… ARM64 target added');
46
+ }
47
+
48
+ // Check for ARM64 cross-compiler
49
+ console.log('๐Ÿ” Checking for ARM64 cross-compiler...');
50
+ try {
51
+ execSync('wsl bash -c "command -v aarch64-linux-gnu-gcc"', { stdio: 'pipe' });
52
+ console.log('โœ… ARM64 cross-compiler found');
53
+ } catch {
54
+ console.log('๐Ÿ“ฆ Installing ARM64 cross-compiler...');
55
+ execSync('wsl bash -c "sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu"', { stdio: 'inherit' });
56
+ console.log('โœ… ARM64 cross-compiler installed');
57
+ }
58
+
59
+ // Check for build dependencies
60
+ console.log('๐Ÿ” Checking for build dependencies in WSL...');
61
+ try {
62
+ execSync('wsl bash -c "pkg-config --exists gtk+-3.0 webkit2gtk-4.1"', { stdio: 'pipe' });
63
+ console.log('โœ… Build dependencies found');
64
+ } catch {
65
+ console.log('โš ๏ธ Build dependencies not found, installing...');
66
+ execSync('wsl bash -c "sudo apt-get update && sudo apt-get install -y pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev libsoup-3.0-dev"', { stdio: 'inherit' });
67
+ console.log('โœ… Build dependencies installed');
68
+ }
69
+
70
+ // Build for ARM64
71
+ console.log('\n๐Ÿ“ฆ Building ARM64 binary...');
72
+ const buildCmd = `wsl bash -c "cd ${wslPath} && . $HOME/.cargo/env && export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc && PKG_CONFIG_ALLOW_CROSS=1 cargo build --release --target aarch64-unknown-linux-gnu"`;
73
+ execSync(buildCmd, { stdio: 'inherit' });
74
+ console.log('โœ… ARM64 build completed');
75
+
76
+ // Copy the binary
77
+ const sourcePath = path.join(__dirname, 'target', 'aarch64-unknown-linux-gnu', 'release', 'msgernative');
78
+ const destDir = path.join(__dirname, 'bin');
79
+ const destPath = path.join(destDir, 'msgernative-arm64');
80
+
81
+ if (!fs.existsSync(destDir)) {
82
+ fs.mkdirSync(destDir, { recursive: true });
83
+ }
84
+
85
+ fs.copyFileSync(sourcePath, destPath);
86
+ console.log(`โœ… Binary copied to: ${destPath}`);
87
+
88
+ const stats = fs.statSync(destPath);
89
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
90
+ console.log(`๐Ÿ“Š Binary size: ${sizeMB} MB`);
91
+
92
+ console.log('\n๐ŸŽ‰ ARM64 build process completed!');
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ // Configuration - UPDATE THESE VALUES
7
+ const PI_HOST = 'pi4c'; // or 'pi@raspberrypi.local' or 'pi@192.168.1.xxx'
8
+ const PI_BUILD_DIR = '/tmp/msger-native-build';
9
+
10
+ console.log('๐Ÿฆพ Building ARM64 binary via SSH to Raspberry Pi...');
11
+ console.log(`๐Ÿ“ Target: ${PI_HOST}`);
12
+
13
+ try {
14
+ // Test SSH connection
15
+ console.log('๐Ÿ” Testing SSH connection...');
16
+ execSync(`ssh ${PI_HOST} "echo Connected"`, { stdio: 'pipe' });
17
+ console.log('โœ… SSH connection successful');
18
+ } catch (error) {
19
+ console.error('โŒ Cannot connect to Pi via SSH');
20
+ console.error(' Make sure you can run: ssh ' + PI_HOST);
21
+ console.error(' You may need to set up SSH keys: ssh-copy-id ' + PI_HOST);
22
+ process.exit(1);
23
+ }
24
+
25
+ // Create build directory on Pi
26
+ console.log('๐Ÿ“ Creating build directory on Pi...');
27
+ execSync(`ssh ${PI_HOST} "mkdir -p ${PI_BUILD_DIR}/src"`, { stdio: 'inherit' });
28
+
29
+ // Copy source files to Pi
30
+ console.log('๐Ÿ“ค Copying source files to Pi...');
31
+ execSync(`scp Cargo.toml ${PI_HOST}:${PI_BUILD_DIR}/`, { stdio: 'inherit', cwd: import.meta.dirname });
32
+ execSync(`scp -r src/* ${PI_HOST}:${PI_BUILD_DIR}/src/`, { stdio: 'inherit', cwd: import.meta.dirname });
33
+
34
+ // Check for Rust on Pi
35
+ console.log('๐Ÿ” Checking for Rust/Cargo on Pi...');
36
+ try {
37
+ execSync(`ssh ${PI_HOST} "command -v cargo"`, { stdio: 'pipe' });
38
+ console.log('โœ… Rust/Cargo found');
39
+ } catch {
40
+ console.log('๐Ÿ“ฆ Installing Rust on Pi...');
41
+ execSync(`ssh ${PI_HOST} "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"`, { stdio: 'inherit' });
42
+ console.log('โœ… Rust installed successfully');
43
+ }
44
+
45
+ // Ensure pkg-config is installed first (required to check for other dependencies)
46
+ console.log('๐Ÿ”ง Ensuring pkg-config is installed on Pi...');
47
+ try {
48
+ execSync(`ssh ${PI_HOST} "command -v pkg-config"`, { stdio: 'pipe' });
49
+ console.log('โœ… pkg-config found');
50
+ } catch {
51
+ console.log('๐Ÿ“ฆ Installing pkg-config on Pi...');
52
+ execSync(`ssh ${PI_HOST} "sudo apt-get update && sudo apt-get install -y pkg-config"`, { stdio: 'inherit' });
53
+ console.log('โœ… pkg-config installed');
54
+ }
55
+
56
+ // Check for build dependencies on Pi
57
+ console.log('๐Ÿ” Checking for build dependencies on Pi...');
58
+ try {
59
+ execSync(`ssh ${PI_HOST} "pkg-config --exists gtk+-3.0 webkit2gtk-4.0"`, { stdio: 'pipe' });
60
+ console.log('โœ… Build dependencies found');
61
+ } catch {
62
+ console.log('๐Ÿ“ฆ Installing build dependencies on Pi...');
63
+ execSync(`ssh ${PI_HOST} "sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libsoup2.4-dev"`, { stdio: 'inherit' });
64
+ console.log('โœ… Build dependencies installed');
65
+ }
66
+
67
+ // Build on Pi
68
+ console.log('\n๐Ÿ“ฆ Building ARM64 binary on Pi...');
69
+ try {
70
+ execSync(`ssh ${PI_HOST} "cd ${PI_BUILD_DIR} && export PATH=~/.cargo/bin:\\$PATH && export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig && cargo build --release"`, { stdio: 'inherit' });
71
+ console.log('โœ… ARM64 build completed');
72
+ } catch (error: any) {
73
+ console.error('โŒ Build failed:');
74
+ console.error(error.stdout?.toString());
75
+ console.error(error.stderr?.toString());
76
+ throw error;
77
+ }
78
+
79
+ // Copy binary back
80
+ console.log('๐Ÿ“ฅ Copying binary back from Pi...');
81
+ const destDir = path.join(import.meta.dirname, 'bin');
82
+ if (!fs.existsSync(destDir)) {
83
+ fs.mkdirSync(destDir, { recursive: true });
84
+ }
85
+
86
+ const destPath = path.join(destDir, 'msgernative-arm64');
87
+ execSync(`scp ${PI_HOST}:${PI_BUILD_DIR}/target/release/msgernative ${destPath}`, { stdio: 'inherit' });
88
+
89
+ // Set execute permissions
90
+ fs.chmodSync(destPath, 0o755);
91
+
92
+ const stats = fs.statSync(destPath);
93
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
94
+ console.log(`โœ… Binary copied to: ${destPath}`);
95
+ console.log(`๐Ÿ“Š Binary size: ${sizeMB} MB`);
96
+
97
+ // Cleanup on Pi
98
+ console.log('๐Ÿงน Cleaning up on Pi...');
99
+ execSync(`ssh ${PI_HOST} "rm -rf ${PI_BUILD_DIR}"`, { stdio: 'inherit' });
100
+
101
+ console.log('\n๐ŸŽ‰ ARM64 build process completed!');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/msger",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Fast, lightweight, cross-platform message box - Rust-powered alternative to msgview",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -17,7 +17,9 @@
17
17
  "build": "npm run build:ts && npm run build:native",
18
18
  "build:native": "cd msger-native && npm run build",
19
19
  "build:native:wsl": "cd msger-native && npm run build:wsl",
20
+ "build:native:pi": "cd msger-native && npm run build:pi",
20
21
  "build:native:all": "npm run build:native && npm run build:native:wsl",
22
+ "build:native:allpiignored": "npm run build:native:pi",
21
23
  "build:ts": "tsc",
22
24
  "watch": "tsc -w",
23
25
  "clean": "rm -rf *.js *.d.ts *.js.map bin && cd msger-native && cargo clean",
package/postinstall.js CHANGED
@@ -9,15 +9,17 @@ const __dirname = path.dirname(__filename);
9
9
  const isWindows = process.platform === 'win32';
10
10
 
11
11
  if (!isWindows) {
12
- const binaryPath = path.join(__dirname, 'msger-native', 'bin', 'msgernative');
12
+ const arch = process.arch;
13
+ const binaryName = arch === 'arm64' ? 'msgernative-arm64' : 'msgernative';
14
+ const binaryPath = path.join(__dirname, 'msger-native', 'bin', binaryName);
13
15
 
14
16
  if (fs.existsSync(binaryPath)) {
15
17
  try {
16
18
  fs.chmodSync(binaryPath, 0o755);
17
- console.log('โœ… Set execute permissions on msgernative binary');
19
+ console.log(`โœ… Set execute permissions on ${binaryName} binary`);
18
20
  } catch (error) {
19
21
  console.warn(`โš ๏ธ Could not set execute permission on ${binaryPath}: ${error.message}`);
20
- console.warn(' You may need to run: sudo chmod +x ${binaryPath}');
22
+ console.warn(` You may need to run: sudo chmod +x ${binaryPath}`);
21
23
  }
22
24
  } else {
23
25
  console.warn(`โš ๏ธ Binary not found at ${binaryPath}`);