Skip to content

Commit b58622a

Browse files
committed
fix(version-check): use createRequire instead of require.resolve for ESM compat
docs: add versioning guidelines to AGENTS.md, CONTRIBUTING.md, and scaffold README - Fix require.resolve in readAdapterVersion — not available in ESM context - Add Versioning section to AGENTS.md: patch/minor/major rules for core + adapters - Add versioning + changeset workflow section to CONTRIBUTING.md - Update create-adapter scaffold: README now includes versioning section, correct package name (@browserkit-dev/adapter-*), and dynamic core version Made-with: Cursor
1 parent 5908439 commit b58622a

4 files changed

Lines changed: 116 additions & 17 deletions

File tree

AGENTS.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,45 @@ Durable facts and correction patterns for this workspace. Updated by continual-l
8080
- El Al scraper returns `ERR_ABORTED` when called concurrently with Israir — run the two scrapers sequentially to avoid
8181
- **Israir booking URL** format: `https://www.israir.co.il/he-IL/reservation/deal/searchFlight/abroadFlight?destCode=TLV&departDate=...&fNumbers=...&sessionId=...` — the `sessionId` is live-session-scoped and expires; cannot be reused outside the active browser session
8282
- **Verification preference**: use the adapter's own headless Patchright browser (not the cursor-ide-browser MCP) for rescue-flights verification — user stated strong preference ("I prefer it immensely")
83+
84+
## Versioning
85+
86+
### @browserkit-dev/core
87+
88+
Follows semver. During 0.x, treat minor bumps as potentially breaking for consumers.
89+
90+
- **patch** (`0.1.x`): bug fixes, log/doc changes, internal refactors with no public API change.
91+
- Examples: fix a crash in `waitUntil`, fix a typo in an error message, optimize `scrollContainer`.
92+
- Rule: **no adapter needs to change any code** after updating core.
93+
94+
- **minor** (`0.x.0`): new features, new optional fields on `SiteAdapter`, new exported utilities, new CLI commands.
95+
- Examples: add `withLoginFlow`, add `minCoreVersion?` to `SiteAdapter`, add `browserkit doctor`.
96+
- Rule: **existing adapters compile and run without changes** (purely additive).
97+
98+
- **major** (`x.0.0`): breaking changes — removed exports, renamed functions, required new fields on `SiteAdapter`, changed tool-call contracts.
99+
- Examples: rename `detectRateLimit``detectChallenge`, make `minCoreVersion` required, remove `scrollContainer`.
100+
- Rule: **at least one published adapter must change source code** to compile against the new version.
101+
102+
**Decision shortcut**: run `test-adapters.yml` after your change (or locally build each adapter against the new core). If all 5 pass without code changes → patch or minor. If any fails → major (or the failing adapter's peer dep range was already wrong).
103+
104+
### Adapter packages (`@browserkit-dev/adapter-*`)
105+
106+
Same semver rules, but "breaking" means "an MCP tool's public interface changed":
107+
108+
- **patch**: bug fix, selector update, scraping logic change — no tool name/input/output signature change.
109+
- **minor**: new tool added, new optional input field on an existing tool, new optional output field.
110+
- **major**: tool removed or renamed, required input field added, output field removed or type-changed.
111+
112+
### Changeset workflow (required for every PR that changes behavior)
113+
114+
```bash
115+
# In the monorepo (core changes)
116+
pnpm changeset
117+
118+
# In an adapter repo
119+
npx changeset
120+
```
121+
122+
When prompted: choose `patch` / `minor` / `major` per the rules above, then write a one-sentence user-facing summary (what changed for users, not how it was implemented). Commit the generated `.changeset/*.md` file in the same PR.
123+
124+
The Release GitHub Action handles version bumping and `npm publish` automatically when the changeset PR is merged to `main`.

CONTRIBUTING.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,27 @@ Scaffold a new adapter with:
9191
```bash
9292
npx @browserkit-dev/core create-adapter my-site
9393
```
94+
95+
---
96+
97+
## Versioning and releases
98+
99+
Versioning rules are documented in full in [AGENTS.md — Versioning](https://github.com/browserkit-dev/browserkit/blob/main/AGENTS.md#versioning). The short version:
100+
101+
| Change | Bump |
102+
|--------|------|
103+
| Bug fix, doc/log change, no API change | `patch` |
104+
| New feature, new optional API field | `minor` |
105+
| Removed/renamed export, required new field | `major` |
106+
107+
Every PR that changes behavior needs a **changeset** before merging:
108+
109+
```bash
110+
# Core monorepo
111+
pnpm changeset
112+
113+
# Adapter repos
114+
npx changeset
115+
```
116+
117+
Follow the prompts: choose `patch` / `minor` / `major`, write a one-line user-facing summary, and commit the generated `.changeset/*.md` file in the same PR. The Release GitHub Action bumps the version and publishes to npm automatically when the changeset PR merges to `main`.

packages/core/src/create-adapter.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,15 @@ describe("${name} adapter", () => {
264264
}
265265

266266
function readme(name: string): string {
267+
const coreVersion = readCoreVersion();
267268
return `# browserkit adapter: ${name}
268269
269-
A [browserkit](https://github.com/jzarecki/browserkit) adapter for ${name}.
270+
A [browserkit](https://github.com/browserkit-dev/browserkit) adapter for ${name}.
270271
271272
## Installation
272273
273274
\`\`\`bash
274-
pnpm add @browserkit-dev/core browserkit-adapter-${name}
275+
pnpm add @browserkit-dev/core @browserkit-dev/adapter-${name}
275276
\`\`\`
276277
277278
## Usage
@@ -283,7 +284,7 @@ import { defineConfig } from "@browserkit-dev/core";
283284
284285
export default defineConfig({
285286
adapters: {
286-
"browserkit-adapter-${name}": { port: 3847 },
287+
"@browserkit-dev/adapter-${name}": { port: 3847 },
287288
},
288289
});
289290
\`\`\`
@@ -308,5 +309,17 @@ pnpm install
308309
pnpm test
309310
pnpm run build
310311
\`\`\`
312+
313+
## Versioning
314+
315+
This adapter requires \`@browserkit-dev/core >= ${coreVersion}\` (declared via \`minCoreVersion\`).
316+
317+
Bump rules for this adapter:
318+
- **patch** — bug fix, selector update, no tool API change
319+
- **minor** — new tool added, new optional input/output field
320+
- **major** — tool removed or renamed, required input added, output type changed
321+
322+
Every PR that changes behavior should include a changeset (\`npx changeset\`).
323+
See [browserkit versioning guidelines](https://github.com/browserkit-dev/browserkit/blob/main/AGENTS.md#versioning) for the full rules.
311324
`;
312325
}

packages/core/src/version-check.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from "node:fs";
22
import { fileURLToPath } from "node:url";
33
import path from "node:path";
4+
import { createRequire } from "node:module";
45

56
/**
67
* Parse a semver string into [major, minor, patch] tuple.
@@ -47,26 +48,45 @@ export function readCoreVersion(): string {
4748
/**
4849
* Read a package.json version from a file path or npm package name.
4950
* Returns null if not found.
51+
*
52+
* For file paths: walks up from the given path to find the nearest package.json.
53+
* For npm package names: resolves the main entry via createRequire, then walks
54+
* up the directory tree to find the package.json whose "name" matches.
5055
*/
5156
export function readAdapterVersion(packageNameOrPath: string): string | null {
5257
try {
53-
let pkgJsonPath: string;
54-
5558
if (packageNameOrPath.startsWith("/") || packageNameOrPath.startsWith(".")) {
56-
// File path: look for package.json next to the dist file
57-
const dir = path.dirname(packageNameOrPath);
58-
// Try sibling package.json (e.g. dist/index.js → package.json one level up)
59-
pkgJsonPath = fs.existsSync(path.join(dir, "package.json"))
60-
? path.join(dir, "package.json")
61-
: path.join(dir, "..", "package.json");
62-
} else {
63-
// npm package: resolve from node_modules
64-
// Use require.resolve to find it regardless of cwd
65-
pkgJsonPath = require.resolve(`${packageNameOrPath}/package.json`);
59+
// File path: walk up at most 5 levels to find package.json
60+
let dir = path.dirname(packageNameOrPath);
61+
for (let i = 0; i < 5; i++) {
62+
const candidate = path.join(dir, "package.json");
63+
if (fs.existsSync(candidate)) {
64+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8")) as { version?: string };
65+
return pkg.version ?? null;
66+
}
67+
const parent = path.dirname(dir);
68+
if (parent === dir) break; // reached filesystem root
69+
dir = parent;
70+
}
71+
return null;
6672
}
6773

68-
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")) as { version?: string };
69-
return pkg.version ?? null;
74+
// npm package: use createRequire (ESM-safe) to resolve the main entry,
75+
// then walk up to find the package.json whose "name" matches.
76+
const require = createRequire(import.meta.url);
77+
const mainEntry = require.resolve(packageNameOrPath);
78+
let dir = path.dirname(mainEntry);
79+
while (true) {
80+
const candidate = path.join(dir, "package.json");
81+
if (fs.existsSync(candidate)) {
82+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8")) as { name?: string; version?: string };
83+
if (pkg.name === packageNameOrPath) return pkg.version ?? null;
84+
}
85+
const parent = path.dirname(dir);
86+
if (parent === dir) break; // reached filesystem root
87+
dir = parent;
88+
}
89+
return null;
7090
} catch {
7191
return null;
7292
}

0 commit comments

Comments
 (0)