chore: prepare fork sync and independent release setup

This commit is contained in:
leeguooooo
2026-02-24 14:14:50 +09:00
parent ecad112707
commit 955543b757
8 changed files with 210 additions and 17 deletions
+1 -1
View File
@@ -11,6 +11,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
id-token: write
jobs: jobs:
# Build native binaries for all platforms first # Build native binaries for all platforms first
@@ -219,7 +220,6 @@ jobs:
commit: 'chore: version packages' commit: 'chore: version packages'
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_VERCEL_TOKEN_ELEVATED }}
# Create GitHub release with binaries after npm publish # Create GitHub release with binaries after npm publish
github-release: github-release:
+39 -3
View File
@@ -51,7 +51,7 @@ agent-browser install # Download Chromium
### From Source ### From Source
```bash ```bash
git clone https://github.com/vercel-labs/agent-browser git clone https://github.com/leeguooooo/agent-browser
cd agent-browser cd agent-browser
pnpm install pnpm install
pnpm build pnpm build
@@ -60,6 +60,42 @@ pnpm link --global # Makes agent-browser available globally
agent-browser install agent-browser install
``` ```
### Fork Maintenance (Independent Release + Upstream Sync)
If you maintain a fork and publish your own CLI, use this workflow:
1. Keep an upstream-tracking branch (`upstream-main`) for clean sync history.
2. Keep your release branch (`main`) for production-ready code only.
3. Merge upstream into short-lived sync branches, then open PRs into `main`.
One-time setup:
```bash
git remote add upstream https://github.com/vercel-labs/agent-browser.git
git fetch upstream
```
Regular sync:
```bash
pnpm run sync:upstream:push
```
This command:
- Fetches `upstream/main`
- Fast-forwards local `upstream-main`
- Creates `sync/YYYY-MM-DD` from local `main`
- Merges `upstream-main` into the sync branch
- Pushes the sync branch to `origin` (with `sync:upstream:push`)
If merge conflicts occur, resolve them on the sync branch and open a PR as usual.
Independent release checklist for forks:
- Use your own npm package name and CLI binary name (avoid conflicts with upstream package ownership).
- Update `repository`, `bugs`, and `homepage` in `package.json` to your fork.
- Configure npm Trusted Publishing (OIDC) for your package and repository workflow.
- Keep release tags and changelog in your own namespace/versioning policy.
### Linux Dependencies ### Linux Dependencies
On Linux, install system dependencies: On Linux, install system dependencies:
@@ -971,7 +1007,7 @@ The `--help` output is comprehensive and most agents can figure it out from ther
Add the skill to your AI coding assistant for richer context: Add the skill to your AI coding assistant for richer context:
```bash ```bash
npx skills add vercel-labs/agent-browser npx skills add leeguooooo/agent-browser
``` ```
This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository, so it stays up to date automatically -- do not copy `SKILL.md` from `node_modules` as it will become stale. This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository, so it stays up to date automatically -- do not copy `SKILL.md` from `node_modules` as it will become stale.
@@ -981,7 +1017,7 @@ This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, O
Install as a Claude Code skill: Install as a Claude Code skill:
```bash ```bash
npx skills add vercel-labs/agent-browser npx skills add leeguooooo/agent-browser
``` ```
This adds the skill to `.claude/skills/agent-browser/SKILL.md` in your project. The skill teaches Claude Code the full agent-browser workflow, including the snapshot-ref interaction pattern, session management, and timeout handling. This adds the skill to `.claude/skills/agent-browser/SKILL.md` in your project. The skill teaches Claude Code the full agent-browser workflow, including the snapshot-ref interaction pattern, session management, and timeout handling.
+1 -1
View File
@@ -14,7 +14,7 @@ const DEFAULT_MODEL = "anthropic/claude-haiku-4.5";
const SYSTEM_PROMPT = `You are a helpful documentation assistant for agent-browser, a headless browser automation CLI designed for AI agents. const SYSTEM_PROMPT = `You are a helpful documentation assistant for agent-browser, a headless browser automation CLI designed for AI agents.
GitHub repository: https://github.com/vercel-labs/agent-browser GitHub repository: https://github.com/leeguooooo/agent-browser
Documentation: https://agent-browser.dev Documentation: https://agent-browser.dev
npm package: agent-browser npm package: agent-browser
+2 -2
View File
@@ -51,7 +51,7 @@ agent-browser install # Download Chromium
## From source ## From source
```bash ```bash
git clone https://github.com/vercel-labs/agent-browser git clone https://github.com/leeguooooo/agent-browser
cd agent-browser cd agent-browser
pnpm install pnpm install
pnpm build pnpm build
@@ -110,7 +110,7 @@ agent-browser works with any AI agent out of the box. For richer context:
Install the skill for your AI coding assistant: Install the skill for your AI coding assistant:
```bash ```bash
npx skills add vercel-labs/agent-browser npx skills add leeguooooo/agent-browser
``` ```
This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository and stays up to date automatically. This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository and stays up to date automatically.
+1 -1
View File
@@ -53,7 +53,7 @@ export function Header() {
</div> </div>
<nav className="flex items-center gap-4"> <nav className="flex items-center gap-4">
<a <a
href="https://github.com/vercel-labs/agent-browser" href="https://github.com/leeguooooo/agent-browser"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="hidden sm:flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors" className="hidden sm:flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
+5 -3
View File
@@ -33,6 +33,8 @@
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest", "test:watch": "vitest",
"postinstall": "node scripts/postinstall.js", "postinstall": "node scripts/postinstall.js",
"sync:upstream": "bash scripts/sync-upstream.sh",
"sync:upstream:push": "bash scripts/sync-upstream.sh --push",
"changeset": "changeset", "changeset": "changeset",
"ci:version": "changeset version && pnpm run version:sync && pnpm install --no-frozen-lockfile", "ci:version": "changeset version && pnpm run version:sync && pnpm install --no-frozen-lockfile",
"ci:publish": "pnpm run version:sync && pnpm run build && changeset publish" "ci:publish": "pnpm run version:sync && pnpm run build && changeset publish"
@@ -48,12 +50,12 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/vercel-labs/agent-browser.git" "url": "git+https://github.com/leeguooooo/agent-browser.git"
}, },
"bugs": { "bugs": {
"url": "https://github.com/vercel-labs/agent-browser/issues" "url": "https://github.com/leeguooooo/agent-browser/issues"
}, },
"homepage": "https://github.com/vercel-labs/agent-browser#readme", "homepage": "https://github.com/leeguooooo/agent-browser#readme",
"dependencies": { "dependencies": {
"node-simctl": "^7.4.0", "node-simctl": "^7.4.0",
"playwright-core": "^1.57.0", "playwright-core": "^1.57.0",
+19 -6
View File
@@ -9,7 +9,7 @@
* - Mac/Linux: Replaces symlink to point to native binary * - Mac/Linux: Replaces symlink to point to native binary
*/ */
import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync, writeFileSync, symlinkSync, lstatSync } from 'fs'; import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync, writeFileSync, symlinkSync, lstatSync, readFileSync } from 'fs';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { platform, arch } from 'os'; import { platform, arch } from 'os';
@@ -27,15 +27,28 @@ const binaryName = `agent-browser-${platformKey}${ext}`;
const binaryPath = join(binDir, binaryName); const binaryPath = join(binDir, binaryName);
// Package info // Package info
const packageJson = JSON.parse( const packageJson = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8'));
(await import('fs')).readFileSync(join(projectRoot, 'package.json'), 'utf8')
);
const version = packageJson.version; const version = packageJson.version;
// GitHub release URL // GitHub release URL
const GITHUB_REPO = 'vercel-labs/agent-browser'; const GITHUB_REPO = getGitHubRepoFromPackage(packageJson);
const DOWNLOAD_URL = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${binaryName}`; const DOWNLOAD_URL = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${binaryName}`;
function getGitHubRepoFromPackage(pkg) {
const repo = pkg?.repository;
const repoUrl = typeof repo === 'string' ? repo : repo?.url;
if (typeof repoUrl === 'string') {
const match = repoUrl.match(/github\.com[:/]([^/]+\/[^/.]+)(?:\.git)?$/i);
if (match?.[1]) {
return match[1];
}
}
// Fallback for legacy package metadata
return 'vercel-labs/agent-browser';
}
async function downloadFile(url, dest) { async function downloadFile(url, dest) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const file = createWriteStream(dest); const file = createWriteStream(dest);
@@ -107,7 +120,7 @@ async function main() {
console.log(''); console.log('');
console.log('To build the native binary locally:'); console.log('To build the native binary locally:');
console.log(' 1. Install Rust: https://rustup.rs'); console.log(' 1. Install Rust: https://rustup.rs');
console.log(' 2. Run: npm run build:native'); console.log(' 2. Run: pnpm run build:native');
} }
// On global installs, fix npm's bin entry to use native binary directly // On global installs, fix npm's bin entry to use native binary directly
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env bash
set -euo pipefail
UPSTREAM_REMOTE="upstream"
UPSTREAM_BRANCH="main"
BASE_BRANCH="main"
TRACK_BRANCH="upstream-main"
SYNC_BRANCH=""
PUSH_BRANCH=false
usage() {
cat <<'EOF'
Synchronize upstream changes into a dedicated sync branch.
Usage:
./scripts/sync-upstream.sh [options]
Options:
--push Push the created sync branch to origin
--upstream-remote <name> Upstream remote name (default: upstream)
--upstream-branch <name> Upstream branch to sync from (default: main)
--base-branch <name> Local base branch for sync branch (default: main)
--track-branch <name> Local branch tracking upstream (default: upstream-main)
--sync-branch <name> Explicit sync branch name (default: sync/YYYY-MM-DD)
-h, --help Show this help message
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--push)
PUSH_BRANCH=true
shift
;;
--upstream-remote)
UPSTREAM_REMOTE="${2:-}"
shift 2
;;
--upstream-branch)
UPSTREAM_BRANCH="${2:-}"
shift 2
;;
--base-branch)
BASE_BRANCH="${2:-}"
shift 2
;;
--track-branch)
TRACK_BRANCH="${2:-}"
shift 2
;;
--sync-branch)
SYNC_BRANCH="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
done
for var_name in UPSTREAM_REMOTE UPSTREAM_BRANCH BASE_BRANCH TRACK_BRANCH; do
if [[ -z "${!var_name}" ]]; then
echo "Error: ${var_name} cannot be empty." >&2
exit 1
fi
done
if [[ -n "$(git status --porcelain)" ]]; then
echo "Error: working tree is not clean. Commit or stash changes first." >&2
exit 1
fi
if ! git remote get-url "$UPSTREAM_REMOTE" >/dev/null 2>&1; then
echo "Error: remote '$UPSTREAM_REMOTE' does not exist." >&2
exit 1
fi
echo "Fetching upstream branch: ${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}"
git fetch "$UPSTREAM_REMOTE" "$UPSTREAM_BRANCH"
if git show-ref --verify --quiet "refs/heads/$TRACK_BRANCH"; then
echo "Updating local track branch: $TRACK_BRANCH"
git switch "$TRACK_BRANCH" >/dev/null
git merge --ff-only "${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}"
else
echo "Creating local track branch: $TRACK_BRANCH"
git branch "$TRACK_BRANCH" "${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}"
fi
echo "Switching to base branch: $BASE_BRANCH"
git switch "$BASE_BRANCH" >/dev/null
if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then
echo "Fast-forwarding ${BASE_BRANCH} from origin/${BASE_BRANCH}"
git fetch origin "$BASE_BRANCH"
git merge --ff-only "origin/${BASE_BRANCH}"
fi
if [[ -z "$SYNC_BRANCH" ]]; then
SYNC_BRANCH="sync/$(date +%F)"
fi
if git show-ref --verify --quiet "refs/heads/$SYNC_BRANCH"; then
suffix=1
while git show-ref --verify --quiet "refs/heads/${SYNC_BRANCH}-${suffix}"; do
suffix=$((suffix + 1))
done
SYNC_BRANCH="${SYNC_BRANCH}-${suffix}"
fi
echo "Creating sync branch: $SYNC_BRANCH"
git switch -c "$SYNC_BRANCH" "$BASE_BRANCH" >/dev/null
merge_message="chore(sync): merge ${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH} into ${BASE_BRANCH}"
echo "Merging $TRACK_BRANCH into $SYNC_BRANCH"
if ! git merge --no-ff "$TRACK_BRANCH" -m "$merge_message"; then
echo ""
echo "Merge conflict detected. Resolve conflicts, then run:"
echo " git add <resolved-files>"
echo " git commit"
if [[ "$PUSH_BRANCH" == true ]]; then
echo " git push -u origin $SYNC_BRANCH"
fi
exit 1
fi
echo "Upstream merge completed on branch: $SYNC_BRANCH"
if [[ "$PUSH_BRANCH" == true ]]; then
echo "Pushing branch to origin: $SYNC_BRANCH"
git push -u origin "$SYNC_BRANCH"
echo "Done. Open a PR: ${SYNC_BRANCH} -> ${BASE_BRANCH}"
else
echo "Branch is local only. Push when ready:"
echo " git push -u origin $SYNC_BRANCH"
fi