promethios-bridge 1.7.2 → 1.7.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promethios-bridge",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Run Promethios agent frameworks locally on your computer with full file, terminal, browser access, ambient context capture, and the always-on-top floating chat overlay. Native Framework Mode supports OpenClaw and other frameworks via the bridge.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/bridge.js CHANGED
@@ -227,10 +227,16 @@ async function startBridge({ setupToken, apiBase, port, dev }) {
227
227
  // Users can toggle watching on/off from the pill without restarting the bridge.
228
228
  if (launchOverlay) {
229
229
  try {
230
- launchOverlay({ authToken, apiBase, dev });
231
- console.log(chalk.cyan(' ⬡ Promethios overlay launched — floating chat is ready'));
232
- console.log(chalk.gray(' Hotkey: Ctrl+Shift+P (Win/Linux) or Cmd+Shift+P (Mac)'));
233
- console.log('');
230
+ const overlayChild = launchOverlay({ authToken, apiBase, dev });
231
+ if (overlayChild) {
232
+ // Give the child process a moment to start — if it fails immediately
233
+ // (e.g. ENOENT because electron is not installed), the error handler
234
+ // in launcher.js will silently absorb it. We print the success message
235
+ // optimistically but it's non-critical if the overlay doesn't appear.
236
+ console.log(chalk.cyan(' ⬡ Promethios overlay launched — floating chat is ready'));
237
+ console.log(chalk.gray(' Hotkey: Ctrl+Shift+P (Win/Linux) or Cmd+Shift+P (Mac)'));
238
+ console.log('');
239
+ }
234
240
  } catch (err) {
235
241
  log('Overlay launch failed (non-critical):', err.message);
236
242
  }
@@ -53,39 +53,43 @@ async function captureContext(platform, dev) {
53
53
  // ─────────────────────────────────────────────────────────────────────────────
54
54
  async function captureWindows(snapshot, log) {
55
55
  // Active window title + process name
56
+ // NOTE: PowerShell here-strings (@"..."@) cannot be passed via -Command because
57
+ // newlines get collapsed. We write a temp .ps1 file and run it with -File instead.
56
58
  try {
57
- const psScript = `
58
- Add-Type @"
59
- using System;
60
- using System.Runtime.InteropServices;
61
- using System.Text;
62
- public class Win32 {
63
- [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
64
- [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
65
- [DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
66
- }
67
- "@
68
- $hwnd = [Win32]::GetForegroundWindow()
69
- $sb = New-Object System.Text.StringBuilder 512
70
- [Win32]::GetWindowText($hwnd, $sb, 512) | Out-Null
71
- $pid = 0
72
- [Win32]::GetWindowThreadProcessId($hwnd, [ref]$pid) | Out-Null
73
- $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
74
- $result = @{
75
- title = $sb.ToString()
76
- process = if ($proc) { $proc.Name } else { "unknown" }
77
- } | ConvertTo-Json -Compress
78
- Write-Output $result
79
- `.trim();
80
-
59
+ const os = require('os');
60
+ const tmpFile = require('path').join(os.tmpdir(), `promethios_ctx_${process.pid}.ps1`);
61
+ const psScript = [
62
+ 'Add-Type @"',
63
+ 'using System;',
64
+ 'using System.Runtime.InteropServices;',
65
+ 'using System.Text;',
66
+ 'public class Win32 {',
67
+ ' [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();',
68
+ ' [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);',
69
+ ' [DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);',
70
+ '}',
71
+ '"@',
72
+ '$hwnd = [Win32]::GetForegroundWindow()',
73
+ '$sb = New-Object System.Text.StringBuilder 512',
74
+ '[Win32]::GetWindowText($hwnd, $sb, 512) | Out-Null',
75
+ '$pid2 = 0',
76
+ '[Win32]::GetWindowThreadProcessId($hwnd, [ref]$pid2) | Out-Null',
77
+ '$proc = Get-Process -Id $pid2 -ErrorAction SilentlyContinue',
78
+ '$result = @{',
79
+ ' title = $sb.ToString()',
80
+ ' procName = if ($proc) { $proc.Name } else { "unknown" }',
81
+ '} | ConvertTo-Json -Compress',
82
+ 'Write-Output $result',
83
+ ].join('\r\n');
84
+ require('fs').writeFileSync(tmpFile, psScript, 'utf8');
81
85
  const output = execSync(
82
- `powershell -NoProfile -NonInteractive -Command "${psScript.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`,
86
+ `powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${tmpFile}"`,
83
87
  { encoding: 'utf8', timeout: 4000, windowsHide: true }
84
88
  ).trim();
85
-
89
+ try { require('fs').unlinkSync(tmpFile); } catch { /* cleanup best-effort */ }
86
90
  const parsed = JSON.parse(output);
87
- snapshot.active_window = { title: parsed.title, process: parsed.process };
88
- snapshot.active_app = friendlyAppName(parsed.process, parsed.title);
91
+ snapshot.active_window = { title: parsed.title, process: parsed.procName };
92
+ snapshot.active_app = friendlyAppName(parsed.procName, parsed.title);
89
93
  log('Active window:', snapshot.active_window);
90
94
  } catch (err) {
91
95
  log('Windows active window capture failed:', err.message);
@@ -17,6 +17,11 @@ const fs = require('fs');
17
17
  /**
18
18
  * Launch the Promethios overlay Electron window.
19
19
  * Returns the child process (or null if Electron is not available).
20
+ *
21
+ * IMPORTANT: When running via `npx`, optional dependencies (including electron)
22
+ * are NOT installed in the npx cache. The spawn() call may therefore fail with
23
+ * ENOENT. We attach an 'error' handler before unref() to silently absorb this
24
+ * instead of crashing the bridge process with an unhandled error event.
20
25
  */
21
26
  function launchOverlay({ authToken, apiBase = 'https://api.promethios.ai', threadId = '', dev = false } = {}) {
22
27
  // Find electron binary — try local node_modules first, then global
@@ -33,7 +38,7 @@ function launchOverlay({ authToken, apiBase = 'https://api.promethios.ai', threa
33
38
  for (const candidate of candidates) {
34
39
  try {
35
40
  if (candidate === 'electron') {
36
- // Try to resolve globally
41
+ // Try to resolve globally — throws if not installed
37
42
  require.resolve('electron');
38
43
  electronBin = candidate;
39
44
  break;
@@ -46,7 +51,7 @@ function launchOverlay({ authToken, apiBase = 'https://api.promethios.ai', threa
46
51
  }
47
52
 
48
53
  if (!electronBin) {
49
- if (dev) console.log('[overlay] Electron not found — overlay will not launch. Install with: npm install -g electron');
54
+ if (dev) console.log('[overlay] Electron not found — overlay will not launch.');
50
55
  return null;
51
56
  }
52
57
 
@@ -64,6 +69,14 @@ function launchOverlay({ authToken, apiBase = 'https://api.promethios.ai', threa
64
69
  env: { ...process.env, ELECTRON_NO_ATTACH_CONSOLE: '1' },
65
70
  });
66
71
 
72
+ // Attach error handler BEFORE unref() to prevent unhandled 'error' event crashes.
73
+ // When running via npx, optional deps like electron are not installed, so spawn
74
+ // may emit ENOENT. We catch it silently — the bridge works fine without the overlay.
75
+ child.on('error', (err) => {
76
+ if (dev) console.log(`[overlay] Spawn error (non-critical): ${err.message}`);
77
+ // No-op: overlay is optional, bridge continues running normally
78
+ });
79
+
67
80
  child.unref(); // Don't keep bridge CLI alive waiting for overlay
68
81
 
69
82
  if (dev) console.log(`[overlay] Launched (pid ${child.pid})`);