amalgm 0.1.109 → 0.1.110

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.109",
3
+ "version": "0.1.110",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -108,11 +108,11 @@ function agentBrowserCommand() {
108
108
  }
109
109
 
110
110
  function wantsHeaded() {
111
+ // CLI mode is the background/headless lane. A headed standalone browser is
112
+ // opt-in so searches and sub-agents do not open Chrome or steal focus.
111
113
  const explicit = process.env.AMALGM_BROWSER_HEADED || process.env.AGENT_BROWSER_HEADED;
112
- if (explicit) return !/^(0|false|no)$/i.test(explicit);
113
- if (/^(1|true|yes)$/i.test(process.env.AMALGM_BROWSER_HEADLESS || '')) return false;
114
- if (process.platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) return false;
115
- return true;
114
+ if (explicit) return /^(1|true|yes)$/i.test(explicit);
115
+ return false;
116
116
  }
117
117
 
118
118
  function baseArgs(session, json = true, cdp = null) {
@@ -18,6 +18,31 @@ function withoutBinOverride(fn) {
18
18
  }
19
19
  }
20
20
 
21
+ async function withBrowserEnv(overrides, fn) {
22
+ const keys = [
23
+ 'AMALGM_AGENT_BROWSER_BIN',
24
+ 'AMALGM_BROWSER_HEADED',
25
+ 'AGENT_BROWSER_HEADED',
26
+ 'AMALGM_BROWSER_HEADLESS',
27
+ ];
28
+ const saved = {};
29
+ for (const key of keys) {
30
+ saved[key] = process.env[key];
31
+ delete process.env[key];
32
+ }
33
+ for (const [key, value] of Object.entries(overrides)) {
34
+ if (value !== undefined) process.env[key] = value;
35
+ }
36
+ try {
37
+ return await fn();
38
+ } finally {
39
+ for (const key of keys) {
40
+ if (saved[key] === undefined) delete process.env[key];
41
+ else process.env[key] = saved[key];
42
+ }
43
+ }
44
+ }
45
+
21
46
  test('agent-browser spawns the native binary directly when it exists', () => {
22
47
  // The node wrapper exists only to pick a platform binary — spawning it adds
23
48
  // a node startup (~100ms) to every command, which is the verb floor latency.
@@ -39,6 +64,42 @@ test('agent-browser spawns the native binary directly when it exists', () => {
39
64
  }
40
65
  });
41
66
 
67
+ test('CLI browser sessions stay headless unless headed mode is explicit', async () => {
68
+ await withBrowserEnv({}, () => {
69
+ assert.equal(cli.wantsHeaded(), false);
70
+ });
71
+ await withBrowserEnv({ AMALGM_BROWSER_HEADED: '1' }, () => {
72
+ assert.equal(cli.wantsHeaded(), true);
73
+ });
74
+ await withBrowserEnv({ AGENT_BROWSER_HEADED: 'true' }, () => {
75
+ assert.equal(cli.wantsHeaded(), true);
76
+ });
77
+ await withBrowserEnv({ AMALGM_BROWSER_HEADED: 'false', AGENT_BROWSER_HEADED: 'true' }, () => {
78
+ assert.equal(cli.wantsHeaded(), false);
79
+ });
80
+ await withBrowserEnv({ AMALGM_BROWSER_HEADLESS: '1' }, () => {
81
+ assert.equal(cli.wantsHeaded(), false);
82
+ });
83
+ });
84
+
85
+ test('runCli does not pass --headed to background browser sessions by default', async () => {
86
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'amalgm-cli-headed-test-'));
87
+ const stub = path.join(dir, 'echo-argv.sh');
88
+ fs.writeFileSync(stub, '#!/bin/sh\nprintf "%s\\n" "$@"\n', { mode: 0o755 });
89
+ try {
90
+ await withBrowserEnv({ AMALGM_AGENT_BROWSER_BIN: stub }, async () => {
91
+ const result = await cli.runCli(['get', 'url'], { session: 'headless-test', json: false, timeoutMs: 5000 });
92
+ assert.equal(result.text.includes('--headed'), false);
93
+ });
94
+ await withBrowserEnv({ AMALGM_AGENT_BROWSER_BIN: stub, AMALGM_BROWSER_HEADED: '1' }, async () => {
95
+ const result = await cli.runCli(['get', 'url'], { session: 'headed-test', json: false, timeoutMs: 5000 });
96
+ assert.equal(result.text.includes('--headed'), true);
97
+ });
98
+ } finally {
99
+ fs.rmSync(dir, { recursive: true, force: true });
100
+ }
101
+ });
102
+
42
103
  test('runCli forwards stdin for batch JSON commands', async () => {
43
104
  // `batch` reads JSON command arrays from stdin — argv-quoting nested
44
105
  // commands is exactly how arguments got eaten in the wild.