chore: prepare fork sync and independent release setup
This commit is contained in:
@@ -11,6 +11,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
# Build native binaries for all platforms first
|
||||
@@ -219,7 +220,6 @@ jobs:
|
||||
commit: 'chore: version packages'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_VERCEL_TOKEN_ELEVATED }}
|
||||
|
||||
# Create GitHub release with binaries after npm publish
|
||||
github-release:
|
||||
|
||||
@@ -51,7 +51,7 @@ agent-browser install # Download Chromium
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/vercel-labs/agent-browser
|
||||
git clone https://github.com/leeguooooo/agent-browser
|
||||
cd agent-browser
|
||||
pnpm install
|
||||
pnpm build
|
||||
@@ -60,6 +60,42 @@ pnpm link --global # Makes agent-browser available globally
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
```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.
|
||||
@@ -981,7 +1017,7 @@ This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, O
|
||||
Install as a Claude Code skill:
|
||||
|
||||
```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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
GitHub repository: https://github.com/vercel-labs/agent-browser
|
||||
GitHub repository: https://github.com/leeguooooo/agent-browser
|
||||
Documentation: https://agent-browser.dev
|
||||
npm package: agent-browser
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ agent-browser install # Download Chromium
|
||||
## From source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/vercel-labs/agent-browser
|
||||
git clone https://github.com/leeguooooo/agent-browser
|
||||
cd agent-browser
|
||||
pnpm install
|
||||
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:
|
||||
|
||||
```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.
|
||||
|
||||
@@ -53,7 +53,7 @@ export function Header() {
|
||||
</div>
|
||||
<nav className="flex items-center gap-4">
|
||||
<a
|
||||
href="https://github.com/vercel-labs/agent-browser"
|
||||
href="https://github.com/leeguooooo/agent-browser"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hidden sm:flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
|
||||
+5
-3
@@ -33,6 +33,8 @@
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"postinstall": "node scripts/postinstall.js",
|
||||
"sync:upstream": "bash scripts/sync-upstream.sh",
|
||||
"sync:upstream:push": "bash scripts/sync-upstream.sh --push",
|
||||
"changeset": "changeset",
|
||||
"ci:version": "changeset version && pnpm run version:sync && pnpm install --no-frozen-lockfile",
|
||||
"ci:publish": "pnpm run version:sync && pnpm run build && changeset publish"
|
||||
@@ -48,12 +50,12 @@
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vercel-labs/agent-browser.git"
|
||||
"url": "git+https://github.com/leeguooooo/agent-browser.git"
|
||||
},
|
||||
"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": {
|
||||
"node-simctl": "^7.4.0",
|
||||
"playwright-core": "^1.57.0",
|
||||
|
||||
+19
-6
@@ -9,7 +9,7 @@
|
||||
* - 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 { fileURLToPath } from 'url';
|
||||
import { platform, arch } from 'os';
|
||||
@@ -27,15 +27,28 @@ const binaryName = `agent-browser-${platformKey}${ext}`;
|
||||
const binaryPath = join(binDir, binaryName);
|
||||
|
||||
// Package info
|
||||
const packageJson = JSON.parse(
|
||||
(await import('fs')).readFileSync(join(projectRoot, 'package.json'), 'utf8')
|
||||
);
|
||||
const packageJson = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8'));
|
||||
const version = packageJson.version;
|
||||
|
||||
// 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}`;
|
||||
|
||||
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) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = createWriteStream(dest);
|
||||
@@ -107,7 +120,7 @@ async function main() {
|
||||
console.log('');
|
||||
console.log('To build the native binary locally:');
|
||||
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
|
||||
|
||||
Executable
+142
@@ -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
|
||||
Reference in New Issue
Block a user