amalgm 0.1.52 → 0.1.53

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.52",
3
+ "version": "0.1.53",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -60,15 +60,57 @@ function tabInfo(session, extra = {}) {
60
60
  return info;
61
61
  }
62
62
 
63
+ function executableExists(file) {
64
+ try {
65
+ fs.accessSync(file, fs.constants.X_OK);
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ function linuxLibcSuffix() {
73
+ if (process.platform !== 'linux') return '';
74
+ const glibc = process.report?.getReport?.().header?.glibcVersionRuntime;
75
+ return glibc ? '' : '-musl';
76
+ }
77
+
78
+ function agentBrowserBinaryName() {
79
+ if (!['darwin', 'linux', 'win32'].includes(process.platform)) return null;
80
+ if (!['arm64', 'x64'].includes(process.arch)) return null;
81
+ const platform = process.platform === 'win32' ? 'win32' : `${process.platform}${linuxLibcSuffix()}`;
82
+ const ext = process.platform === 'win32' ? '.exe' : '';
83
+ return `agent-browser-${platform}-${process.arch}${ext}`;
84
+ }
85
+
86
+ function asarUnpackedPath(file) {
87
+ const marker = `${path.sep}app.asar${path.sep}`;
88
+ return file.includes(marker)
89
+ ? file.replace(marker, `${path.sep}app.asar.unpacked${path.sep}`)
90
+ : file;
91
+ }
92
+
93
+ function nativeAgentBrowserCommand(entrypoint) {
94
+ const binaryName = agentBrowserBinaryName();
95
+ if (!entrypoint || !binaryName) return null;
96
+ const candidate = path.join(path.dirname(entrypoint), binaryName);
97
+ const unpacked = asarUnpackedPath(candidate);
98
+ const candidates = unpacked === candidate ? [candidate] : [unpacked];
99
+ return candidates.find(executableExists) || null;
100
+ }
101
+
63
102
  function agentBrowserCommand() {
64
103
  if (process.env.AMALGM_AGENT_BROWSER_BIN) {
65
104
  return { command: process.env.AMALGM_AGENT_BROWSER_BIN, prefix: [] };
66
105
  }
67
106
 
68
107
  try {
108
+ const entrypoint = require.resolve('agent-browser/bin/agent-browser.js');
109
+ const nativeCommand = nativeAgentBrowserCommand(entrypoint);
110
+ if (nativeCommand) return { command: nativeCommand, prefix: [] };
69
111
  return {
70
112
  command: process.execPath,
71
- prefix: [require.resolve('agent-browser/bin/agent-browser.js')],
113
+ prefix: [entrypoint],
72
114
  };
73
115
  } catch {
74
116
  return { command: 'agent-browser', prefix: [] };
@@ -25,6 +25,25 @@ function executableExists(file) {
25
25
  }
26
26
  }
27
27
 
28
+ function asarUnpackedPath(file) {
29
+ const marker = `${path.sep}app.asar${path.sep}`;
30
+ return file && file.includes(marker)
31
+ ? file.replace(marker, `${path.sep}app.asar.unpacked${path.sep}`)
32
+ : file;
33
+ }
34
+
35
+ function executablePath(file) {
36
+ const unpacked = asarUnpackedPath(file);
37
+ if (unpacked !== file) return executableExists(unpacked) ? unpacked : null;
38
+ return executableExists(file) ? file : null;
39
+ }
40
+
41
+ function existingPath(file) {
42
+ const unpacked = asarUnpackedPath(file);
43
+ if (unpacked !== file && fs.existsSync(unpacked)) return unpacked;
44
+ return fs.existsSync(file) ? file : null;
45
+ }
46
+
28
47
  function findPackageJson(packageName) {
29
48
  const candidateDirs = [
30
49
  ...nativeNodeModulesDirs(),
@@ -160,7 +179,7 @@ function bundledClaudeBinary() {
160
179
  const root = packageRoot(packageName);
161
180
  if (!root) return null;
162
181
  const candidate = path.join(root, process.platform === 'win32' ? 'claude.exe' : 'claude');
163
- return executableExists(candidate) ? candidate : null;
182
+ return executablePath(candidate);
164
183
  }
165
184
 
166
185
  function resolveClaudeBinary() {
@@ -213,8 +232,10 @@ function codexVendorRoot() {
213
232
  if (platformRoot) return path.join(platformRoot, 'vendor');
214
233
  const wrapperRoot = packageRoot('@openai/codex');
215
234
  if (wrapperRoot) {
216
- const localVendorRoot = path.join(wrapperRoot, 'vendor');
217
- if (fs.existsSync(localVendorRoot)) return localVendorRoot;
235
+ const nestedVendorRoot = existingPath(path.join(wrapperRoot, 'node_modules', target.packageName, 'vendor'));
236
+ if (nestedVendorRoot) return nestedVendorRoot;
237
+ const localVendorRoot = existingPath(path.join(wrapperRoot, 'vendor'));
238
+ if (localVendorRoot) return localVendorRoot;
218
239
  }
219
240
  return null;
220
241
  }
@@ -224,7 +245,8 @@ function bundledCodexBinary() {
224
245
  const vendorRoot = codexVendorRoot();
225
246
  if (target && vendorRoot) {
226
247
  const candidate = path.join(vendorRoot, target.triple, 'codex', target.binaryName);
227
- if (executableExists(candidate)) return candidate;
248
+ const binary = executablePath(candidate);
249
+ if (binary) return binary;
228
250
  }
229
251
  return packageBin('@openai/codex', 'codex');
230
252
  }
@@ -234,7 +256,8 @@ function bundledCodexPathDirs() {
234
256
  const vendorRoot = codexVendorRoot();
235
257
  if (!target || !vendorRoot) return [];
236
258
  const candidate = path.join(vendorRoot, target.triple, 'path');
237
- return executableExists(path.join(candidate, process.platform === 'win32' ? 'rg.exe' : 'rg')) ? [candidate] : [];
259
+ const rgPath = executablePath(path.join(candidate, process.platform === 'win32' ? 'rg.exe' : 'rg'));
260
+ return rgPath ? [path.dirname(rgPath)] : [];
238
261
  }
239
262
 
240
263
  function openCodePlatform() {
@@ -291,12 +314,14 @@ function bundledOpenCodeBinary() {
291
314
  const root = packageRoot(packageName);
292
315
  if (!root) continue;
293
316
  const candidate = path.join(root, 'bin', binaryName);
294
- if (executableExists(candidate)) return candidate;
317
+ const binary = executablePath(candidate);
318
+ if (binary) return binary;
295
319
  }
296
320
  const wrapperRoot = packageRoot('opencode-ai');
297
321
  if (wrapperRoot) {
298
322
  const cached = path.join(wrapperRoot, 'bin', '.opencode');
299
- if (executableExists(cached)) return cached;
323
+ const binary = executablePath(cached);
324
+ if (binary) return binary;
300
325
  }
301
326
  return packageBin('opencode-ai', 'opencode');
302
327
  }
@@ -340,12 +365,12 @@ function commandTargets() {
340
365
  {
341
366
  command: 'codex',
342
367
  name: 'Codex',
343
- path: packageBin('@openai/codex', 'codex') || bundledCodexBinary(),
368
+ path: bundledCodexBinary() || packageBin('@openai/codex', 'codex'),
344
369
  },
345
370
  {
346
371
  command: 'opencode',
347
372
  name: 'OpenCode',
348
- path: packageBin('opencode-ai', 'opencode') || bundledOpenCodeBinary(),
373
+ path: bundledOpenCodeBinary() || packageBin('opencode-ai', 'opencode'),
349
374
  },
350
375
  ];
351
376
  }