Skip to content

Commit c1f4a32

Browse files
committed
chore: rename npm scope @browserkit@browserkit-dev
@browserkit org name unavailable on npm; @browserkit-dev matches GitHub org. Updates: packages/core, packages/adapter-hackernews, packages/adapter-linkedin, browserkit.config.js, README, ARCH, CONTRIBUTING, AGENTS, docs, E2E tests. Made-with: Cursor
1 parent bab4fa9 commit c1f4a32

27 files changed

Lines changed: 1131 additions & 72 deletions

.changeset/initial-release.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
2-
"@browserkit/core": minor
2+
"@browserkit-dev/core": minor
33
---
44

5-
Initial public release of @browserkit/core — the framework for building site-specific MCP servers over authenticated browser sessions.
5+
Initial public release of @browserkit-dev/core — the framework for building site-specific MCP servers over authenticated browser sessions.
66

77
Key features:
88
- `defineAdapter` / `SiteAdapter` interface for building adapters

.context/progress.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ All 3 adapters logged in and serving tools:
6464

6565
### Testing harness
6666

67-
Added `packages/harness` (`@browserkit/harness`) — shared test utilities:
67+
Added `packages/harness` (`@browserkit-dev/harness`) — shared test utilities:
6868
- `src/test-server.ts``createTestAdapterServer(adapter)`: spins up an isolated in-process adapter server on a dynamic port with a temp `dataDir` (avoids pidfile conflicts); cleans up on `stop()`.
6969
- `src/mcp-client.ts``createTestMcpClient(url)`: wraps `Client` + `StreamableHTTPClientTransport` from `@modelcontextprotocol/sdk`; provides `callTool`, `listTools`, `close`.
7070

@@ -91,7 +91,7 @@ Added `packages/harness` (`@browserkit/harness`) — shared test utilities:
9191
- CDP attach pattern: `chromium.connectOverCDP(cdpUrl)` → reuses authenticated session, `browser.disconnect()` leaves session alive
9292

9393
- Established monorepo with pnpm workspaces (`packages/core`, `packages/adapter-linkedin`)
94-
- Implemented `@browserkit/core`:
94+
- Implemented `@browserkit-dev/core`:
9595
- `types.ts` — full type system: `SiteAdapter`, `ToolDefinition`, `ToolResult` (text+image), `FrameworkConfig`, `SessionConfig`, `AdapterStatus`, `DaemonStatus`
9696
- `define-adapter.ts``defineAdapter()` with compile-time + runtime validation
9797
- `define-config.ts``defineConfig()` with security validation (non-localhost requires bearer token)
@@ -105,7 +105,7 @@ Added `packages/harness` (`@browserkit/harness`) — shared test utilities:
105105
- `cli.ts``start`, `login`, `status`, `config cursor`, `create-adapter` commands; startup banner with auth status
106106
- `create-adapter.ts` — standalone project scaffolding (package.json, tsconfig, selectors, index, tests, README)
107107
- `observability.ts``withObservability()` wrapping Playwright trace + screenshot + ARIA snapshot + timing log
108-
- Implemented `@browserkit/adapter-linkedin`:
108+
- Implemented `@browserkit-dev/adapter-linkedin`:
109109
- `selectors.ts` — named selector constants for feed, messaging, people search
110110
- `index.ts``defineAdapter()` with `isLoggedIn`, `get_feed`, `get_messages`, `search_people`
111111
- 23 tests passing across both packages (LockManager, RateLimiter, defineAdapter, SessionManager, LinkedIn adapter)

.cursor/hooks/state/continual-learning-index.json

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,84 @@
22
"version": 1,
33
"transcripts": {
44
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/7ff80e1e-d316-4cd1-9f0f-6dc4e044e981/7ff80e1e-d316-4cd1-9f0f-6dc4e044e981.jsonl": {
5-
"mtimeMs": 1774268759000,
5+
"mtimeMs": 1774268759958,
66
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
77
},
88
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/abb7fe3a-e2fb-4d6a-96c9-af2132261e36/abb7fe3a-e2fb-4d6a-96c9-af2132261e36.jsonl": {
9-
"mtimeMs": 1774276015000,
9+
"mtimeMs": 1774276015547,
1010
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
1111
},
1212
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/48c31d0a-13ce-4e19-88ec-0225ad4494ad/48c31d0a-13ce-4e19-88ec-0225ad4494ad.jsonl": {
13-
"mtimeMs": 1774280028000,
13+
"mtimeMs": 1774280028089,
1414
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
1515
},
1616
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/4abb768d-dfd3-4278-8f22-5f3ccfb3a959/4abb768d-dfd3-4278-8f22-5f3ccfb3a959.jsonl": {
17-
"mtimeMs": 1774281374000,
17+
"mtimeMs": 1774281374304,
1818
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
1919
},
2020
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/7110620f-271a-4db1-87b4-279c6adfcfb7/7110620f-271a-4db1-87b4-279c6adfcfb7.jsonl": {
21-
"mtimeMs": 1774286264000,
21+
"mtimeMs": 1774286264720,
2222
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
2323
},
2424
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/b82fce76-2196-4db3-9013-49280b49e97b/b82fce76-2196-4db3-9013-49280b49e97b.jsonl": {
25-
"mtimeMs": 1774286078000,
25+
"mtimeMs": 1774286078162,
2626
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
2727
},
2828
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/d7b149aa-4f29-4d71-9c3f-19e2c665da59/d7b149aa-4f29-4d71-9c3f-19e2c665da59.jsonl": {
29-
"mtimeMs": 1774286530000,
29+
"mtimeMs": 1774286530909,
3030
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
3131
},
3232
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/7b307ef7-47b9-4311-b527-3318ac9231d3/7b307ef7-47b9-4311-b527-3318ac9231d3.jsonl": {
33-
"mtimeMs": 1774301611000,
33+
"mtimeMs": 1774301611565,
3434
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
3535
},
3636
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/50512271-3552-41e1-88d4-9d4c141964c4/50512271-3552-41e1-88d4-9d4c141964c4.jsonl": {
37-
"mtimeMs": 1774303070000,
37+
"mtimeMs": 1774303070925,
3838
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
3939
},
4040
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/5e728ef6-2360-48b8-9a4d-e9f09b8932a6/5e728ef6-2360-48b8-9a4d-e9f09b8932a6.jsonl": {
41-
"mtimeMs": 1774305471000,
41+
"mtimeMs": 1774305471543,
4242
"lastProcessedAt": "2026-03-24T11:40:00.000Z"
4343
},
4444
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/4fba3f3f-9558-449e-a5e9-362f032f6611/4fba3f3f-9558-449e-a5e9-362f032f6611.jsonl": {
45-
"mtimeMs": 1774369653000,
45+
"mtimeMs": 1774369653273,
4646
"lastProcessedAt": "2026-03-25T00:00:00.000Z"
4747
},
4848
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/742cd137-f286-473f-b685-4441da6c55db/742cd137-f286-473f-b685-4441da6c55db.jsonl": {
49-
"mtimeMs": 1774390690000,
49+
"mtimeMs": 1774390690326,
5050
"lastProcessedAt": "2026-03-25T00:00:00.000Z"
5151
},
5252
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/031606d7-01ca-4b3e-bad0-274af5a9a931/031606d7-01ca-4b3e-bad0-274af5a9a931.jsonl": {
53-
"mtimeMs": 1774450242000,
53+
"mtimeMs": 1774450242566,
5454
"lastProcessedAt": "2026-03-25T16:00:00.000Z"
5555
},
5656
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/672ffd14-9bc9-4c91-9eb7-9759b40e8893/672ffd14-9bc9-4c91-9eb7-9759b40e8893.jsonl": {
57-
"mtimeMs": 1774522118000,
58-
"lastProcessedAt": "2026-03-26T00:00:00.000Z"
57+
"mtimeMs": 1774993795838,
58+
"lastProcessedAt": "2026-04-06T12:13:43.000Z"
5959
},
6060
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/d03e9a64-5187-4bee-88df-279763fa977e/d03e9a64-5187-4bee-88df-279763fa977e.jsonl": {
61-
"mtimeMs": 1774474691000,
61+
"mtimeMs": 1774474691329,
6262
"lastProcessedAt": "2026-03-26T00:00:00.000Z"
6363
},
6464
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/8511b06d-07c8-42f2-8f30-5b6762c2fdc6/8511b06d-07c8-42f2-8f30-5b6762c2fdc6.jsonl": {
65-
"mtimeMs": 1774523258000,
66-
"lastProcessedAt": "2026-03-26T00:00:00.000Z"
65+
"mtimeMs": 1774771011223,
66+
"lastProcessedAt": "2026-03-30T00:00:00.000Z"
6767
},
6868
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/9bec9e6f-a179-401c-90cc-6d64720fbfee/9bec9e6f-a179-401c-90cc-6d64720fbfee.jsonl": {
69-
"mtimeMs": 1774534587000,
70-
"lastProcessedAt": "2026-03-26T00:00:00.000Z"
69+
"mtimeMs": 1774769808531,
70+
"lastProcessedAt": "2026-03-30T00:00:00.000Z"
71+
},
72+
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/9e65043f-de65-4412-8de4-cb92e2d2d3be/9e65043f-de65-4412-8de4-cb92e2d2d3be.jsonl": {
73+
"mtimeMs": 1775071678450,
74+
"lastProcessedAt": "2026-04-06T12:13:43.000Z"
75+
},
76+
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/f11036f4-a422-48e7-8c20-aa5cf076678c/f11036f4-a422-48e7-8c20-aa5cf076678c.jsonl": {
77+
"mtimeMs": 1775120150582,
78+
"lastProcessedAt": "2026-04-06T12:13:43.000Z"
79+
},
80+
"/Users/jzarecki/.cursor/projects/Users-jzarecki-Projects-session-mcp/agent-transcripts/34f93a81-231f-4d19-918d-d81470065cf5/34f93a81-231f-4d19-918d-d81470065cf5.jsonl": {
81+
"mtimeMs": 1775477365853,
82+
"lastProcessedAt": "2026-04-06T12:13:43.000Z"
7183
}
7284
}
73-
}
85+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"version": 1,
3-
"lastRunAtMs": 1774534549568,
4-
"turnsSinceLastRun": 6,
5-
"lastTranscriptMtimeMs": 1774534549508,
6-
"lastProcessedGenerationId": "785251f5-f6dd-46fd-bd02-6b91246cd354",
3+
"lastRunAtMs": 1775586519300,
4+
"turnsSinceLastRun": 1,
5+
"lastTranscriptMtimeMs": 1775586519155,
6+
"lastProcessedGenerationId": "b4d4cc21-66b9-45ab-baf5-70cb33eb1d39",
77
"trialStartedAtMs": null
88
}

AGENTS.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Durable facts and correction patterns for this workspace. Updated by continual-l
55
## Project: browserkit
66

77
- Project is named **browserkit** — decided and final. npm scope is `@browserkit`. GitHub org is `browserkit-dev` (`browserkit` org was taken on GitHub, available on npm).
8-
- GitHub repos: `browserkit-dev/browserkit` (framework — `@browserkit/core` + `@browserkit/core/testing`), `browserkit-dev/adapter-hackernews`, `browserkit-dev/adapter-google-discover`, `browserkit-dev/adapter-linkedin` — all standalone public repos
8+
- GitHub repos: `browserkit-dev/browserkit` (framework — `@browserkit-dev/core` + `@browserkit-dev/core/testing`), `browserkit-dev/adapter-hackernews`, `browserkit-dev/adapter-google-discover`, `browserkit-dev/adapter-linkedin` — all standalone public repos
99
- Language is TypeScript, not Python
1010
- MCP transport is HTTP (`StreamableHTTPServerTransport`), not stdio — preferred for multi-agent deployment
1111
- Each adapter gets its own HTTP port; each connecting MCP client gets its own `McpServer + StreamableHTTPServerTransport` pair (per-session factory inside the HTTP handler). Shared state (browser, lock, rate limiter) lives outside the McpServer.
@@ -32,11 +32,11 @@ Durable facts and correction patterns for this workspace. Updated by continual-l
3232
- "Raw" Playwright access means exposing the CDP WebSocket URL (`wsEndpoint()`) of each adapter's browser — external agents (Claude Code, Cursor) attach to the already-authenticated session and write their own Playwright scripts via shell
3333
- The Playwright skill pattern: AI writes a script to `/tmp`, executes it via shell — primary approach for shell-capable clients (Cursor, Claude Code); opt-in `run_script` MCP tool planned for clients without shell access (Claude Desktop) — opt-in because Cursor/Claude Code already have shell, only Claude Desktop needs it
3434
- MCP resources use `page://${site}/snapshot` (site name dynamic) — user pushed back when the URI appeared to hardcode the adapter name
35-
- Testing utilities (`createTestAdapterServer`, `createTestMcpClient`) live at `@browserkit/core/testing` subpath — a separate harness package was explicitly rejected ("I don't think we need it, it should be in either adapter or in core")
35+
- Testing utilities (`createTestAdapterServer`, `createTestMcpClient`) live at `@browserkit-dev/core/testing` subpath — a separate harness package was explicitly rejected ("I don't think we need it, it should be in either adapter or in core")
3636
- Real Chrome (`channel: "chrome"`) is required for Google-based adapters — Playwright's bundled Chromium is blocked by Google's login with "This browser or app may not be secure". `isLoggedIn` must NOT navigate during login polling or it redirects the user away from the sign-in page.
3737
- Google Discover has NO infinite scroll in automated browser contexts — confirmed with Pixel 5, Pixel 7, both headless and watch mode, both `window.scrollBy` and `mouse.wheel`. ~10 articles is the practical ceiling per call. Do NOT mention this limitation in marketing content.
3838
- Patchright (drop-in Playwright replacement) **has been implemented** in core and all adapters — removes `Runtime.enable` CDP leak, `Console.enable` leak, and `--enable-automation` flag. Same API as Playwright; just change the import. `channel: "chrome"` still recommended on top of Patchright for Google-based adapters.
39-
- LinkedIn adapter was rebuilt 1:1 with `stickerdaniel/linkedin-mcp-server`: innerText + URL navigation (not DOM selectors), section-based architecture, 7 tools (`get_person_profile`, `get_company_profile`, `get_company_posts`, `search_people`, `search_jobs`, `get_job_details`, `get_feed`). `isAuthBlockerUrl` + `detectAuthBarrier` promoted to `@browserkit/core` as generic utilities.
39+
- LinkedIn adapter was rebuilt 1:1 with `stickerdaniel/linkedin-mcp-server`: innerText + URL navigation (not DOM selectors), section-based architecture, 7 tools (`get_person_profile`, `get_company_profile`, `get_company_posts`, `search_people`, `search_jobs`, `get_job_details`, `get_feed`). `isAuthBlockerUrl` + `detectAuthBarrier` promoted to `@browserkit-dev/core` as generic utilities.
4040
- CSS class selectors break on JS-heavy apps (LinkedIn proved this) — prefer `page.evaluate()` + ARIA-label walk-up from stable action buttons, or raw `innerText` extraction. This is now in the `create-adapter` scaffold template.
4141
- Framework navigates to `adapter.loginUrl` before calling `isLoggedIn()` when browser is at `about:blank` — adapters do NOT need to handle this themselves
4242
- `warm_up_browser()` (visiting google/wiki/github before login) was evaluated from stickerdaniel's code — decided as "nice to have" for first-time login, not adopted yet
@@ -55,7 +55,7 @@ Durable facts and correction patterns for this workspace. Updated by continual-l
5555
- Testing preference: all 4 layers (unit, scraping integration, MCP protocol, reliability) — user said "all of those" without hesitation; don't propose a subset
5656
- Bugs found during testing should be fixed inline ("fix issues on the go"), not deferred to a follow-up task
5757
- Adapter developers should minimize visible dependency on the framework — adapters should feel like standalone npm packages, not framework plugins
58-
- Documentation for AI agents building adapters is a first-class concern — README must include the full `SiteAdapter` interface, testing pattern (`@browserkit/core/testing`), and a link to the HN adapter as a reference
58+
- Documentation for AI agents building adapters is a first-class concern — README must include the full `SiteAdapter` interface, testing pattern (`@browserkit-dev/core/testing`), and a link to the HN adapter as a reference
5959
- Cursor uses `.cursor/mcp.json` for project-level MCP config; `.mcp.json` is the Claude Code format — these are different files serving different tools
6060
- E2E install tests are wanted: spin up a clean environment, install core + HN adapter, verify tools work, install Google Discover adapter, verify it starts but returns auth error (no login)
6161
- Squash CI fix commits to keep git history clean — user noticed multiple "fix CI" commits and asked to squash
@@ -74,6 +74,9 @@ Durable facts and correction patterns for this workspace. Updated by continual-l
7474
- Runs locally at port 52746; registered in `.cursor/mcp.json` as `"rescue-flights"` (local config only, not committed to monorepo)
7575
- **Israir tool**: `detailUrl`, `flightNumber`, and `departureTime` are only populated when `availableSeats > 0`; sold-out flights return empty strings for those fields
7676
- **Israir `buildDetail()` bug**: guard `if (!available || !price)` is overly strict — flights with seats but no price get no booking link; fix is to change to `if (!available)` (1-line change, zero risk)
77-
- **El Al tool**: always returns `flightNumber` and `departureTime` for all flights (including sold-out); never returns a `detailUrl` — no booking link field exists in El Al output
77+
- **El Al tool**: always returns `flightNumber` and `departureTime` for all flights (including sold-out); `detailUrl` links to the seat-availability page (`?d=0` from Israel / `?d=1` to Israel) — El Al booking pages all return 403 (session tokens required), so the availability page is the best accessible link
78+
- **El Al virtual scroll bug**: Angular virtual scroll recycles DOM nodes on scroll-back — must collect flight data incrementally *during* each scroll step (not after); single-pass post-scroll extraction returns only the currently-visible rows (~7 flights vs 168+ total)
7879
- **Coverage difference**: El Al covers the next 8 days only; Israir covers 30+ days ahead
7980
- El Al scraper returns `ERR_ABORTED` when called concurrently with Israir — run the two scrapers sequentially to avoid
81+
- **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
82+
- **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")

ARCH.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ browserkit is a local-first framework for building site-specific MCP servers ove
99
```
1010
browserkit/ # monorepo root
1111
├── packages/
12-
│ ├── core/ # @browserkit/core (published)
12+
│ ├── core/ # @browserkit-dev/core (published)
1313
│ │ └── src/
1414
│ │ ├── types.ts # SiteAdapter, ToolDefinition, FrameworkConfig
1515
│ │ ├── define-adapter.ts # defineAdapter() — type-safe adapter factory
@@ -24,9 +24,9 @@ browserkit/ # monorepo root
2424
│ │ ├── server.ts # orchestrator: load adapters, start servers
2525
│ │ ├── create-adapter.ts # scaffolding for new adapter packages
2626
│ │ └── cli.ts # start | login | status | config | create-adapter
27-
│ ├── adapter-linkedin/ # @browserkit/adapter-linkedin (reference impl)
28-
│ ├── adapter-hackernews/ # @browserkit/adapter-hackernews (demo adapter)
29-
│ └── harness/ # @browserkit/harness (test utilities, private)
27+
│ ├── adapter-linkedin/ # @browserkit-dev/adapter-linkedin (reference impl)
28+
│ ├── adapter-hackernews/ # @browserkit-dev/adapter-hackernews (demo adapter)
29+
│ └── harness/ # @browserkit-dev/harness (test utilities, private)
3030
│ └── src/
3131
│ ├── test-server.ts # createTestAdapterServer() — isolated in-process server
3232
│ └── mcp-client.ts # createTestMcpClient() — typed MCP HTTP test client

0 commit comments

Comments
 (0)