Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ No vendored files in your repo, no version drift, no manual upgrades. Every Clau

Swap `required` for `optional` if you'd rather nudge teammates than block them.

### Advanced Linux Installation (Arch Linux, NixOS, etc.)

If you are using a non-Ubuntu Linux distribution, Playwright's pre-compiled Chromium binaries may fail to launch due to missing system libraries or sandbox constraints.

You can bypass the bundled browser download and use your system's native Chromium instead by installing it via your package manager and setting the environment variables:

```bash
# Arch Linux example
sudo pacman -S chromium

# Export variables before running setup
export GSTACK_SKIP_PLAYWRIGHT=1
export GSTACK_CHROMIUM_PATH="/usr/bin/chromium"
export CHROME_PATH="/usr/bin/chromium"

# Run setup
./setup
```

Make sure to add these exports to your `~/.bashrc` or `~/.zshrc` so Claude Code can locate your system browser during runtime execution.

### OpenClaw

OpenClaw spawns Claude Code sessions via ACP, so every gstack skill just works
Expand Down
3 changes: 3 additions & 0 deletions browse/src/browser-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,10 @@ export class BrowserManager {
}

this.browser = await chromium.launch({
//If GSTACK_CHROMIUM_PATH exist use executablePath, else undefined
executablePath: process.env.GSTACK_CHROMIUM_PATH || process.env.PLAYWRIGHT_CHROMIUM_HEADLESS_SHELL_EXECUTABLE_PATH || undefined,
headless: useHeadless,
args: process.env.GSTACK_SKIP_PLAYWRIGHT === '1' ? ['--no-sandbox', '--disable-setuid-sandbox'] : [],
// On Windows, Chromium's sandbox fails when the server is spawned through
// the Bun→Node process chain (GitHub #276). Disable it — local daemon
// browsing user-specified URLs has marginal sandbox benefit.
Expand Down
2 changes: 2 additions & 0 deletions browse/test/bridge-chromium-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ describe('bridge-chromium-e2e (codex F3)', () => {
});
httpFixture = await startHttpFixture('<html><body><h1 id="ok">via-bridge</h1></body></html>');
browser = await chromium.launch({
executablePath: process.env.GSTACK_CHROMIUM_PATH || undefined,
headless: true,
args: process.env.GSTACK_SKIP_PLAYWRIGHT === '1' ? ['--no-sandbox', '--disable-setuid-sandbox'] : [],
proxy: { server: `socks5://127.0.0.1:${bridge.port}` },
});
});
Expand Down
40 changes: 37 additions & 3 deletions setup
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,43 @@ if [ "$INSTALL_CODEX" -eq 1 ]; then
fi

ensure_playwright_browser() {
if [ "$IS_WINDOWS" -eq 1 ]; then
if [ "${GSTACK_SKIP_PLAYWRIGHT:-0}" = "1" ]; then
log "Skipping download step. Testing system Chromium instead..."
(
cd "$SOURCE_GSTACK_DIR"

# Force the Playwright library to be available locally without downloading Ubuntu browsers
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 bun add playwright --dev

echo "
const { chromium } = require('playwright');
(async () => {
try {
const browser = await chromium.launch({
executablePath: '${GSTACK_CHROMIUM_PATH:-/usr/bin/chromium}',
args: ['--no-sandbox', '--disable-setuid-sandbox', '--headless']
});
await browser.close();
console.log('Smoke test successfully completed!');
process.exit(0);
} catch (e) {
console.error('Error launching system Chromium:', e);
process.exit(1);
}
})();
" > test-chromium.js

bun test-chromium.js
local_exit_code=$?
rm -f test-chromium.js
return $local_exit_code
)
elif [ "$IS_WINDOWS" -eq 1 ]; then
# On Windows, Bun can't launch Chromium due to broken pipe handling
# (oven-sh/bun#4253). Use Node.js to verify Chromium works instead.
(
cd "$SOURCE_GSTACK_DIR"
node -e "const { chromium } = require('playwright'); (async () => { const b = await chromium.launch(); await b.close(); })()" 2>/dev/null
node -e "const { chromium } = require('playwright'); (async () => { const b = await chromium.launch(); await b.close(); })()"
)
else
(
Expand All @@ -220,6 +251,7 @@ ensure_playwright_browser() {
fi
}


# 1. Build browse binary if needed (smart rebuild: stale sources, package.json, lock)
NEEDS_BUILD=0
if [ ! -x "$BROWSE_BIN" ]; then
Expand Down Expand Up @@ -322,7 +354,9 @@ if [ "$INSTALL_OPENCODE" -eq 1 ] && [ "$NEEDS_BUILD" -eq 0 ]; then
fi

# 2. Ensure Playwright's Chromium is available
if ! ensure_playwright_browser; then
if [ "${GSTACK_SKIP_PLAYWRIGHT:-0}" = "1" ]; then
echo "Skipping Playwright browser check (GSTACK_SKIP_PLAYWRIGHT=1)"
elif ! ensure_playwright_browser; then
echo "Installing Playwright Chromium..."
(
cd "$SOURCE_GSTACK_DIR"
Expand Down