ember-mug 0.3.2 → 0.3.4

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/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ Usage:
11
11
  ember-mug [options]
12
12
 
13
13
  Options:
14
- -d, --debug Enable debug mode (outputs detailed Bluetooth logs)
14
+ -d, --debug Enable debug mode (console output with detailed Bluetooth logs)
15
15
  -h, --help Show this help message
16
16
 
17
17
  Environment variables:
@@ -19,53 +19,111 @@ Environment variables:
19
19
  `);
20
20
  process.exit(0);
21
21
  }
22
- // ANSI escape codes for alternate screen buffer
23
- const enterAltScreen = "\x1b[?1049h";
24
- const exitAltScreen = "\x1b[?1049l";
25
- const hideCursor = "\x1b[?25l";
26
- const showCursor = "\x1b[?25h";
27
- const clearScreen = "\x1b[2J\x1b[H";
28
- // Enter alternate screen buffer and hide cursor
29
- process.stdout.write(enterAltScreen + hideCursor + clearScreen);
30
- // Handle graceful shutdown - restore terminal state
31
- const cleanup = () => {
32
- process.stdout.write(showCursor + exitAltScreen);
33
- process.exit(0);
34
- };
35
- process.on("SIGINT", cleanup);
36
- process.on("SIGTERM", cleanup);
37
- process.on("exit", () => {
38
- process.stdout.write(showCursor + exitAltScreen);
39
- });
40
- // Handle terminal resize - clear screen to prevent artifacts
41
- process.stdout.on("resize", () => {
42
- process.stdout.write(clearScreen);
43
- });
44
- async function main() {
45
- // Dynamic imports to avoid initializing Bluetooth for --help
22
+ // Debug mode: run without Ink UI, just console output
23
+ async function runDebugMode() {
46
24
  const { setDebugMode } = await import("./lib/debug.js");
47
- // Enable debug mode if flag is set
48
- if (debugMode) {
49
- setDebugMode(true);
50
- }
51
- const React = await import("react");
52
- const { render } = await import("ink");
53
- const { App } = await import("./components/App.js");
54
- const { isMockMode, setBluetoothManager } = await import("./lib/bluetooth.js");
55
- // Initialize mock manager if in mock mode (set via EMBER_MOCK env var)
25
+ setDebugMode(true);
26
+ console.log("Starting ember-mug in debug mode...\n");
27
+ const { getBluetoothManager, isMockMode, setBluetoothManager } = await import("./lib/bluetooth.js");
28
+ // Initialize mock manager if in mock mode
56
29
  if (isMockMode()) {
30
+ console.log("Running in MOCK mode\n");
57
31
  const { getMockBluetoothManager } = await import("./lib/mock-bluetooth.js");
58
32
  const { BluetoothManager } = await import("./lib/bluetooth.js");
59
33
  setBluetoothManager(getMockBluetoothManager());
60
34
  }
61
- // Render the app
62
- const app = render(React.createElement(App));
63
- await app.waitUntilExit();
64
- process.exit(0);
35
+ const manager = getBluetoothManager();
36
+ // Listen to all events and log them
37
+ manager.on('scanning', (isScanning) => {
38
+ console.log(`[EVENT] Scanning: ${isScanning}`);
39
+ });
40
+ manager.on('mugFound', (name) => {
41
+ console.log(`[EVENT] Mug found: ${name}`);
42
+ });
43
+ manager.on('connected', () => {
44
+ console.log(`[EVENT] Connected!`);
45
+ });
46
+ manager.on('disconnected', () => {
47
+ console.log(`[EVENT] Disconnected`);
48
+ });
49
+ manager.on('error', (error) => {
50
+ console.error(`[EVENT] Error: ${error.message}`);
51
+ });
52
+ manager.on('stateChange', (state) => {
53
+ console.log(`[EVENT] State changed:`, JSON.stringify(state, null, 2));
54
+ });
55
+ // Handle graceful shutdown
56
+ process.on("SIGINT", () => {
57
+ console.log("\nShutting down...");
58
+ manager.disconnect();
59
+ process.exit(0);
60
+ });
61
+ // Start scanning
62
+ console.log("Starting Bluetooth scan...\n");
63
+ try {
64
+ await manager.startScanning();
65
+ }
66
+ catch (error) {
67
+ console.error("Failed to start scanning:", error);
68
+ process.exit(1);
69
+ }
70
+ // Keep the process running
71
+ await new Promise(() => { });
72
+ }
73
+ // Normal mode: run with Ink UI
74
+ async function runNormalMode() {
75
+ // ANSI escape codes for alternate screen buffer
76
+ const enterAltScreen = "\x1b[?1049h";
77
+ const exitAltScreen = "\x1b[?1049l";
78
+ const hideCursor = "\x1b[?25l";
79
+ const showCursor = "\x1b[?25h";
80
+ const clearScreen = "\x1b[2J\x1b[H";
81
+ // Enter alternate screen buffer and hide cursor
82
+ process.stdout.write(enterAltScreen + hideCursor + clearScreen);
83
+ // Handle graceful shutdown - restore terminal state
84
+ const cleanup = () => {
85
+ process.stdout.write(showCursor + exitAltScreen);
86
+ process.exit(0);
87
+ };
88
+ process.on("SIGINT", cleanup);
89
+ process.on("SIGTERM", cleanup);
90
+ process.on("exit", () => {
91
+ process.stdout.write(showCursor + exitAltScreen);
92
+ });
93
+ // Handle terminal resize - clear screen to prevent artifacts
94
+ process.stdout.on("resize", () => {
95
+ process.stdout.write(clearScreen);
96
+ });
97
+ try {
98
+ const React = await import("react");
99
+ const { render } = await import("ink");
100
+ const { App } = await import("./components/App.js");
101
+ const { isMockMode, setBluetoothManager } = await import("./lib/bluetooth.js");
102
+ // Initialize mock manager if in mock mode (set via EMBER_MOCK env var)
103
+ if (isMockMode()) {
104
+ const { getMockBluetoothManager } = await import("./lib/mock-bluetooth.js");
105
+ const { BluetoothManager } = await import("./lib/bluetooth.js");
106
+ setBluetoothManager(getMockBluetoothManager());
107
+ }
108
+ // Render the app
109
+ const app = render(React.createElement(App));
110
+ await app.waitUntilExit();
111
+ process.exit(0);
112
+ }
113
+ catch (error) {
114
+ process.stdout.write(showCursor + exitAltScreen);
115
+ console.error("Failed to start:", error);
116
+ process.exit(1);
117
+ }
118
+ }
119
+ // Run appropriate mode
120
+ if (debugMode) {
121
+ runDebugMode().catch((error) => {
122
+ console.error("Failed to start:", error);
123
+ process.exit(1);
124
+ });
125
+ }
126
+ else {
127
+ runNormalMode();
65
128
  }
66
- main().catch((error) => {
67
- process.stdout.write(showCursor + exitAltScreen);
68
- console.error("Failed to start:", error);
69
- process.exit(1);
70
- });
71
129
  export {};
@@ -46,6 +46,12 @@ export class BluetoothManager extends EventEmitter {
46
46
  this.emit('mugFound', name);
47
47
  await this.stopScanning();
48
48
  this.peripheral = peripheral;
49
+ // Wait for BLE adapter to settle after stopping scan
50
+ // This delay is necessary because some BLE adapters (especially on Linux with BlueZ)
51
+ // need time to switch from scanning mode to connection mode
52
+ const POST_SCAN_DELAY = 500;
53
+ debug(`Waiting ${POST_SCAN_DELAY}ms for BLE adapter to settle after scan...`);
54
+ await new Promise(resolve => setTimeout(resolve, POST_SCAN_DELAY));
49
55
  debug('Starting connection process...');
50
56
  await this.connectWithRetry();
51
57
  }
package/dist/lib/debug.js CHANGED
@@ -17,6 +17,5 @@ export function debug(message, ...args) {
17
17
  const formattedArgs = args.length > 0
18
18
  ? ' ' + args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ')
19
19
  : '';
20
- // Write to stderr so it doesn't interfere with Ink's stdout rendering
21
- process.stderr.write(`[${timestamp}] [DEBUG] ${message}${formattedArgs}\n`);
20
+ console.log(`[${timestamp}] [DEBUG] ${message}${formattedArgs}`);
22
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-mug",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "A CLI app for controlling Ember mugs via Bluetooth",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",