promethios-bridge 2.2.0 → 2.2.1

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": "2.2.0",
3
+ "version": "2.2.1",
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
@@ -39,7 +39,12 @@ const { initAndroidTools } = require('./tools/android');
39
39
 
40
40
  // Optional: Electron overlay window (bundled in src/overlay — gracefully skipped if Electron not available)
41
41
  let launchOverlay = null;
42
- try { launchOverlay = require('./overlay/launcher').launchOverlay; } catch { /* overlay launcher not found */ }
42
+ let isDesktopInstalled = null;
43
+ try {
44
+ const overlayLauncher = require('./overlay/launcher');
45
+ launchOverlay = overlayLauncher.launchOverlay;
46
+ isDesktopInstalled = overlayLauncher.isDesktopInstalled;
47
+ } catch { /* overlay launcher not found */ }
43
48
 
44
49
  const HEARTBEAT_INTERVAL = 30_000; // 30s
45
50
  const POLL_INTERVAL = 1_000; // 1s — poll for pending tool calls
@@ -1430,17 +1435,27 @@ h1{font-size:20px;font-weight:700;margin:0;}p{font-size:13px;color:rgba(255,255,
1430
1435
  overlayAuthToken = authToken;
1431
1436
  bridgeUsername = require('os').userInfo().username;
1432
1437
 
1433
- // Try Electron first (available when installed globally or via postinstall).
1434
- // Fall back to opening the browser-based overlay at http://localhost:<port>/overlay.
1438
+ // ── Option C: Try Electron first; only fall back to browser overlay if not installed ──
1439
+ // isDesktopInstalled() scans standard install paths (postinstall dir + OS program dirs).
1440
+ // If the EXE is found, we launch it and skip the browser overlay entirely.
1441
+ // If not found, we open the browser overlay as a fallback.
1435
1442
  let overlayLaunched = false;
1443
+
1444
+ const desktopInstalled = isDesktopInstalled && isDesktopInstalled();
1445
+
1436
1446
  if (launchOverlay) {
1437
1447
  try {
1438
1448
  const overlayChild = launchOverlay({ authToken, apiBase, dev });
1439
1449
  if (overlayChild) {
1440
1450
  overlayLaunched = true;
1441
- console.log(chalk.cyan(' ⬡ Promethios overlay launched — floating chat is ready'));
1451
+ console.log(chalk.cyan(' ⬡ Promethios Desktop launched — floating overlay is ready'));
1442
1452
  console.log(chalk.gray(' Hotkey: Ctrl+Shift+P (Win/Linux) or Cmd+Shift+P (Mac)'));
1443
1453
  console.log('');
1454
+ } else if (desktopInstalled) {
1455
+ // findDesktopBinary found a path but spawn returned null — EXE may already be running
1456
+ overlayLaunched = true;
1457
+ console.log(chalk.cyan(' ⬡ Promethios Desktop is running'));
1458
+ console.log('');
1444
1459
  }
1445
1460
  } catch (err) {
1446
1461
  log('Electron overlay launch failed (non-critical):', err.message);
@@ -1448,8 +1463,8 @@ h1{font-size:20px;font-weight:700;margin:0;}p{font-size:13px;color:rgba(255,255,
1448
1463
  }
1449
1464
 
1450
1465
  if (!overlayLaunched) {
1451
- // Electron not available — open the lightweight browser overlay instead.
1452
- // This is a small chat UI served by the bridge's own Express server.
1466
+ // Electron Desktop not installed — open the lightweight browser overlay instead.
1467
+ // This is the full-featured chat + Providers UI served by the bridge's Express server.
1453
1468
  const overlayUrl = `http://127.0.0.1:${port}/overlay`;
1454
1469
  const openedInBrowser = await openInBrowser(overlayUrl, log);
1455
1470
  if (openedInBrowser) {
@@ -2,13 +2,15 @@
2
2
  * launcher.js — Promethios Bridge
3
3
  *
4
4
  * Called by bridge.js after successful authentication.
5
- * Finds the pre-built Promethios Desktop binary (downloaded by postinstall.js
6
- * into ~/.promethios/desktop/) and spawns it with auth credentials via env vars.
5
+ * Finds the pre-built Promethios Desktop binary and spawns it with auth
6
+ * credentials via env vars.
7
7
  *
8
8
  * Binary search order:
9
9
  * 1. PROMETHIOS_DESKTOP_BIN environment variable (dev override)
10
10
  * 2. ~/.promethios/desktop/ — where postinstall.js places the binary
11
- * 3. Electron source-mode fallback (dev only, requires electron in node_modules)
11
+ * 3. Standard OS install paths (Windows: %LOCALAPPDATA%\Programs\Promethios\,
12
+ * macOS: /Applications/Promethios.app, Linux: /opt/Promethios/)
13
+ * 4. Electron source-mode fallback (dev only, requires electron in node_modules)
12
14
  *
13
15
  * The pre-built binary reads its config from env vars:
14
16
  * PROMETHIOS_TOKEN, PROMETHIOS_API_BASE, PROMETHIOS_THREAD_ID, PROMETHIOS_DEV
@@ -30,18 +32,17 @@ function findDesktopBinary() {
30
32
  return process.env.PROMETHIOS_DESKTOP_BIN;
31
33
  }
32
34
 
33
- // 2. Scan ~/.promethios/desktop/ for a matching binary
35
+ // 2. Scan ~/.promethios/desktop/ for a matching binary (postinstall download location)
34
36
  if (fs.existsSync(INSTALL_DIR)) {
35
37
  const files = fs.readdirSync(INSTALL_DIR);
36
38
  const exts = process.platform === 'win32' ? ['.exe']
37
- : process.platform === 'darwin' ? ['.dmg', '.app']
39
+ : process.platform === 'darwin' ? ['.app']
38
40
  : ['.AppImage'];
39
41
 
40
42
  for (const ext of exts) {
41
- const match = files.find(f => f.endsWith(ext));
43
+ const match = files.find(f => f.endsWith(ext) && !f.includes('Setup'));
42
44
  if (match) {
43
45
  const full = path.join(INSTALL_DIR, match);
44
- // Ensure executable bit is set on Unix
45
46
  try {
46
47
  if (process.platform !== 'win32') fs.chmodSync(full, 0o755);
47
48
  } catch {}
@@ -50,6 +51,67 @@ function findDesktopBinary() {
50
51
  }
51
52
  }
52
53
 
54
+ // 3. Standard OS install paths (when user installed via the installer EXE/DMG)
55
+ if (process.platform === 'win32') {
56
+ const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
57
+ const programFiles = process.env.PROGRAMFILES || 'C:\\Program Files';
58
+ const programFilesX86 = process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)';
59
+
60
+ const candidates = [
61
+ // Electron-builder default: %LOCALAPPDATA%\Programs\Promethios\Promethios.exe
62
+ path.join(localAppData, 'Programs', 'Promethios', 'Promethios.exe'),
63
+ path.join(localAppData, 'Programs', 'promethios', 'Promethios.exe'),
64
+ // Per-machine install
65
+ path.join(programFiles, 'Promethios', 'Promethios.exe'),
66
+ path.join(programFilesX86, 'Promethios', 'Promethios.exe'),
67
+ // Alternate casing
68
+ path.join(localAppData, 'Programs', 'Promethios Desktop', 'Promethios Desktop.exe'),
69
+ path.join(localAppData, 'Programs', 'Promethios', 'Promethios Desktop.exe'),
70
+ ];
71
+
72
+ for (const c of candidates) {
73
+ if (fs.existsSync(c)) return c;
74
+ }
75
+
76
+ // Scan %LOCALAPPDATA%\Programs\ for any Promethios*.exe
77
+ const programsDir = path.join(localAppData, 'Programs');
78
+ if (fs.existsSync(programsDir)) {
79
+ try {
80
+ const dirs = fs.readdirSync(programsDir);
81
+ for (const dir of dirs) {
82
+ if (dir.toLowerCase().includes('promethios')) {
83
+ const dirPath = path.join(programsDir, dir);
84
+ const files = fs.readdirSync(dirPath);
85
+ const exe = files.find(f => f.endsWith('.exe') && !f.includes('Uninstall') && !f.includes('Update'));
86
+ if (exe) return path.join(dirPath, exe);
87
+ }
88
+ }
89
+ } catch {}
90
+ }
91
+ } else if (process.platform === 'darwin') {
92
+ const candidates = [
93
+ '/Applications/Promethios.app/Contents/MacOS/Promethios',
94
+ '/Applications/Promethios Desktop.app/Contents/MacOS/Promethios Desktop',
95
+ path.join(os.homedir(), 'Applications', 'Promethios.app', 'Contents', 'MacOS', 'Promethios'),
96
+ ];
97
+ for (const c of candidates) {
98
+ if (fs.existsSync(c)) return c;
99
+ }
100
+ } else {
101
+ // Linux
102
+ const candidates = [
103
+ '/opt/Promethios/promethios',
104
+ '/usr/local/bin/promethios',
105
+ path.join(os.homedir(), '.local', 'share', 'promethios', 'promethios'),
106
+ ];
107
+ for (const c of candidates) {
108
+ if (fs.existsSync(c)) {
109
+ try { fs.chmodSync(c, 0o755); } catch {}
110
+ return c;
111
+ }
112
+ }
113
+ }
114
+
53
115
  return null;
54
116
  }
55
117
 
@@ -131,4 +193,9 @@ function launchOverlay({ authToken, apiBase = 'https://api.promethios.ai', threa
131
193
  return child;
132
194
  }
133
195
 
134
- module.exports = { launchOverlay };
196
+ // ── Check if Electron is installed (without launching) ───────────────────────
197
+ function isDesktopInstalled() {
198
+ return !!findDesktopBinary();
199
+ }
200
+
201
+ module.exports = { launchOverlay, isDesktopInstalled, findDesktopBinary };