amalgm 0.1.53 → 0.1.55

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": "amalgm",
3
- "version": "0.1.53",
3
+ "version": "0.1.55",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -1,12 +1,58 @@
1
1
  const http = require('http');
2
2
  const https = require('https');
3
+ const fs = require('fs');
4
+ const os = require('os');
5
+ const path = require('path');
3
6
 
4
7
  const DEFAULT_SESSION = `mcp-${process.pid}-default`;
5
8
 
9
+ function amalgmDir() {
10
+ return process.env.AMALGM_DIR || path.join(os.homedir(), '.amalgm');
11
+ }
12
+
13
+ function bridgeConfigFile() {
14
+ return path.join(amalgmDir(), 'electron-browser-bridge.json');
15
+ }
16
+
17
+ function isLoopbackUrl(value) {
18
+ try {
19
+ const url = new URL(value);
20
+ return url.protocol === 'http:' && (url.hostname === '127.0.0.1' || url.hostname === 'localhost');
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ function pidIsRunning(pid) {
27
+ if (!Number.isInteger(pid) || pid <= 0) return false;
28
+ try {
29
+ process.kill(pid, 0);
30
+ return true;
31
+ } catch (err) {
32
+ return err && err.code === 'EPERM';
33
+ }
34
+ }
35
+
36
+ function normalizeConfig(data) {
37
+ const baseUrl = typeof data?.baseUrl === 'string' ? data.baseUrl : '';
38
+ const token = typeof data?.token === 'string' ? data.token : '';
39
+ if (!baseUrl || !token || !isLoopbackUrl(baseUrl)) return null;
40
+ if (typeof data?.pid === 'number' && !pidIsRunning(data.pid)) return null;
41
+ return { baseUrl, token };
42
+ }
43
+
44
+ function fileConfig() {
45
+ try {
46
+ return normalizeConfig(JSON.parse(fs.readFileSync(bridgeConfigFile(), 'utf8')));
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
6
52
  function config() {
7
53
  const baseUrl = process.env.AMALGM_ELECTRON_BROWSER_URL;
8
54
  const token = process.env.AMALGM_ELECTRON_BROWSER_TOKEN;
9
- return baseUrl && token ? { baseUrl, token } : null;
55
+ return normalizeConfig({ baseUrl, token }) || fileConfig();
10
56
  }
11
57
 
12
58
  function isConfigured() {
@@ -1,6 +1,11 @@
1
1
  const electron = require('./electron-bridge');
2
2
  const agentBrowser = require('./agent-browser');
3
3
 
4
+ function isPackagedDesktopRuntime() {
5
+ const execPath = process.execPath || '';
6
+ return process.env.ELECTRON_RUN_AS_NODE === '1' && execPath.includes('.app/Contents/MacOS/');
7
+ }
8
+
4
9
  function backend() {
5
10
  const requested = (process.env.AMALGM_BROWSER_BACKEND || '').toLowerCase();
6
11
  if (requested === 'agent-browser' || requested === 'external') return agentBrowser;
@@ -8,7 +13,8 @@ function backend() {
8
13
 
9
14
  // In the desktop app this bridge drives the visible in-tab Electron webview.
10
15
  // Outside Electron, keep the agent-browser CLI fallback for headless/remote use.
11
- return electron.isConfigured() ? electron : agentBrowser;
16
+ if (electron.isConfigured() || isPackagedDesktopRuntime()) return electron;
17
+ return agentBrowser;
12
18
  }
13
19
 
14
20
  const exported = {};