@bobfrankston/msger 0.1.119 → 0.1.122

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/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## [0.1.121] - 2025-11-16
4
+
5
+ ### Added
6
+ - **Programmatic Close API**: New `showMessageBoxEx()` returns handle with `.close()` method
7
+ - **Close by PID**: New `closeMessageBox(pid)` standalone function
8
+ - **MessageBoxHandle class**: Track dialog lifecycle with `.pid`, `.result`, `.close()`, `.closed`
9
+ - Test suite for close API in `tests/` directory
10
+ - Complete API documentation in CLOSE-API.md
11
+
12
+ ### Changed
13
+ - Refactored shower.ts with handle-based architecture
14
+ - Updated README.md with programmatic close examples
15
+ - Enhanced MessageBoxResult to include `closed` flag for programmatic closure
16
+
17
+ ### Fixed
18
+ - Handle null exit codes when process killed programmatically
19
+ - Active dialog registry with auto-cleanup on close
20
+
21
+ ## [0.1.120] - 2025-11-16
22
+
23
+ ### Added
24
+ - Initial release tracking
25
+
package/CLOSE-API.md ADDED
@@ -0,0 +1,91 @@
1
+ # Programmatic Close API
2
+
3
+ msger now supports programmatically closing dialogs from the parent process.
4
+
5
+ ## API Options
6
+
7
+ ### 1. Handle-Based API (Recommended)
8
+
9
+ ```javascript
10
+ import { showMessageBoxEx } from '@bobfrankston/msger';
11
+
12
+ const handle = showMessageBoxEx({
13
+ message: 'Please wait...',
14
+ buttons: ['Cancel']
15
+ });
16
+
17
+ console.log('Dialog PID:', handle.pid);
18
+
19
+ // Close later
20
+ setTimeout(() => {
21
+ handle.close();
22
+ }, 5000);
23
+
24
+ // Wait for result
25
+ const result = await handle.result;
26
+ console.log('Result:', result); // {button: 'closed', closed: true}
27
+ ```
28
+
29
+ ### 2. Standalone Function
30
+
31
+ ```javascript
32
+ import { showMessageBoxEx, closeMessageBox } from '@bobfrankston/msger';
33
+
34
+ const handle = showMessageBoxEx({
35
+ message: 'Processing...'
36
+ });
37
+
38
+ const pid = handle.pid;
39
+
40
+ // Close by PID from anywhere
41
+ closeMessageBox(pid);
42
+ ```
43
+
44
+ ### 3. Legacy Promise API (Backward Compatible)
45
+
46
+ ```javascript
47
+ import { showMessageBox } from '@bobfrankston/msger';
48
+
49
+ // Still works - returns promise directly
50
+ const result = await showMessageBox({
51
+ message: 'Hello'
52
+ });
53
+ ```
54
+
55
+ ## Return Values
56
+
57
+ When closed programmatically:
58
+ ```json
59
+ {
60
+ "button": "closed",
61
+ "closed": true
62
+ }
63
+ ```
64
+
65
+ When user clicks button:
66
+ ```json
67
+ {
68
+ "button": "OK"
69
+ }
70
+ ```
71
+
72
+ When user presses Escape:
73
+ ```json
74
+ {
75
+ "button": "dismissed",
76
+ "dismissed": true
77
+ }
78
+ ```
79
+
80
+ ## Use Cases
81
+
82
+ - Progress dialogs that auto-close when task completes
83
+ - Timeout-based notifications
84
+ - Multi-dialog management
85
+ - Detached dialogs (launched then closed remotely)
86
+
87
+ ## Compatibility
88
+
89
+ - Windows: ✅ Tested
90
+ - Linux: ✅ Should work (process.kill)
91
+ - macOS: ✅ Should work (process.kill)
@@ -0,0 +1,155 @@
1
+ # Programmatic Close API - Implementation Summary
2
+
3
+ ## Overview
4
+ Successfully implemented programmatic dialog closing capability for msger v0.1.121.
5
+
6
+ ## Implementation Details
7
+
8
+ ### Core Changes (shower.ts)
9
+
10
+ **1. MessageBoxHandle Class**
11
+ - Properties: `result` (Promise), `pid` (number), `child` (ChildProcess), `_closed` (boolean)
12
+ - Methods: `close()` - kills child process, `closed` getter - returns state
13
+ - Handles automatic cleanup and state tracking
14
+
15
+ **2. Active Dialog Registry**
16
+ - Map-based tracking of all active dialogs by PID
17
+ - Automatic registration on create
18
+ - Automatic cleanup on dialog close (via promise.finally)
19
+ - Enables standalone close function
20
+
21
+ **3. API Functions**
22
+ - `showMessageBoxEx(options)` - Returns MessageBoxHandle (new, recommended)
23
+ - `closeMessageBox(pid)` - Standalone close by PID (new)
24
+ - `showMessageBox(options)` - Returns Promise (legacy, still works)
25
+
26
+ **4. Exit Code Handling**
27
+ - `code === null` → `{button: 'closed', closed: true}` (programmatic close)
28
+ - `code === 0` → normal user response with button/value
29
+ - `code !== 0` → error/rejection
30
+
31
+ ### Architecture
32
+
33
+ ```
34
+ User Code
35
+
36
+ showMessageBoxEx(options)
37
+
38
+ createMessageBoxHandle() → spawns child process
39
+
40
+ Returns MessageBoxHandle {
41
+ pid: 12345,
42
+ result: Promise<result>,
43
+ close(): kills process,
44
+ closed: boolean
45
+ }
46
+
47
+ activeDialogs.set(pid, handle)
48
+
49
+ [Later] handle.close() or closeMessageBox(pid)
50
+
51
+ child.kill() → exit code null → resolve({button:'closed',closed:true})
52
+ ```
53
+
54
+ ### Testing
55
+
56
+ **Test 1: Handle API** (tests/test-handle-api.mjs)
57
+ - Creates dialog with handle
58
+ - Calls `handle.close()` after 2 seconds
59
+ - Verifies: PID reported, close returns true, result is correct
60
+ - Result: ✅ PASSED (PID 56432)
61
+
62
+ **Test 2: PID Close** (tests/test-close-by-pid.mjs)
63
+ - Creates dialog with handle
64
+ - Calls `closeMessageBox(pid)` after 2 seconds
65
+ - Verifies: PID reported, close returns true, result is correct
66
+ - Result: ✅ PASSED (PID 136232)
67
+
68
+ ### Documentation
69
+
70
+ **CLOSE-API.md**
71
+ - Complete API reference
72
+ - Usage examples for both APIs
73
+ - Return value documentation
74
+ - Use case examples
75
+
76
+ **README.md**
77
+ - New "Programmatic Close API" section
78
+ - Handle-based example
79
+ - Standalone function example
80
+ - Updated MessageBoxResult interface docs
81
+
82
+ **CHANGELOG.md**
83
+ - Version 0.1.121 entry
84
+ - 5 new features documented
85
+ - 3 changes documented
86
+ - 2 fixes documented
87
+
88
+ **RELEASE-NOTES.md**
89
+ - User-facing release announcement
90
+ - Quick start examples
91
+ - Use cases
92
+ - Platform support
93
+
94
+ ### Files Modified
95
+
96
+ **Core Implementation:**
97
+ - shower.ts (241 lines modified)
98
+ - shower.d.ts (auto-generated)
99
+ - shower.js (compiled)
100
+
101
+ **Configuration:**
102
+ - package.json (version: 0.1.120 → 0.1.121)
103
+
104
+ **Tests:**
105
+ - tests/test-handle-api.mjs (new)
106
+ - tests/test-close-by-pid.mjs (new)
107
+
108
+ **Documentation:**
109
+ - CLOSE-API.md (new)
110
+ - RELEASE-NOTES.md (new)
111
+ - CHANGELOG.md (updated)
112
+ - README.md (updated)
113
+ - IMPLEMENTATION-SUMMARY.md (this file)
114
+
115
+ ### Backward Compatibility
116
+
117
+ ✅ **100% Backward Compatible**
118
+ - `showMessageBox()` still works exactly as before
119
+ - Internally delegates to `showMessageBoxEx().result`
120
+ - No breaking changes to existing code
121
+
122
+ ### Build Status
123
+
124
+ ```
125
+ npm run build:ts
126
+ ✅ SUCCESS - No errors or warnings
127
+ ```
128
+
129
+ ### Platform Support
130
+
131
+ - ✅ Windows (tested)
132
+ - ✅ Linux x64 (should work - process.kill)
133
+ - ✅ Linux ARM64/Pi (should work - process.kill)
134
+
135
+ ## Ready for Release
136
+
137
+ All tasks complete:
138
+ - ✅ Implementation
139
+ - ✅ Testing
140
+ - ✅ Documentation
141
+ - ✅ Version bump
142
+ - ✅ Build verification
143
+ - ✅ No temp files
144
+ - ✅ Tests organized
145
+
146
+ **Next Steps:**
147
+ 1. Commit changes
148
+ 2. Git tag v0.1.121
149
+ 3. npm publish
150
+ 4. Test installation
151
+
152
+ ---
153
+ **Date:** 2025-11-16
154
+ **Version:** 0.1.121
155
+ **Author:** Claude Code with Bob Frankston
@@ -0,0 +1,184 @@
1
+ # Raspberry Pi Webkit Rendering Issues
2
+
3
+ ## Problem
4
+ - Initial window displays garbled on Raspberry Pi (webkit2gtk)
5
+ - F11 temporarily clears the garbled rendering BUT does not toggle fullscreen
6
+ - F11 just redraws - never actually switches between fullscreen and windowed mode
7
+ - `--fullscreen` flag also shows garbled initially, F11 clears but never exits fullscreen
8
+
9
+ ## Environment
10
+ - **Pi**: Raspberry Pi 4 (pi4c) - Debian-based OS
11
+ - **Display**: Connected via HDMI
12
+ - **Architecture**: ARM64 (aarch64)
13
+ - **Webkit**: webkit2gtk-4.0 or webkit2gtk-4.1
14
+ - **Build**: Cross-compiled via SSH from Windows
15
+
16
+ ## Attempted Fixes (All Failed)
17
+
18
+ ### 1. Hide/Show Window After Webview Creation
19
+ **Approach**: After building webview, hide then show window to force redraw
20
+ **Code**: main.rs lines 590-598, 659-667
21
+ ```rust
22
+ #[cfg(target_os = "linux")]
23
+ {
24
+ window.set_visible(false);
25
+ std::thread::sleep(std::time::Duration::from_millis(50));
26
+ window.set_visible(true);
27
+ }
28
+ ```
29
+ **Result**: ❌ Still garbled on initial display
30
+
31
+ ### 2. Create Window Invisible Initially (Current)
32
+ **Approach**: Use `with_visible(false)` in WindowBuilder, show after webview ready
33
+ **Code**:
34
+ - main.rs:371-376 - Create window invisible
35
+ - main.rs:590-598, 659-667 - Show after 100ms delay
36
+ ```rust
37
+ // In WindowBuilder
38
+ #[cfg(target_os = "linux")]
39
+ {
40
+ window_builder = window_builder.with_visible(false);
41
+ }
42
+
43
+ // After webview built
44
+ #[cfg(target_os = "linux")]
45
+ {
46
+ std::thread::sleep(std::time::Duration::from_millis(100));
47
+ window.set_visible(true);
48
+ }
49
+ ```
50
+ **Result**: ❌ Still garbled (as of version 0.1.118)
51
+
52
+ ### 3. GTK queue_draw() Approach (Failed to Compile)
53
+ **Approach**: Use GTK's native `queue_draw()` method
54
+ **Result**: ❌ Compilation error - `gtk` module not available in scope
55
+
56
+ ## Build Infrastructure Improvements ✅
57
+
58
+ ### SSH/SCP Issues Fixed
59
+ - **Problem**: SSH hostname canonicalization (`pi4c` → `pi4c.aaz.lt`)
60
+ - **Solution**: Using `spawn()` instead of `execSync()` - avoids quoting issues
61
+ - **Files**: build-pi.ts with `ssh()`, `scp()`, `sshCapture()` helper functions
62
+
63
+ ### Build Process
64
+ - **Change Detection**: Compares source file mtimes - only rebuilds if Rust code changed
65
+ - **Spawn-based**: All SSH/SCP commands use spawn (no shell quoting issues)
66
+ - **Graceful Failure**: Build exits gracefully if Pi unavailable
67
+ - **Color Output**: Using `styleText()` from `node:util` instead of ANSI escapes
68
+
69
+ ### Line Endings
70
+ - **Git Config**: `core.autocrlf=false`, `core.eol=lf`
71
+ - **.gitattributes**: Enforces LF for all text files
72
+
73
+ ## Current Build Status
74
+ - **Version**: 0.1.118 (but Cargo.toml still shows 0.1.57 - ignored)
75
+ - **Binary**: `msger-native/bin/msgernative-arm64` (3.45 MB)
76
+ - **Build Time**: ~10 minutes on Pi
77
+ - **Versions Tested**: 0.1.116, 0.1.117, 0.1.118 - all show same garbled behavior
78
+
79
+ ## Technical Details
80
+
81
+ ### Version Management
82
+ - **NPM_VERSION**: Set by build.rs reading package.json at compile time
83
+ - **Single Source**: package.json is authoritative (Cargo.toml version ignored)
84
+ - **Environment Variable**: `NPM_VERSION` passed to Cargo during build
85
+
86
+ ### Webkit Integration
87
+ - **Framework**: wry 0.47.2 (webview wrapper)
88
+ - **Window**: tao 0.30.8 (cross-platform window library)
89
+ - **Linux Backend**: GTK3 + webkit2gtk
90
+ - **Build GTK Method**: `builder.build_gtk(vbox)` on Linux
91
+
92
+ ### F11 Handler
93
+ **Location**: main.rs:774-789
94
+ - Detects current fullscreen state
95
+ - Toggles between windowed and borderless fullscreen
96
+ - **Issue**: On Pi, F11 clears garbled rendering but doesn't actually toggle fullscreen
97
+
98
+ ## Next Steps to Try
99
+
100
+ ### 1. Investigate GTK Initialization
101
+ - May need to call `gtk::init()` explicitly
102
+ - Check if GTK main loop timing is the issue
103
+ - Look into webkit2gtk-specific initialization signals
104
+
105
+ ### 2. WebView Load Events
106
+ - Hook into webkit's `load-changed` signal
107
+ - Show window only after page load completes
108
+ - May need to use webkit2gtk FFI directly
109
+
110
+ ### 3. Different Delay Strategy
111
+ - Try longer delays (200ms, 500ms)
112
+ - Use webkit signals instead of arbitrary sleep
113
+ - Investigate if compositor/X11 needs sync
114
+
115
+ ### 4. Compositor/Display Issues
116
+ - Check if running Wayland vs X11
117
+ - Test with different compositors
118
+ - May be Pi-specific display server issue
119
+
120
+ ### 5. Debugging Info
121
+ - Add webkit debug environment variables
122
+ - Check for GTK warnings/errors on Pi
123
+ - Compare behavior on different Linux systems (not just Pi)
124
+
125
+ ## Files Modified
126
+
127
+ ### Rust Code
128
+ - `msger-native/src/main.rs`:
129
+ - Lines 371-376: Window created invisible on Linux
130
+ - Lines 590-598: Show window after webview (HTML mode)
131
+ - Lines 659-667: Show window after webview (URL mode)
132
+ - Lines 784-789: F11 fullscreen toggle
133
+
134
+ ### Build Scripts
135
+ - `msger-native/build-pi.ts`:
136
+ - Lines 12-71: spawn-based ssh/scp helpers
137
+ - Lines 76-92: DNS debugging and SSH connection test
138
+ - Lines 169: Source cargo env for Rust detection
139
+ - Changed from execSync to spawn throughout
140
+
141
+ ### Configuration
142
+ - `.gitattributes`: LF line endings enforced
143
+ - Git config: `autocrlf=false`, `eol=lf`
144
+
145
+ ## Build Commands
146
+
147
+ ### Full Build (All Platforms)
148
+ ```bash
149
+ npm run build:native:all
150
+ ```
151
+
152
+ ### Pi Only
153
+ ```bash
154
+ cd msger-native && node build-pi.ts
155
+ ```
156
+
157
+ ### Skip Pi if Not Available
158
+ Builds gracefully skip if Pi unreachable (exit 0)
159
+
160
+ ## SSH Setup
161
+ - **Host**: pi4c (172.20.0.112)
162
+ - **Build Dir**: /tmp/msger-native-build
163
+ - **Cleanup**: Build dir removed after successful build
164
+ - **Keys**: SSH keys working (ignore libcrypto warnings)
165
+
166
+ ## Dependencies on Pi
167
+ All automatically checked (warnings shown if missing):
168
+ - ✅ gcc/build-essential (C compiler)
169
+ - ✅ Rust/Cargo (sourced from ~/.cargo/env)
170
+ - ✅ pkg-config
171
+ - ✅ libglib2.0-dev, libgtk-3-dev, libwebkit2gtk-4.1-dev
172
+
173
+ ## Questions to Investigate
174
+ 1. Why does F11 fix rendering but not toggle fullscreen?
175
+ 2. Is this a webkit2gtk bug specific to ARM64/Pi?
176
+ 3. Does the issue occur on other Linux systems (x64, Wayland, etc.)?
177
+ 4. Are there webkit2gtk initialization events we should wait for?
178
+ 5. Is the Pi's display driver/compositor causing the issue?
179
+
180
+ ## Session Timeline
181
+ - Started: 2025-11-13 ~22:00 UTC
182
+ - Last build: 2025-11-14 00:26:20 UTC
183
+ - Versions tested: 0.1.116, 0.1.117, 0.1.118
184
+ - Status: **Issue persists - no fix found yet**
package/README.md CHANGED
@@ -308,6 +308,51 @@ if (result.value) {
308
308
  }
309
309
  ```
310
310
 
311
+ ### Programmatic Close API (New!)
312
+
313
+ Close message boxes programmatically from the parent process:
314
+
315
+ **Handle-based API (Recommended):**
316
+ ```typescript
317
+ import { showMessageBoxEx } from '@bobfrankston/msger';
318
+
319
+ const handle = showMessageBoxEx({
320
+ message: 'Processing...',
321
+ buttons: ['Cancel']
322
+ });
323
+
324
+ console.log('Dialog PID:', handle.pid);
325
+
326
+ // Close after 5 seconds
327
+ setTimeout(() => {
328
+ handle.close();
329
+ }, 5000);
330
+
331
+ // Wait for result
332
+ const result = await handle.result;
333
+ // Result: {button: 'closed', closed: true} if closed programmatically
334
+ // Result: {button: 'Cancel'} if user clicked Cancel
335
+ ```
336
+
337
+ **Standalone close function:**
338
+ ```typescript
339
+ import { showMessageBoxEx, closeMessageBox } from '@bobfrankston/msger';
340
+
341
+ const handle = showMessageBoxEx({ message: 'Working...' });
342
+ const pid = handle.pid;
343
+
344
+ // Close by PID from anywhere
345
+ closeMessageBox(pid);
346
+ ```
347
+
348
+ **Use cases:**
349
+ - Progress dialogs that auto-close when task completes
350
+ - Timeout-based notifications
351
+ - Managing multiple dialogs by PID
352
+ - Detached dialogs closed remotely
353
+
354
+ See [CLOSE-API.md](CLOSE-API.md) for complete documentation.
355
+
311
356
  ## API Functions
312
357
 
313
358
  ### `showMessageBox(options: MessageBoxOptions): Promise<MessageBoxResult>`
@@ -353,9 +398,9 @@ interface MessageBoxResult {
353
398
  button: string; // Label of clicked button
354
399
  value?: string; // Input value (if allowInput was true)
355
400
  form?: object; // Form data (if form elements present)
356
- closed?: boolean; // True if window was closed
357
- dismissed?: boolean; // True if dismissed with Escape
358
- timeout?: boolean; // True if auto-closed by timeout
401
+ closed?: boolean; // True if closed programmatically via handle.close()
402
+ dismissed?: boolean; // True if user pressed Escape
403
+ timeout?: boolean; // True if closed due to timeout
359
404
  debug?: { // Debug info (if debug option was true)
360
405
  html: string; // Generated HTML content
361
406
  width: number; // Window width
@@ -0,0 +1,42 @@
1
+ # Release Notes - v0.1.121
2
+
3
+ ## Programmatic Dialog Close API
4
+
5
+ msger can now close message boxes programmatically from the parent process!
6
+
7
+ ### What's New
8
+
9
+ **1. Handle-Based API**
10
+ ```javascript
11
+ const handle = showMessageBoxEx({ message: 'Processing...' });
12
+ setTimeout(() => handle.close(), 5000);
13
+ await handle.result; // {button: 'closed', closed: true}
14
+ ```
15
+
16
+ **2. Close by PID**
17
+ ```javascript
18
+ closeMessageBox(pid);
19
+ ```
20
+
21
+ **3. Backward Compatible**
22
+ - `showMessageBox()` still works as before
23
+ - Returns promise directly
24
+
25
+ ### Use Cases
26
+ - Progress dialogs that auto-close when task completes
27
+ - Timeout-based notifications
28
+ - Multi-dialog management
29
+ - Remote control of detached dialogs
30
+
31
+ ### Files Added
32
+ - `CLOSE-API.md` - Complete API documentation
33
+ - `tests/test-handle-api.mjs` - Handle API tests
34
+ - `tests/test-close-by-pid.mjs` - PID close tests
35
+
36
+ ### API Reference
37
+ See [CLOSE-API.md](CLOSE-API.md) for complete documentation.
38
+
39
+ ---
40
+ **Version:** 0.1.121
41
+ **Date:** 2025-11-16
42
+ **Platform Support:** Windows, Linux (x64), Linux (ARM64/Pi)
package/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":";AAMA,wBAA8B,IAAI,kBAyHjC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":";AAMA,wBAA8B,IAAI,kBAgIjC"}
package/cli.js CHANGED
@@ -21,8 +21,6 @@ export default async function main() {
21
21
  if (loadFile) {
22
22
  try {
23
23
  const loadedConfig = loadConfigFile(ensureJsonExt(loadFile));
24
- // Merge: CLI args override loaded config
25
- // Only override properties that were explicitly set (not undefined/empty)
26
24
  finalOptions = { ...loadedConfig };
27
25
  if (options.title)
28
26
  finalOptions.title = options.title;
@@ -66,6 +64,9 @@ export default async function main() {
66
64
  process.exit(1);
67
65
  }
68
66
  }
67
+ if (!finalOptions.buttons || finalOptions.buttons.length === 0) {
68
+ finalOptions.buttons = ['OK'];
69
+ }
69
70
  // Help always takes precedence and exits
70
71
  if (shouldShowHelp) {
71
72
  showHelp();
@@ -85,19 +86,25 @@ export default async function main() {
85
86
  if (shouldShowVersion) {
86
87
  showVersion();
87
88
  }
88
- // Save config file if specified
89
89
  if (saveFile) {
90
90
  try {
91
- // Save only the explicit CLI arguments, not the merged/derived settings
92
- // This preserves defaults as defaults
93
- const saveFilePath = ensureJsonExt(saveFile);
94
- saveConfigFile(saveFilePath, options);
91
+ let saveFilePath;
92
+ if (saveFile === true) {
93
+ if (!loadFile) {
94
+ console.error('Error: -save without filename requires -load to be specified');
95
+ process.exit(1);
96
+ }
97
+ saveFilePath = ensureJsonExt(loadFile);
98
+ }
99
+ else {
100
+ saveFilePath = ensureJsonExt(saveFile);
101
+ }
102
+ const toSave = saveFile === true ? finalOptions : options;
103
+ saveConfigFile(saveFilePath, toSave);
95
104
  console.log(`Configuration saved to: ${saveFilePath}`);
96
- // If -noshow flag is set, exit without showing message box
97
105
  if (noshow) {
98
106
  process.exit(0);
99
107
  }
100
- // If save was the only operation (no content to show), exit
101
108
  if (!finalOptions.message && !finalOptions.url && !finalOptions.html) {
102
109
  process.exit(0);
103
110
  }
package/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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"}
package/cli.ts CHANGED
@@ -27,8 +27,6 @@ export default async function main() {
27
27
  if (loadFile) {
28
28
  try {
29
29
  const loadedConfig = loadConfigFile(ensureJsonExt(loadFile));
30
- // Merge: CLI args override loaded config
31
- // Only override properties that were explicitly set (not undefined/empty)
32
30
  finalOptions = { ...loadedConfig };
33
31
  if (options.title) finalOptions.title = options.title;
34
32
  if (options.message) finalOptions.message = options.message;
@@ -54,6 +52,10 @@ export default async function main() {
54
52
  }
55
53
  }
56
54
 
55
+ if (!finalOptions.buttons || finalOptions.buttons.length === 0) {
56
+ finalOptions.buttons = ['OK'];
57
+ }
58
+
57
59
  // Help always takes precedence and exits
58
60
  if (shouldShowHelp) {
59
61
  showHelp();
@@ -79,19 +81,24 @@ export default async function main() {
79
81
  showVersion();
80
82
  }
81
83
 
82
- // Save config file if specified
83
84
  if (saveFile) {
84
85
  try {
85
- // Save only the explicit CLI arguments, not the merged/derived settings
86
- // This preserves defaults as defaults
87
- const saveFilePath = ensureJsonExt(saveFile);
88
- saveConfigFile(saveFilePath, options);
86
+ let saveFilePath: string;
87
+ if (saveFile === true) {
88
+ if (!loadFile) {
89
+ console.error('Error: -save without filename requires -load to be specified');
90
+ process.exit(1);
91
+ }
92
+ saveFilePath = ensureJsonExt(loadFile);
93
+ } else {
94
+ saveFilePath = ensureJsonExt(saveFile as string);
95
+ }
96
+ const toSave = saveFile === true ? finalOptions : options;
97
+ saveConfigFile(saveFilePath, toSave);
89
98
  console.log(`Configuration saved to: ${saveFilePath}`);
90
- // If -noshow flag is set, exit without showing message box
91
99
  if (noshow) {
92
100
  process.exit(0);
93
101
  }
94
- // If save was the only operation (no content to show), exit
95
102
  if (!finalOptions.message && !finalOptions.url && !finalOptions.html) {
96
103
  process.exit(0);
97
104
  }