agent-browser-stealth 0.16.1-fork.1 → 0.16.1-fork.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/README.md CHANGED
@@ -81,7 +81,10 @@ Install once in Chrome: load unpacked extension from `extensions/tab-group-cdp/`
81
81
  - Download archive routing: downloads from managed tabs are routed to `agent-browser-stealth/<session>/...`.
82
82
  - Domain allowlist fallback: when allowlist is configured for a session, extension can force-block out-of-policy tabs to `about:blank`.
83
83
  - Risk hints (debug only): suspicious host/TLD hints are returned via handshake and printed only when `AGENT_BROWSER_DEBUG=1`.
84
- - Side panel console: view session/tab/group mapping, focus a session, keep only one session, clean empty groups, edit session allowlist, and toggle auto-clean.
84
+ - Side panel browser controls: open/back/forward/reload, click/fill/press by CSS selector, run shortcut commands, and switch/close tabs.
85
+ - Side panel developer signals: capture page console errors/warnings, fetch/xhr network events, command history, and live DOM snapshots.
86
+ - Workflow automation: record actions into workflows, run workflows, map workflows to slash shortcuts, and schedule runs (daily/weekly/monthly/yearly).
87
+ - Side panel operations console: view session/tab/group mapping, focus a session, keep only one session, clean empty groups, edit session allowlist, and toggle auto-clean.
85
88
 
86
89
  ## Stealth Architecture
87
90
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ /Users/leo/github.com/agent-browser/cli/target/release/agent-browser-stealth: /Users/leo/github.com/agent-browser/cli/build.rs /Users/leo/github.com/agent-browser/cli/cdp-protocol/browser_protocol.json /Users/leo/github.com/agent-browser/cli/cdp-protocol/js_protocol.json /Users/leo/github.com/agent-browser/cli/src/color.rs /Users/leo/github.com/agent-browser/cli/src/commands.rs /Users/leo/github.com/agent-browser/cli/src/connection.rs /Users/leo/github.com/agent-browser/cli/src/flags.rs /Users/leo/github.com/agent-browser/cli/src/install.rs /Users/leo/github.com/agent-browser/cli/src/main.rs /Users/leo/github.com/agent-browser/cli/src/main_stealth.rs /Users/leo/github.com/agent-browser/cli/src/output.rs /Users/leo/github.com/agent-browser/cli/src/validation.rs
Binary file
@@ -0,0 +1 @@
1
+ /Users/leo/github.com/agent-browser/cli/target/release/agent-browser: /Users/leo/github.com/agent-browser/cli/build.rs /Users/leo/github.com/agent-browser/cli/cdp-protocol/browser_protocol.json /Users/leo/github.com/agent-browser/cli/cdp-protocol/js_protocol.json /Users/leo/github.com/agent-browser/cli/src/color.rs /Users/leo/github.com/agent-browser/cli/src/commands.rs /Users/leo/github.com/agent-browser/cli/src/connection.rs /Users/leo/github.com/agent-browser/cli/src/flags.rs /Users/leo/github.com/agent-browser/cli/src/install.rs /Users/leo/github.com/agent-browser/cli/src/main.rs /Users/leo/github.com/agent-browser/cli/src/output.rs /Users/leo/github.com/agent-browser/cli/src/validation.rs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-browser-stealth",
3
- "version": "0.16.1-fork.1",
3
+ "version": "0.16.1-fork.3",
4
4
  "description": "Stealth browser automation CLI for AI agents with anti-bot evasions",
5
5
  "type": "module",
6
6
  "main": "dist/daemon.js",
@@ -27,7 +27,7 @@
27
27
  "build:windows": "npm run version:sync && docker compose -f docker/docker-compose.yml run --rm build-windows",
28
28
  "build:all-platforms": "npm run version:sync && (npm run build:linux & npm run build:windows & wait) && npm run build:macos",
29
29
  "build:docker": "docker build -t agent-browser-builder -f docker/Dockerfile.build .",
30
- "release": "npm run version:sync && npm run build && npm run build:all-platforms && npm publish",
30
+ "release": "npm run version:sync && npm run build && npm run build:all-platforms && npm run verify:bundled-binaries && npm run verify:native-version && npm publish",
31
31
  "start": "node dist/daemon.js",
32
32
  "dev": "tsx src/daemon.ts",
33
33
  "typecheck": "tsc --noEmit",
@@ -41,12 +41,16 @@
41
41
  "check:turnstile-testkey": "pnpm exec tsx scripts/check-turnstile-testkey.ts",
42
42
  "postinstall": "node scripts/postinstall.js",
43
43
  "verify:native-version": "node scripts/verify-native-version.js",
44
+ "verify:bundled-binaries": "node scripts/verify-bundled-binaries.js",
45
+ "verify:packed-host-binary": "node scripts/verify-packed-host-binary.js",
46
+ "verify:registry-host-binary": "node scripts/verify-registry-host-binary.js",
47
+ "prepublishOnly": "pnpm run verify:bundled-binaries && pnpm run verify:native-version && pnpm run verify:packed-host-binary",
44
48
  "clawhub:sync": "bash scripts/clawhub-sync.sh",
45
49
  "sync:upstream": "bash scripts/sync-upstream.sh",
46
50
  "sync:upstream:push": "bash scripts/sync-upstream.sh --push",
47
51
  "changeset": "changeset",
48
52
  "ci:version": "changeset version && pnpm run version:sync && pnpm install --no-frozen-lockfile",
49
- "ci:publish": "pnpm run version:sync && pnpm run build && pnpm run build:native && pnpm run verify:native-version && changeset publish"
53
+ "ci:publish": "pnpm run version:sync && pnpm run build && pnpm run build:native && pnpm run verify:bundled-binaries && pnpm run verify:native-version && pnpm run verify:packed-host-binary && changeset publish"
50
54
  },
51
55
  "keywords": [
52
56
  "browser",
@@ -2,19 +2,29 @@
2
2
 
3
3
  /**
4
4
  * Postinstall script for agent-browser
5
- *
5
+ *
6
6
  * Downloads the platform-specific native binary if not present.
7
7
  * On global installs, patches npm's bin entry to use the native binary directly:
8
8
  * - Windows: Overwrites .cmd/.ps1 shims
9
9
  * - Mac/Linux: Replaces symlink to point to native binary
10
10
  */
11
11
 
12
- import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync, writeFileSync, symlinkSync, lstatSync, readFileSync } from 'fs';
12
+ import {
13
+ existsSync,
14
+ mkdirSync,
15
+ chmodSync,
16
+ createWriteStream,
17
+ unlinkSync,
18
+ writeFileSync,
19
+ symlinkSync,
20
+ lstatSync,
21
+ readFileSync,
22
+ } from 'fs';
13
23
  import { dirname, join } from 'path';
14
24
  import { fileURLToPath } from 'url';
15
25
  import { platform, arch } from 'os';
16
26
  import { get } from 'https';
17
- import { execSync } from 'child_process';
27
+ import { execFileSync, execSync } from 'child_process';
18
28
 
19
29
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
30
  const projectRoot = join(__dirname, '..');
@@ -65,7 +75,7 @@ function getBinCommands(pkg) {
65
75
  async function downloadFile(url, dest) {
66
76
  return new Promise((resolve, reject) => {
67
77
  const file = createWriteStream(dest);
68
-
78
+
69
79
  const request = (url) => {
70
80
  get(url, (response) => {
71
81
  // Handle redirects
@@ -73,12 +83,12 @@ async function downloadFile(url, dest) {
73
83
  request(response.headers.location);
74
84
  return;
75
85
  }
76
-
86
+
77
87
  if (response.statusCode !== 200) {
78
88
  reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
79
89
  return;
80
90
  }
81
-
91
+
82
92
  response.pipe(file);
83
93
  file.on('finish', () => {
84
94
  file.close();
@@ -89,7 +99,7 @@ async function downloadFile(url, dest) {
89
99
  reject(err);
90
100
  });
91
101
  };
92
-
102
+
93
103
  request(url);
94
104
  });
95
105
  }
@@ -101,13 +111,21 @@ async function main() {
101
111
  if (platform() !== 'win32') {
102
112
  chmodSync(binaryPath, 0o755);
103
113
  }
104
- console.log(`✓ Native binary ready: ${binaryName}`);
105
-
106
- // On global installs, fix npm's bin entry to use native binary directly
107
- await fixGlobalInstallBin();
108
-
109
- showPlaywrightReminder();
110
- return;
114
+ const installedVersion = readBinaryVersion(binaryPath);
115
+ if (installedVersion.includes(version)) {
116
+ console.log(`✓ Native binary ready: ${binaryName}`);
117
+
118
+ // On global installs, fix npm's bin entry to use native binary directly
119
+ await fixGlobalInstallBin();
120
+
121
+ showPlaywrightReminder();
122
+ return;
123
+ }
124
+
125
+ console.log(
126
+ `⚠ Binary version mismatch detected: expected ${version}, got "${installedVersion || 'unknown'}"`
127
+ );
128
+ console.log(` Re-downloading ${binaryName} from release assets...`);
111
129
  }
112
130
 
113
131
  // Ensure bin directory exists
@@ -120,12 +138,19 @@ async function main() {
120
138
 
121
139
  try {
122
140
  await downloadFile(DOWNLOAD_URL, binaryPath);
123
-
141
+
124
142
  // Make executable on Unix
125
143
  if (platform() !== 'win32') {
126
144
  chmodSync(binaryPath, 0o755);
127
145
  }
128
-
146
+
147
+ const downloadedVersion = readBinaryVersion(binaryPath);
148
+ if (!downloadedVersion.includes(version)) {
149
+ throw new Error(
150
+ `downloaded binary version mismatch: expected ${version}, got "${downloadedVersion || 'unknown'}"`
151
+ );
152
+ }
153
+
129
154
  console.log(`✓ Downloaded native binary: ${binaryName}`);
130
155
  } catch (err) {
131
156
  console.log(`⚠ Could not download native binary: ${err.message}`);
@@ -143,6 +168,17 @@ async function main() {
143
168
  showPlaywrightReminder();
144
169
  }
145
170
 
171
+ function readBinaryVersion(path) {
172
+ try {
173
+ return execFileSync(path, ['--version'], {
174
+ encoding: 'utf8',
175
+ stdio: ['ignore', 'pipe', 'pipe'],
176
+ }).trim();
177
+ } catch {
178
+ return '';
179
+ }
180
+ }
181
+
146
182
  function showPlaywrightReminder() {
147
183
  console.log('');
148
184
  console.log('╔═══════════════════════════════════════════════════════════════════════════╗');
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Verifies that all bundled platform binaries are present and embed the
5
+ * package.json version string. This catches stale binary bundles where the
6
+ * package version is bumped but one or more binaries were not rebuilt.
7
+ */
8
+
9
+ import { existsSync, readFileSync, statSync } from "fs";
10
+ import { dirname, join } from "path";
11
+ import { fileURLToPath } from "url";
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const rootDir = join(__dirname, "..");
15
+
16
+ const pkg = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8"));
17
+ const expectedVersion = String(pkg.version || "").trim();
18
+
19
+ if (!expectedVersion) {
20
+ console.error("Error: package.json version is empty");
21
+ process.exit(1);
22
+ }
23
+
24
+ const expectedBinaries = [
25
+ "agent-browser-linux-x64",
26
+ "agent-browser-linux-arm64",
27
+ "agent-browser-win32-x64.exe",
28
+ "agent-browser-darwin-x64",
29
+ "agent-browser-darwin-arm64",
30
+ ];
31
+
32
+ const minSizeBytes = 100_000;
33
+ const versionBytes = Buffer.from(expectedVersion, "utf8");
34
+
35
+ let errors = 0;
36
+
37
+ for (const name of expectedBinaries) {
38
+ const binaryPath = join(rootDir, "bin", name);
39
+ if (!existsSync(binaryPath)) {
40
+ console.error(`ERROR: missing binary: bin/${name}`);
41
+ errors += 1;
42
+ continue;
43
+ }
44
+
45
+ const size = statSync(binaryPath).size;
46
+ if (size < minSizeBytes) {
47
+ console.error(
48
+ `ERROR: binary too small: bin/${name} (${size} bytes, expected >= ${minSizeBytes})`
49
+ );
50
+ errors += 1;
51
+ continue;
52
+ }
53
+
54
+ const bytes = readFileSync(binaryPath);
55
+ if (!bytes.includes(versionBytes)) {
56
+ console.error(
57
+ `ERROR: stale binary version: bin/${name} does not contain "${expectedVersion}"`
58
+ );
59
+ errors += 1;
60
+ continue;
61
+ }
62
+
63
+ console.log(`OK: bin/${name} matches version ${expectedVersion}`);
64
+ }
65
+
66
+ if (errors > 0) {
67
+ console.error(`\nFound ${errors} binary validation issue(s).`);
68
+ process.exit(1);
69
+ }
70
+
71
+ console.log(`\nAll bundled binaries match package.json version ${expectedVersion}.`);
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Build an npm tarball locally and verify that the bundled host-platform native
5
+ * binary reports the same version as package.json.
6
+ *
7
+ * This catches publish drifts where package.json is bumped but the embedded
8
+ * binary still points to an older fork version.
9
+ */
10
+
11
+ import { existsSync, mkdtempSync, readFileSync, rmSync, unlinkSync } from 'fs';
12
+ import { tmpdir } from 'os';
13
+ import { dirname, join } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import { execFileSync } from 'child_process';
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const rootDir = join(__dirname, '..');
19
+
20
+ const pkg = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8'));
21
+ const expectedVersion = String(pkg.version || '').trim();
22
+
23
+ if (!expectedVersion) {
24
+ console.error('Error: package.json version is empty');
25
+ process.exit(1);
26
+ }
27
+
28
+ const ext = process.platform === 'win32' ? '.exe' : '';
29
+ const hostBinaryName = `agent-browser-${process.platform}-${process.arch}${ext}`;
30
+
31
+ let tempDir = '';
32
+ let packedTarball = '';
33
+
34
+ try {
35
+ const packRaw = execFileSync('npm', ['pack', '--json'], {
36
+ cwd: rootDir,
37
+ encoding: 'utf8',
38
+ stdio: ['ignore', 'pipe', 'pipe'],
39
+ });
40
+ const parsed = JSON.parse(packRaw);
41
+ const filename = parsed?.[0]?.filename;
42
+ if (!filename || typeof filename !== 'string') {
43
+ throw new Error(`unexpected npm pack output: ${packRaw}`);
44
+ }
45
+
46
+ packedTarball = join(rootDir, filename);
47
+ if (!existsSync(packedTarball)) {
48
+ throw new Error(`tarball not found: ${packedTarball}`);
49
+ }
50
+
51
+ tempDir = mkdtempSync(join(tmpdir(), 'ab-pack-verify-'));
52
+ execFileSync('tar', ['-xzf', packedTarball, '-C', tempDir], {
53
+ stdio: ['ignore', 'pipe', 'pipe'],
54
+ });
55
+
56
+ const packedRoot = join(tempDir, 'package');
57
+ const packedPkg = JSON.parse(readFileSync(join(packedRoot, 'package.json'), 'utf8'));
58
+ if (String(packedPkg.version || '').trim() !== expectedVersion) {
59
+ throw new Error(
60
+ `packed package.json version mismatch: expected ${expectedVersion}, got ${packedPkg.version}`
61
+ );
62
+ }
63
+
64
+ const packedBinary = join(packedRoot, 'bin', hostBinaryName);
65
+ if (!existsSync(packedBinary)) {
66
+ throw new Error(`host binary missing in tarball: bin/${hostBinaryName}`);
67
+ }
68
+
69
+ const binaryVersion = execFileSync(packedBinary, ['--version'], {
70
+ encoding: 'utf8',
71
+ stdio: ['ignore', 'pipe', 'pipe'],
72
+ }).trim();
73
+
74
+ if (!binaryVersion.includes(expectedVersion)) {
75
+ throw new Error(
76
+ `tarball host binary version mismatch: expected ${expectedVersion}, got "${binaryVersion}"`
77
+ );
78
+ }
79
+
80
+ console.log(`✓ Packed tarball host binary matches package.json (${expectedVersion})`);
81
+ } catch (error) {
82
+ const message = error instanceof Error ? error.message : String(error);
83
+ console.error(`Error: ${message}`);
84
+ process.exitCode = 1;
85
+ } finally {
86
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
87
+ if (packedTarball && existsSync(packedTarball)) unlinkSync(packedTarball);
88
+ }
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Download the published npm tarball and verify that the bundled host-platform
5
+ * native binary reports the expected package version.
6
+ */
7
+
8
+ import { createWriteStream, existsSync, mkdtempSync, readFileSync, rmSync, unlinkSync } from 'fs';
9
+ import { tmpdir } from 'os';
10
+ import { dirname, join } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { execFileSync } from 'child_process';
13
+ import { get } from 'https';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const rootDir = join(__dirname, '..');
17
+
18
+ const pkg = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8'));
19
+ const packageName = process.env.PACKAGE_NAME || pkg.name || 'agent-browser-stealth';
20
+ const expectedVersion = process.env.EXPECTED_VERSION || pkg.version;
21
+
22
+ if (!expectedVersion) {
23
+ console.error('Error: expected version is empty');
24
+ process.exit(1);
25
+ }
26
+
27
+ const ext = process.platform === 'win32' ? '.exe' : '';
28
+ const hostBinaryName = `agent-browser-${process.platform}-${process.arch}${ext}`;
29
+
30
+ function downloadFile(url, dest) {
31
+ return new Promise((resolve, reject) => {
32
+ const file = createWriteStream(dest);
33
+
34
+ const request = (currentUrl) => {
35
+ get(currentUrl, (response) => {
36
+ if (response.statusCode === 301 || response.statusCode === 302) {
37
+ request(response.headers.location);
38
+ return;
39
+ }
40
+
41
+ if (response.statusCode !== 200) {
42
+ reject(new Error(`Failed to download tarball: HTTP ${response.statusCode}`));
43
+ return;
44
+ }
45
+
46
+ response.pipe(file);
47
+ file.on('finish', () => {
48
+ file.close();
49
+ resolve();
50
+ });
51
+ }).on('error', (err) => {
52
+ reject(err);
53
+ });
54
+ };
55
+
56
+ request(url);
57
+ });
58
+ }
59
+
60
+ let tempDir = '';
61
+ let tarballPath = '';
62
+
63
+ try {
64
+ const tarballUrl = execFileSync(
65
+ 'npm',
66
+ ['view', `${packageName}@${expectedVersion}`, 'dist.tarball'],
67
+ {
68
+ cwd: rootDir,
69
+ encoding: 'utf8',
70
+ stdio: ['ignore', 'pipe', 'pipe'],
71
+ }
72
+ ).trim();
73
+
74
+ if (!tarballUrl) {
75
+ throw new Error(`could not resolve dist.tarball for ${packageName}@${expectedVersion}`);
76
+ }
77
+
78
+ tempDir = mkdtempSync(join(tmpdir(), 'ab-registry-verify-'));
79
+ tarballPath = join(tempDir, 'package.tgz');
80
+ await downloadFile(tarballUrl, tarballPath);
81
+
82
+ execFileSync('tar', ['-xzf', tarballPath, '-C', tempDir], {
83
+ stdio: ['ignore', 'pipe', 'pipe'],
84
+ });
85
+
86
+ const packedRoot = join(tempDir, 'package');
87
+ const packedPkg = JSON.parse(readFileSync(join(packedRoot, 'package.json'), 'utf8'));
88
+ if (String(packedPkg.version || '').trim() !== expectedVersion) {
89
+ throw new Error(
90
+ `registry package.json version mismatch: expected ${expectedVersion}, got ${packedPkg.version}`
91
+ );
92
+ }
93
+
94
+ const packedBinary = join(packedRoot, 'bin', hostBinaryName);
95
+ if (!existsSync(packedBinary)) {
96
+ throw new Error(`host binary missing in registry tarball: bin/${hostBinaryName}`);
97
+ }
98
+
99
+ const binaryVersion = execFileSync(packedBinary, ['--version'], {
100
+ encoding: 'utf8',
101
+ stdio: ['ignore', 'pipe', 'pipe'],
102
+ }).trim();
103
+
104
+ if (!binaryVersion.includes(expectedVersion)) {
105
+ throw new Error(
106
+ `registry host binary version mismatch: expected ${expectedVersion}, got "${binaryVersion}"`
107
+ );
108
+ }
109
+
110
+ console.log(
111
+ `✓ Registry tarball host binary matches package.json (${packageName}@${expectedVersion})`
112
+ );
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ console.error(`Error: ${message}`);
116
+ process.exitCode = 1;
117
+ } finally {
118
+ if (tarballPath && existsSync(tarballPath)) unlinkSync(tarballPath);
119
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
120
+ }
@@ -286,7 +286,10 @@ Notes:
286
286
  - non-default session: `Agent Browser Stealth • <session>`
287
287
  - Additional extension-side capabilities:
288
288
  - Session window isolation + deterministic group colors.
289
- - Side panel controls: Focus / Keep Only This / Clean Empty Groups + isolation/auto-clean toggles.
289
+ - Side panel browser controls: `open` / `back` / `forward` / `reload` + selector-based `click` / `fill` / `press`.
290
+ - Side panel developer signals: page console events, fetch/xhr network events, command history, and on-demand DOM snapshots.
291
+ - Side panel automation: action recording, workflow run, slash shortcut binding, and scheduled execution (daily/weekly/monthly/yearly).
292
+ - Side panel operations: Focus / Keep Only This / Clean Empty Groups + isolation/auto-clean toggles.
290
293
  - Session allowlist policy editing and fallback blocking (`about:blank`).
291
294
  - Download auto-routing to `agent-browser-stealth/<session>/...`.
292
295