@orkestrel/scaffold 0.0.92 → 0.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/main.js +6 -6
- package/dist/bin/main.js.map +1 -1
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +4 -2
- package/dist/host/agents/skills/enterprise-bootstrap/references/responsive-layout.md +1 -1
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/statechart.md +1 -1
- package/dist/host/claude/agents/orkestrel.md +5 -5
- package/dist/host/claude/rules/styles.md +5 -0
- package/dist/host/dotfiles/oxlintrc.json +168 -0
- package/dist/host/guides/browser.md +94 -70
- package/dist/host/guides/mcp.md +15 -15
- package/dist/host/guides/pool.md +73 -48
- package/dist/host/guides/probe.md +262 -216
- package/dist/host/guides/router.md +1 -1
- package/dist/host/guides/worker.md +43 -7
- package/dist/host/manifest.json +15 -15
- package/dist/host/tests/config.test.ts +46 -3
- package/dist/src/core/index.cjs +6 -6
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.js +6 -6
- package/dist/src/core/index.js.map +1 -1
- package/package.json +6 -6
|
@@ -251,24 +251,24 @@ The following table lists the core constants.
|
|
|
251
251
|
|
|
252
252
|
Every error carries a machine-readable `code` and an optional `context` record, and each class has a guard. The following table lists the core errors and their guards.
|
|
253
253
|
|
|
254
|
-
| API | Kind | Summary
|
|
255
|
-
| --------------------------- | -------- |
|
|
256
|
-
| `BrowserError` | class | Represents the base error for all browser automation operations, carrying the code `BROWSER_ERROR` and a `context` record.
|
|
257
|
-
| `BrowserElementError` | class | Reports a refused element operation with a reason and, for `GONE`, the refresh directive.
|
|
258
|
-
| `isBrowserElementError` | function | Checks whether a value is an element refusal.
|
|
259
|
-
| `BrowserStepError` | class | Reports a journey step whose action did not complete, under the code `BROWSER_STEP_ERROR`, with the performed action in `action`.
|
|
260
|
-
| `isBrowserStepError` | function | Checks whether a value is a journey step error.
|
|
261
|
-
| `CDPError` | class | Reports that a CDP request received an error response from the remote endpoint, under the code `BROWSER_CDP_ERROR`, with the `method`, the CDP `code`, the `message`, and any `data` in its context.
|
|
262
|
-
| `CDPConnectionError` | class | Reports that a CDP request could not be sent or completed because the client was not
|
|
263
|
-
| `CDPTimeoutError` | class | Reports that a pending CDP request was not answered within its timeout window, under the code `BROWSER_CDP_TIMEOUT_ERROR`.
|
|
264
|
-
| `BrowserResultLimitError` | class | Reports that an `evaluate()`/`read()` result exceeded `BROWSER_RESULT_LIMIT` and was rejected in-page before it could overflow the CDP transport frame, under the code `BROWSER_RESULT_LIMIT_ERROR`.
|
|
265
|
-
| `isBrowserError` | function | Narrows an unknown value to a `BrowserError`.
|
|
266
|
-
| `isCDPError` | function | Narrows an unknown value to a `CDPError`.
|
|
267
|
-
| `isCDPConnectionError` | function | Narrows an unknown value to a `CDPConnectionError`.
|
|
268
|
-
| `isCDPTimeoutError` | function | Narrows an unknown value to a `CDPTimeoutError`.
|
|
269
|
-
| `isBrowserResultLimitError` | function | Narrows an unknown value to a `BrowserResultLimitError`.
|
|
270
|
-
| `BrowserConnectionError` | class | Reports that a CDP connection, discovery, or launch attempt failed, under the code `BROWSER_CONNECTION_ERROR`.
|
|
271
|
-
| `isBrowserConnectionError` | function | Narrows an unknown value to a `BrowserConnectionError`.
|
|
254
|
+
| API | Kind | Summary |
|
|
255
|
+
| --------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
256
|
+
| `BrowserError` | class | Represents the base error for all browser automation operations, carrying the code `BROWSER_ERROR` and a `context` record. |
|
|
257
|
+
| `BrowserElementError` | class | Reports a refused element operation with a reason and, for `GONE`, the refresh directive. |
|
|
258
|
+
| `isBrowserElementError` | function | Checks whether a value is an element refusal. |
|
|
259
|
+
| `BrowserStepError` | class | Reports a journey step whose action did not complete, under the code `BROWSER_STEP_ERROR`, with the performed action in `action`. |
|
|
260
|
+
| `isBrowserStepError` | function | Checks whether a value is a journey step error. |
|
|
261
|
+
| `CDPError` | class | Reports that a CDP request received an error response from the remote endpoint, under the code `BROWSER_CDP_ERROR`, with the `method`, the CDP `code`, the `message`, and any `data` in its context. |
|
|
262
|
+
| `CDPConnectionError` | class | Reports that a CDP request could not be sent or completed because the client was not connected, closed while connecting, lost its connection, or lost the request's target session, under the code `BROWSER_CDP_CONNECTION_ERROR`. |
|
|
263
|
+
| `CDPTimeoutError` | class | Reports that a pending CDP request was not answered within its timeout window, under the code `BROWSER_CDP_TIMEOUT_ERROR`. |
|
|
264
|
+
| `BrowserResultLimitError` | class | Reports that an `evaluate()`/`read()` result exceeded `BROWSER_RESULT_LIMIT` and was rejected in-page before it could overflow the CDP transport frame, under the code `BROWSER_RESULT_LIMIT_ERROR`. |
|
|
265
|
+
| `isBrowserError` | function | Narrows an unknown value to a `BrowserError`. |
|
|
266
|
+
| `isCDPError` | function | Narrows an unknown value to a `CDPError`. |
|
|
267
|
+
| `isCDPConnectionError` | function | Narrows an unknown value to a `CDPConnectionError`. |
|
|
268
|
+
| `isCDPTimeoutError` | function | Narrows an unknown value to a `CDPTimeoutError`. |
|
|
269
|
+
| `isBrowserResultLimitError` | function | Narrows an unknown value to a `BrowserResultLimitError`. |
|
|
270
|
+
| `BrowserConnectionError` | class | Reports that a CDP connection, discovery, or launch attempt failed, under the code `BROWSER_CONNECTION_ERROR`. |
|
|
271
|
+
| `isBrowserConnectionError` | function | Narrows an unknown value to a `BrowserConnectionError`. |
|
|
272
272
|
|
|
273
273
|
An error names its refusal in `code`. The following table lists every code that reaches a caller, the class that carries it, what throws it, and when.
|
|
274
274
|
|
|
@@ -276,7 +276,7 @@ An error names its refusal in `code`. The following table lists every code that
|
|
|
276
276
|
| ------------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
277
277
|
| `BROWSER_ERROR` | `BrowserError` | every face | An argument or option is invalid, a page, frame, handle, worker, or manager is closed or disconnected, a protocol payload is off-shape, a navigation fails or passes its timeout, or a refusal names no code of its own. |
|
|
278
278
|
| `BROWSER_CDP_ERROR` | `CDPError` | `CDPClient.send` and every call that sends through it | The remote endpoint answers a request with an error response. |
|
|
279
|
-
| `BROWSER_CDP_CONNECTION_ERROR` | `CDPConnectionError` | `CDPClient.send` and every call that sends through it | The client is not connected, closes while it connects,
|
|
279
|
+
| `BROWSER_CDP_CONNECTION_ERROR` | `CDPConnectionError` | `CDPClient.send` and every call that sends through it | The client is not connected, closes while it connects, loses its connection while a request is pending, or receives a detach event for the request's target session. |
|
|
280
280
|
| `BROWSER_CDP_TIMEOUT_ERROR` | `CDPTimeoutError` | `CDPClient.send` and every call that sends through it | A request is not answered within its timeout. |
|
|
281
281
|
| `BROWSER_RESULT_LIMIT_ERROR` | `BrowserResultLimitError` | `evaluate()` and `read()` in both placements, `readBrowserCapture`, and `readBrowserSnapshot` | A serialized result or capture is longer than `BROWSER_RESULT_LIMIT` characters, or a DOM snapshot holds more nodes than its limit. |
|
|
282
282
|
| `BROWSER_CONNECTION_ERROR` | `BrowserConnectionError` | `Browser.connect()`, `WebSocketCDPTransport`, and `SocketCDPTransport`; `fetchCDPTargets` returns it | A connection, discovery, or launch attempt fails, or a transport sends before it opens or after it closes. |
|
|
@@ -348,8 +348,7 @@ import {
|
|
|
348
348
|
try {
|
|
349
349
|
await element.click()
|
|
350
350
|
} catch (error) {
|
|
351
|
-
if (isBrowserElementError(error))
|
|
352
|
-
log(error.code, error.context) // { reason: 'OCCLUDED', … }
|
|
351
|
+
if (isBrowserElementError(error)) log(error.code, error.context) // { reason: 'OCCLUDED', … }
|
|
353
352
|
else if (isCDPError(error)) log(error.code, error.context)
|
|
354
353
|
else if (isCDPConnectionError(error)) log(error.code)
|
|
355
354
|
else if (isCDPTimeoutError(error)) log(error.code)
|
|
@@ -1053,6 +1052,7 @@ The following table lists the core types.
|
|
|
1053
1052
|
| `BrowserProxy` | interface | Describes proxy settings used when creating an isolated browser context. |
|
|
1054
1053
|
| `BrowserDownloadOptions` | interface | Describes the download policy for a browser context. |
|
|
1055
1054
|
| `BrowserContextOptions` | interface | Describes the options for creating and configuring an isolated browser context. |
|
|
1055
|
+
| `BrowserContextDisposal` | type | Records Chromium's disposal acknowledgement or the failure that left disposal unconfirmed. |
|
|
1056
1056
|
| `BrowserContextEventMap` | type | Maps the browser-context lifecycle events. |
|
|
1057
1057
|
| `BrowserJourneyBinding` | type | Binds a native action's string argument to a literal or to one declared parameter by name. |
|
|
1058
1058
|
| `BrowserJourneyParameter` | interface | Declares one parameter a journey takes: its default, or none when it is a secret. |
|
|
@@ -1164,6 +1164,8 @@ A page hands the navigation steps it accepts, typed by `BrowserNavigationEventMa
|
|
|
1164
1164
|
|
|
1165
1165
|
The Node runtime discovers a browser listening on a CDP port, attaches to it, or launches a Chromium-family process. The following fence probes, connects, and destroys.
|
|
1166
1166
|
|
|
1167
|
+
Every library launch, including `browse`, passes `--no-first-run`, `--no-default-browser-check`, `--disable-sync`, and `--disable-features=msImplicitSignin` alongside your launch arguments. On Edge, fresh automation profiles launch with sync off and implicit sign-in disabled, so they carry no Microsoft account, synced extensions, or synced settings. This behavior was measured on Windows with Edge 154.0.4258.53 on 2026-10-05. Sync stays off so account extensions cannot install during page imports and reset the browser's URL loader factories. The launcher merges every caller and library disabled feature into one `--disable-features=` switch, because Chromium reads only the last occurrence. Chrome and Chromium ignore the unknown Edge feature name.
|
|
1168
|
+
|
|
1167
1169
|
```ts
|
|
1168
1170
|
import { createBrowser } from '@orkestrel/browser/server'
|
|
1169
1171
|
|
|
@@ -1249,6 +1251,8 @@ The following table lists the server constants.
|
|
|
1249
1251
|
| `BROWSER_RUN_FILE` | const | Names the persisted run snapshot. |
|
|
1250
1252
|
| `BROWSER_RUN_DIRECTORY` | const | Names the journey directory holding its runs. |
|
|
1251
1253
|
| `BROWSER_SERVER_POOL_SIZE` | const | Sets the default number of warm browsers to 1. |
|
|
1254
|
+
| `BROWSER_SERVER_CONTEXTS` | const | Sets the default context capacity per browser, including the shared holder. |
|
|
1255
|
+
| `BROWSER_SERVER_CONTEXTS_LIMIT` | const | Limits context capacity to the largest measured per-browser count. |
|
|
1252
1256
|
| `BROWSER_SERVER_POOL_LIMIT` | const | Limits the number of warm browsers to 3. |
|
|
1253
1257
|
| `BROWSER_SERVER_RESTARTS` | const | Permits one failed refill before the next failure spends the bound. |
|
|
1254
1258
|
| `BROWSER_SERVER_RECORD` | const | Names the browser process record in each profile. |
|
|
@@ -1377,31 +1381,35 @@ if (found !== undefined) {
|
|
|
1377
1381
|
|
|
1378
1382
|
The following table lists the server types.
|
|
1379
1383
|
|
|
1380
|
-
| API | Kind | Summary
|
|
1381
|
-
| ------------------------------ | --------- |
|
|
1382
|
-
| `BrowserEngine` | type | Names a supported browser engine (raw CDP targets Chromium-family browsers only).
|
|
1383
|
-
| `BrowserConnection` | type | Names how the browser connection was established.
|
|
1384
|
-
| `BrowserStatus` | type | Names the lifecycle status of a browser wrapper.
|
|
1385
|
-
| `BrowserDiscoveryResult` | interface | Describes the result of passive browser discovery.
|
|
1386
|
-
| `SystemBrowserOptions` | interface | Describes the options overriding `findSystemBrowsers`'/`findSystemBrowser`'s candidate sources.
|
|
1387
|
-
| `SystemBrowser` | type | Represents one discovered browser executable on this machine.
|
|
1388
|
-
| `BrowserProfileRecord` | interface | Names the browser a browse profile serves, which a later start's sweep reads.
|
|
1389
|
-
| `BrowserProfileResult` | interface | Describes the resolved browser profile directory used for a Chromium-family launch.
|
|
1390
|
-
| `BrowserCDPOptions` | interface | Configures the CDP (Chrome DevTools Protocol) connection.
|
|
1391
|
-
| `BrowserEventMap` | type | Maps the events a `BrowserInterface` emits.
|
|
1392
|
-
| `BrowserOptions` | interface | Describes the options for creating a `Browser` instance.
|
|
1393
|
-
| `BrowserInterface` | interface | Wraps a browser with discovery, connection management, and lifecycle control.
|
|
1394
|
-
| `WebSocketCDPTransportOptions` | interface | Describes the options for creating a `WebSocketCDPTransport` instance.
|
|
1395
|
-
| `FileBrowserStoreOptions` | interface | Configures a file store: its root under the checkout and the listing cap.
|
|
1396
|
-
| `BrowserLaunchFunction` | type | Creates a browser a browse server connects while warming its pool.
|
|
1397
|
-
| `BrowserSlot` | interface | Holds one
|
|
1398
|
-
| `BrowserSlotWatch` | interface | Holds the listeners and resolver of one browser slot's loss watch.
|
|
1399
|
-
| `
|
|
1400
|
-
| `
|
|
1401
|
-
| `
|
|
1402
|
-
| `
|
|
1403
|
-
| `
|
|
1404
|
-
| `
|
|
1384
|
+
| API | Kind | Summary |
|
|
1385
|
+
| ------------------------------ | --------- | ----------------------------------------------------------------------------------------------- |
|
|
1386
|
+
| `BrowserEngine` | type | Names a supported browser engine (raw CDP targets Chromium-family browsers only). |
|
|
1387
|
+
| `BrowserConnection` | type | Names how the browser connection was established. |
|
|
1388
|
+
| `BrowserStatus` | type | Names the lifecycle status of a browser wrapper. |
|
|
1389
|
+
| `BrowserDiscoveryResult` | interface | Describes the result of passive browser discovery. |
|
|
1390
|
+
| `SystemBrowserOptions` | interface | Describes the options overriding `findSystemBrowsers`'/`findSystemBrowser`'s candidate sources. |
|
|
1391
|
+
| `SystemBrowser` | type | Represents one discovered browser executable on this machine. |
|
|
1392
|
+
| `BrowserProfileRecord` | interface | Names the browser a browse profile serves, which a later start's sweep reads. |
|
|
1393
|
+
| `BrowserProfileResult` | interface | Describes the resolved browser profile directory used for a Chromium-family launch. |
|
|
1394
|
+
| `BrowserCDPOptions` | interface | Configures the CDP (Chrome DevTools Protocol) connection. |
|
|
1395
|
+
| `BrowserEventMap` | type | Maps the events a `BrowserInterface` emits. |
|
|
1396
|
+
| `BrowserOptions` | interface | Describes the options for creating a `Browser` instance. |
|
|
1397
|
+
| `BrowserInterface` | interface | Wraps a browser with discovery, connection management, and lifecycle control. |
|
|
1398
|
+
| `WebSocketCDPTransportOptions` | interface | Describes the options for creating a `WebSocketCDPTransport` instance. |
|
|
1399
|
+
| `FileBrowserStoreOptions` | interface | Configures a file store: its root under the checkout and the listing cap. |
|
|
1400
|
+
| `BrowserLaunchFunction` | type | Creates a browser a browse server connects while warming its pool. |
|
|
1401
|
+
| `BrowserSlot` | interface | Holds one pooled browser and its exclusively owned profile. |
|
|
1402
|
+
| `BrowserSlotWatch` | interface | Holds the listeners and resolver of one browser slot's loss watch. |
|
|
1403
|
+
| `BrowserServerContext` | interface | Holds one prepared or assigned context generation and its downloads directory. |
|
|
1404
|
+
| `BrowserServerLease` | interface | Binds a holder generation to the exact browser lease reserved for its lifetime. |
|
|
1405
|
+
| `BrowserServerLoss` | interface | Records a lost generation's cause and its own last URL. |
|
|
1406
|
+
| `BrowserServerWatch` | interface | Holds page subscriptions for one prepared or assigned context generation. |
|
|
1407
|
+
| `BrowserMCPServerOptions` | interface | Configures the browse server. |
|
|
1408
|
+
| `BrowserServerToolName` | type | Names the server tools that manage independent browser holders. |
|
|
1409
|
+
| `BrowserServerHolder` | interface | Identifies one admitted browser lifetime independently of its current pool token. |
|
|
1410
|
+
| `BrowserServerCatalog` | interface | Describes the JSON catalog returned by the holder tools. |
|
|
1411
|
+
| `BrowserServerMirror` | interface | Binds shared catalog subscriptions to the exact generation that published them. |
|
|
1412
|
+
| `BrowserMCPServerInterface` | interface | Serves the browser vocabulary and the journey tools over MCP on stdio. |
|
|
1405
1413
|
|
|
1406
1414
|
### Browser
|
|
1407
1415
|
|
|
@@ -1670,7 +1678,7 @@ await context?.destroy() // local detach
|
|
|
1670
1678
|
|
|
1671
1679
|
Operations shared by a top-level page and an iframe document. Every asynchronous member takes a trailing `BrowserCallOptions` carrying `timeout` and `signal`. `evaluate` runs in the page's main world; `read` and the element managers run in one isolated world per document, which the page drops on `Runtime.executionContextDestroyed` and `Runtime.executionContextsCleared` and creates again on the next call. A child frame follows its attached out-of-process session when Chromium splits the frame into another target.
|
|
1672
1680
|
|
|
1673
|
-
A
|
|
1681
|
+
A page instruments frame sessions, workers, and popups before or while resuming them, resumes any other target at once, and releases a non-frame target reported by a frame session without instrumenting it. A context configures each page session's auto-attach with `waitForDebuggerOnStart: true`, and the page does the same on each out-of-process frame session, with an `iframe` filter, and on each popup it opens, so every target the page's auto-attach reaches attaches paused. For a frame session the page sends `Page.enable`, `Runtime.enable`, `Page.setLifecycleEventsEnabled`, and `Target.setAutoAttach` and then resumes the target with `Runtime.runIfWaitingForDebugger`. The first commit and load of a frame that moved into another process therefore arrive on its new session and carry the loader of the navigation that moved it: on Chromium 141, the new session reports `Page.frameNavigated` with that loader after the resume, the page session then reports the swap, and the new session reports `load` with the same loader. The page resumes an attached dedicated or shared worker after `Runtime.enable` replies and a popup after the popup's domains and network manager start. It resumes a service worker after queuing `Runtime.enable`; on Edge 154.0.4258.53, that reply waits for worker startup. On Edge 154.0.4258.53, a page's dedicated and shared workers start and answer messages under this setup; the dedicated worker attaches paused, while the shared worker runs without an attachment reported by the page session. The page emits `worker` only after `Runtime.enable` replies. A non-frame target reported by a frame session is resumed and detached through that reporting session without a `worker` event. A target the page cannot enable is resumed and then detached, because on Chromium 141 a paused target stays paused after a detach without a resume, so it does not run and its parent document does not reach `load`; the detach waits until the resume attempt settles through a reply, a refusal, the client's timeout, or the connection's close. The page reads a frame session's frame tree only when the attach named no `parentFrameId`, and then only for the frame's parent, URL, and name. [`tests/src/core/BrowserPage.test.ts`](../tests/src/core/BrowserPage.test.ts) pins the order of each step, and [`tests/service/browser.test.ts`](../tests/service/browser.test.ts) proves worker startup in Chromium.
|
|
1674
1682
|
|
|
1675
1683
|
| Method | Returns | Summary |
|
|
1676
1684
|
| ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -2341,18 +2349,18 @@ await browser.destroy() // terminates and awaits the owned process
|
|
|
2341
2349
|
|
|
2342
2350
|
#### `BrowserMCPServerInterface`
|
|
2343
2351
|
|
|
2344
|
-
Serves the browser vocabulary and the journey tools over MCP on stdio. The server warms its pool at start and
|
|
2352
|
+
Serves the browser vocabulary and the journey tools over MCP on stdio. The server warms its pool at start and places the shared holder and each holder `acquire` admits in its own isolated context on a validated pooled browser. Initialization and tool calls await setup; a lost browser is replaced within the pool's restart bound. Each launch creates an exclusive `ROOT/.profiles/PID-UUID/` profile and one prepared context. `tools/list` answers while warming. Adopted page tools are mirrored until withdrawn or the shared holder loses its browser.
|
|
2345
2353
|
|
|
2346
|
-
A disconnect
|
|
2354
|
+
A disconnect retires the browser and every holder context on it; a crash of a holder's current page replaces only that holder's context, and a background-page crash leaves the holder attached. Hand-out, per-call, and post-failure pings detect browsers that stopped answering. An interrupted failure answers `BROWSER_SERVER_UNRESOLVED`, a known success remains successful, and pending loss notes prefix the next string outcome on a successor or a refusal. Every pending loss is reported. Calls are never repeated, and replacement pages start at `about:blank`.
|
|
2347
2355
|
|
|
2348
2356
|
The end of input, `SIGINT`, and `SIGTERM` stop admission and destroy the pool. Teardown releases watch listeners, destroys each toolset before its browser, and rechecks recorded folders. Unconfirmed termination retains its slot; a stranded launch prevents further launches. A timed-out ping forces termination before teardown. On Linux, a root process launches with `--no-sandbox`; other launches keep the sandbox.
|
|
2349
2357
|
|
|
2350
|
-
| Method | Returns | Summary
|
|
2351
|
-
| --------- | --------------- |
|
|
2352
|
-
| `start` | `Promise<void>` | Serves stdio, sweeps the profiles ended servers left, warms the pool, and resolves after the shared holder
|
|
2353
|
-
| `destroy` | `Promise<void>` | Stops admission, tears down every browser, its toolset, and its profile, then rechecks the folders it answers for.
|
|
2358
|
+
| Method | Returns | Summary |
|
|
2359
|
+
| --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
2360
|
+
| `start` | `Promise<void>` | Serves stdio, sweeps the profiles ended servers left, warms the pool, and resolves after the shared holder consumes a prepared context on a warm browser; the legacy handshake and every tool call await the same setup. Rejects with `BROWSER_SERVER_UNAVAILABLE` when no browser can serve and with `BROWSER_TOOLSET_ENDED` after `destroy()`, and resolves when `destroy()` interrupts setup. |
|
|
2361
|
+
| `destroy` | `Promise<void>` | Stops admission, tears down every browser, its toolset, and its profile, then rechecks the folders it answers for. |
|
|
2354
2362
|
|
|
2355
|
-
The viewport option applies to every warmed browser,
|
|
2363
|
+
The viewport option applies to every warmed browser, refills included, and to every page and popup in each of its isolated contexts.
|
|
2356
2364
|
|
|
2357
2365
|
| Option | Type | Default | Behavior |
|
|
2358
2366
|
| ---------- | ----------------- | ---------------------------- | -------------------------------------------------------------------------------------------- |
|
|
@@ -3591,20 +3599,21 @@ The `browse` binary serves the vocabulary and the journey tools over MCP on stdi
|
|
|
3591
3599
|
- `BROWSE_HEADLESS`: `true`, `false`, `1`, or `0`. Default: `true`.
|
|
3592
3600
|
- `BROWSE_EXECUTABLE`: the path of the Chromium executable. Default: the browser `findSystemBrowser` finds.
|
|
3593
3601
|
- `BROWSE_READONLY`: `true`, `false`, `1`, or `0`; `true` refuses `record`, `save`, `edit`, and `forget`, and `replay` still writes runs. Default: `false`.
|
|
3594
|
-
- `BROWSE_POOL`: an integer from `1` through `3` setting the number of browsers the server keeps,
|
|
3595
|
-
- `
|
|
3602
|
+
- `BROWSE_POOL`: an integer from `1` through `3` setting the number of browsers the server keeps, with holder admission bounded separately by `BROWSE_CONTEXTS`; see [Run work in parallel](#run-work-in-parallel). Default: `1`.
|
|
3603
|
+
- `BROWSE_CONTEXTS`: an integer from `1` through `4` setting the number of contexts each browser holds, the shared holder's included; see [Run work in parallel](#run-work-in-parallel). Default: `2`.
|
|
3604
|
+
- `BROWSE_VIEWPORT`: positive integer dimensions in `WIDTHxHEIGHT` form, such as `390x844`. Applies to every page and popup on every browser, refills included. Default: the browser's launch default.
|
|
3596
3605
|
|
|
3597
|
-
A malformed value ends the process with exit code 1 and one line on standard error. Any other value of `BROWSE_HEADLESS` or `BROWSE_READONLY`, a `BROWSE_POOL` that is not an integer, and a malformed `BROWSE_VIEWPORT` write a `BROWSER_SERVER_ENVIRONMENT` line, such as `browse: BROWSER_SERVER_ENVIRONMENT: BROWSE_HEADLESS must be true, false, 1, or 0, not "sometimes"`. Viewport dimensions must be positive safe integers written as decimal digits with a lowercase `x` separator and no whitespace. An integer `BROWSE_POOL` outside `1` through `3` writes `browse: BROWSER_SERVER_OPTIONS: pool.size must be an integer from 1 through 3`. On Linux a server running as root launches Chromium with `--no-sandbox`, because Chromium refuses to start as root with its sandbox on.
|
|
3606
|
+
A malformed value ends the process with exit code 1 and one line on standard error. Any other value of `BROWSE_HEADLESS` or `BROWSE_READONLY`, a `BROWSE_POOL` or `BROWSE_CONTEXTS` that is not an integer, and a malformed `BROWSE_VIEWPORT` write a `BROWSER_SERVER_ENVIRONMENT` line, such as `browse: BROWSER_SERVER_ENVIRONMENT: BROWSE_HEADLESS must be true, false, 1, or 0, not "sometimes"`. Viewport dimensions must be positive safe integers written as decimal digits with a lowercase `x` separator and no whitespace. An integer `BROWSE_POOL` outside `1` through `3` writes `browse: BROWSER_SERVER_OPTIONS: pool.size must be an integer from 1 through 3`, and an integer `BROWSE_CONTEXTS` outside `1` through `4` writes `browse: BROWSER_SERVER_OPTIONS: pool.contexts must be an integer from 1 through 4`. On Linux a server running as root launches Chromium with `--no-sandbox`, because Chromium refuses to start as root with its sandbox on.
|
|
3598
3607
|
|
|
3599
|
-
Chromium starts when the server starts, before the client sends a request. The server launches its first browser, checks that it answers a CDP ping, and
|
|
3608
|
+
Chromium starts when the server starts, before the client sends a request. The server launches its first browser, checks that it answers a CDP ping, and places the shared holder, which the named tools drive, in that browser's prepared context. `initialize` and every tool call wait for that placement, and `ping` and `tools/list` answer while the browser warms. With `BROWSE_POOL` at `2` or `3`, the other browsers warm after the first, and `initialize` does not wait for them. A launch that fails is retried one time. The end of input or `SIGTERM` closes every browser and removes its profile, the process exits with code 0, and a run without a fault writes nothing to standard error.
|
|
3600
3609
|
|
|
3601
3610
|
A client gives a server a limited time to answer `initialize`. On 2026-10-03, Claude Code's documentation gave 30 s and connected servers in the background, the Codex configuration reference gave 10 s through `startup_timeout_sec`, and Cursor's documentation gave no limit; see [Claude Code's MCP documentation](https://code.claude.com/docs/en/mcp), [the Codex configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference), and [Cursor's MCP documentation](https://cursor.com/docs/context/mcp). On Windows 11 with Edge 154 on 2026-10-04, while a browser test suite ran beside it, the built binary answered `initialize` at most 2.07 s after its spawn at every `BROWSE_POOL` size, a leftover browser to sweep included. No client needs a longer startup timeout.
|
|
3602
3611
|
|
|
3603
|
-
Set `BROWSE_POOL` to `2` or `3` to keep
|
|
3612
|
+
Set `BROWSE_POOL` to `2` or `3` to keep more than one browser. Each browser warms with one prepared context, and `acquire` places a holder on the live browser with the fewest occupied contexts, so a browser that serves no holder takes the next one. After a browser loss, each holder that was on it recovers at its next call: in a free context on another browser, or after the replacement launch when no browser has a free context. Concurrent calls on one holder share its one recovery. At `1`, every recovery after a browser loss waits for the replacement launch. In the contexts measurement on Windows 11 with Edge 154.0.4258.53 on 2026-10-05, acquiring a context took 113 to 266 ms and relaunching a browser 980 to 1898 ms.
|
|
3604
3613
|
|
|
3605
|
-
When a holder
|
|
3614
|
+
When a holder loses its browser or its context, the shared holder's included, browse never repeats a call. A loss is the browser process exiting, its CDP connection dropping, or a CDP ping it fails before a call or after a failed one; a current-page renderer crash replaces only its holder's context, and a crashed background tab leaves the holder attached. The following list gives what each call answers around a loss:
|
|
3606
3615
|
|
|
3607
|
-
- A call after the loss runs
|
|
3616
|
+
- A call after the loss runs in a fresh context that starts at `about:blank`, and its text opens with a `BROWSER_SERVER_CRASH:` note that names the cause and the lost page's URL. An element reference from the lost page is refused.
|
|
3608
3617
|
- A call the loss interrupts answers `BROWSER_SERVER_UNRESOLVED:`: its outcome is unknown, and browse did not repeat it. Read the page before you repeat the call.
|
|
3609
3618
|
- A call that completed before the loss keeps its result, and the next call carries the note.
|
|
3610
3619
|
- A call that fails for its own reason on a live browser answers its plain failure, with no note.
|
|
@@ -3626,7 +3635,7 @@ When no browser starts at setup, the server refuses on each surface and keeps an
|
|
|
3626
3635
|
The server writes each diagnostic as one line on standard error in the form `browse: CODE: DETAIL`, where `CODE` is one of the following codes and `DETAIL` is the cause:
|
|
3627
3636
|
|
|
3628
3637
|
- `BROWSER_SERVER_LAUNCH`: a browser failed to start, and the pool retries it within its bound.
|
|
3629
|
-
- `BROWSER_SERVER_EXHAUSTED`: setup's warming or a call's acquire rejected with the pool's `create` error after the launch bound was spent; a
|
|
3638
|
+
- `BROWSER_SERVER_EXHAUSTED`: setup's warming or a call's acquire rejected with the pool's `create` error after the launch bound was spent; a browser warming after setup that spends the bound writes `BROWSER_SERVER_LAUNCH` lines without this line.
|
|
3630
3639
|
- `BROWSER_SERVER_UNAVAILABLE`: setup was refused, and the binary writes this line before it exits with code 1.
|
|
3631
3640
|
- `BROWSER_SERVER_TEARDOWN`: a browser's termination is unconfirmed or its teardown failed; its profile folder stays until the shutdown recheck, and a shutdown that meets it exits with code 1.
|
|
3632
3641
|
- `BROWSER_SERVER_SWEEP`: the sweep could not read the `.profiles` folder under `BROWSE_ROOT`, and the server serves without it.
|
|
@@ -3689,14 +3698,14 @@ On 2026-10-04, Claude Code 2.1.285 under `claude -p --mcp-config FILE --strict-m
|
|
|
3689
3698
|
|
|
3690
3699
|
### Run work in parallel
|
|
3691
3700
|
|
|
3692
|
-
Acquire a holder when work needs a
|
|
3701
|
+
Acquire a holder when work needs a context of its own beside the shared one, such as a subagent that checks a page while you drive another through the named tools. Each holder runs in its own isolated context on a pooled browser, with its own pages and downloads directory, so its calls run beside the shared holder's calls and beside every other holder's. The named tools, such as `navigate` and `look`, keep serving the shared holder unchanged.
|
|
3693
3702
|
|
|
3694
3703
|
The following list gives the holder tools that `BROWSER_SERVER_COPY` defines:
|
|
3695
3704
|
|
|
3696
3705
|
- `acquire { purpose }`: admits a holder and answers JSON with the server-minted `holder` id and its browser's `tools` catalog. The `purpose` text describes the work and names the holder in a capacity refusal. Hand the id to the agent that does the work.
|
|
3697
3706
|
- `execute { holder, name, arguments }`: runs the tool `name` from the holder's catalog with that tool's own arguments inside `arguments`, and answers what the tool answers.
|
|
3698
3707
|
- `tools { holder }`: lists the holder's catalog, including the page tools its current page registers.
|
|
3699
|
-
- `destroy { holder }`: ends the holder and
|
|
3708
|
+
- `destroy { holder }`: ends the holder and closes its context. A call still running on that holder answers `BROWSER_SERVER_UNRESOLVED:`, and a repeated `destroy` of the same holder succeeds again.
|
|
3700
3709
|
|
|
3701
3710
|
The following fence shows one holder from `acquire` to `destroy`, one request and the text of its answer per line, with the view after the receipt left out; `HOLDER_ID` stands for the id that `acquire` returns.
|
|
3702
3711
|
|
|
@@ -3711,17 +3720,32 @@ The following fence shows one holder from `acquire` to `destroy`, one request an
|
|
|
3711
3720
|
// <- Holder destroyed.
|
|
3712
3721
|
```
|
|
3713
3722
|
|
|
3714
|
-
`destroy`
|
|
3723
|
+
`destroy` closes the holder's context and removes its downloads directory, under `ROOT/.profiles/PID-UUID/contexts/GENERATION-UUID/downloads/`. Copy a file out before destroying its holder. The end of the server closes the shared holder's context and removes its downloads too.
|
|
3724
|
+
|
|
3725
|
+
A holder that `acquire` admits after a `destroy` starts on a clean slate, which is narrower than a fresh browser. Its context starts with no cookies, local or session storage, IndexedDB data, Cache Storage, service worker registration, HTTP cache entry, or permission override; with its own tabs, element references, and catalog; and with an empty downloads directory. The browser process stays and keeps the memory it holds. In the contexts measurement on Windows 11 with Edge 154.0.4258.53 on 2026-10-05, a browser's private memory rose from about 505 MiB to about 670 MiB over its first 5 context generations and then held through 30; a longer run might show more.
|
|
3726
|
+
|
|
3727
|
+
`BROWSE_POOL`, or `pool.size` for `BrowserMCPServer`, counts browsers. `BROWSE_CONTEXTS`, or `pool.contexts`, bounds contexts per browser. Admission is their product, with the shared holder counted; the defaults admit one named holder beside the shared holder. With `contexts: 1`, a size of `3` admits two named holders. At capacity, `acquire` answers immediately with `BROWSER_SERVER_BUSY:` and launches nothing; its text lists each holder by id and purpose, the shared holder as `shared (Shared browser)`, and tells the agent to destroy a holder it no longer needs or to call the named tools to share the shared browser. A holder that `destroy` is ending counts until its context disposal settles. An unknown or ended id answers `BROWSER_SERVER_HOLDER:` and never falls back to the shared holder.
|
|
3728
|
+
|
|
3729
|
+
A failure costs a context only to the holders it reaches, and each of them keeps its id. Each gets a fresh context at its own next call, which answers as the loss list in [Register the browse binary with Claude Code](#register-the-browse-binary-with-claude-code) gives. The following list gives the scope of each failure:
|
|
3730
|
+
|
|
3731
|
+
- A browser loss costs every holder on that browser its context, the shared holder's included. Each receives its own `BROWSER_SERVER_CRASH:` note on its next call, naming the URL its own page last showed.
|
|
3732
|
+
- Holders on another browser receive no note and keep their pages and web state.
|
|
3733
|
+
- A crash of a holder's current page costs only that holder's context. The browser and the other holders on it stay attached.
|
|
3734
|
+
- A call that either failure interrupts answers `BROWSER_SERVER_UNRESOLVED:`, and browse never repeats it.
|
|
3715
3735
|
|
|
3716
|
-
|
|
3736
|
+
Keep the default single browser. Set `BROWSE_POOL` to `2` only when a browser loss must leave some holders running: the holders on the surviving browser keep their pages, at the cost of a second idle browser. In the contexts measurement on Windows 11 with Edge 154.0.4258.53 on 2026-10-05, with one holder, a second browser added about 1 GiB of private memory, 2551 MiB against 1414 MiB, and two holders used 917 MiB as contexts on one browser against 1610 MiB on two browsers.
|
|
3717
3737
|
|
|
3718
|
-
|
|
3738
|
+
Replays of one journey run together across holders, each writing its own run. While a replay of a journey persists its run on any holder, `forget` of that journey answers `BROWSER_JOURNEY_LOCKED: Journey NAME is locked; call forget again.`, where `NAME` is the journey's name, and a replay that starts while `forget` runs answers the same refusal for `replay`.
|
|
3719
3739
|
|
|
3720
3740
|
The following list gives the limits of holders:
|
|
3721
3741
|
|
|
3722
|
-
- The
|
|
3723
|
-
-
|
|
3724
|
-
-
|
|
3742
|
+
- The confirmed defaults, `BROWSE_POOL` of `1` and `BROWSE_CONTEXTS` of `2`, admit one named holder beside the shared holder. The user confirmed them on 2026-10-05 from M1 (2026-10-05, library-level under a core-test load: 21.85 s at one context against 12.91 s at two) and M2 (2026-10-05, through the built binary on a quiet host: 49.73 s at one context against 29.72 s at two, with disjoint ranges). M2 did not establish a gain from two contexts to three.
|
|
3743
|
+
- Contexts isolate automation, not hostile tenants. Every holder on a browser runs in that browser's process, so drive pages that must not share a process from separate `browse` servers.
|
|
3744
|
+
- Browser relaunches have no bound while a holder uses the browser. A browser lost under a holder spends nothing from the launch bound, and the next grant of a browser restores the bound, so a browser that crashes under every holder's use relaunches at every call that meets the crash. At the default `BROWSE_POOL` of `1` the shared holder always uses the only browser, so a browser that fails every context creation or disposal relaunches the same way.
|
|
3745
|
+
- A renderer that hangs without crashing raises no loss. While its browser answers the CDP ping, a call that fails on the hung page answers its plain failure with no note and no launch, and the holder keeps that context until `destroy` or a later crash of its page.
|
|
3746
|
+
- With `BROWSE_HEADLESS=false`, a popup hides the page that opened it, and the hidden page's animation frames stop, so a click on that page can time out. In the contexts measurement on Windows 11 with Edge 154.0.4258.53 on 2026-10-05, headed clicks on a page behind a popup succeeded 3 of 9 times, and headless clicks 9 of 9. The visibility of every busy holder's page is proven in headless mode only.
|
|
3747
|
+
- `tools/list` mirrors only the shared holder's page tools. A holder's page tools appear only in the catalog that `acquire` and `tools` return, and run through `execute`.
|
|
3748
|
+
- A holder keeps its context until `destroy` or the end of the server, with no idle timeout. An abandoned holder costs one context and one place of capacity, and the `BROWSER_SERVER_BUSY:` text names it.
|
|
3725
3749
|
- Journey admission covers the holders of one server. A second `browse` process on the same root can still race a replay against `forget`.
|
|
3726
3750
|
- Codex asks approval for `execute` and `destroy`, because neither is advertised read-only, so under an approval policy that asks, every call a holder makes through `execute` prompts. `acquire` carries no read-only annotation either, and `tools` is advertised read-only.
|
|
3727
3751
|
|
package/dist/host/guides/mcp.md
CHANGED
|
@@ -5374,11 +5374,11 @@ the exact statement:
|
|
|
5374
5374
|
1. **doc ↔ source bijection.** Every `function` / `class` / `const` /
|
|
5375
5375
|
`interface` / `type` row in the `## Surface` tables (the core dispatch
|
|
5376
5376
|
tables and the `### HTTP transport` + `### WebSocket transport` + `### stdio
|
|
5377
|
-
transport` tables) is a real export of the mcp layer (`src/core` or
|
|
5377
|
+
transport` tables) is a real export of the mcp layer (`src/core` or
|
|
5378
5378
|
`src/server`), and every export of either appears as a Surface row —
|
|
5379
5379
|
exhaustive, both directions.
|
|
5380
5380
|
2. **JSON-RPC 2.0 envelope.** A `dispatch` response is always `{ jsonrpc:
|
|
5381
|
-
'2.0', … }` with exactly one of `result` / `error`. The success arm always
|
|
5381
|
+
'2.0', … }` with exactly one of `result` / `error`. The success arm always
|
|
5382
5382
|
carries an `id`, echoing the request's, because a result answers a request and
|
|
5383
5383
|
a request always has one. The error arm is the only arm whose `id` may be
|
|
5384
5384
|
missing, and it is then omitted — the member is absent from the envelope, never
|
|
@@ -5410,7 +5410,7 @@ transport` tables) is a real export of the mcp layer (`src/core` or
|
|
|
5410
5410
|
metadata, run through the same dispatcher, and are projected back unstamped — so
|
|
5411
5411
|
they inherit the modern engine's execution port, cancellation, bounds, and
|
|
5412
5412
|
validation rather than running beside them. `initialize` → `{ protocolVersion,
|
|
5413
|
-
capabilities: { tools: {} }, serverInfo: { name, version } }`, the version negotiated over the
|
|
5413
|
+
capabilities: { tools: {} }, serverInfo: { name, version } }`, the version negotiated over the
|
|
5414
5414
|
legacy subset only: the client's `params.protocolVersion` is echoed when it is a
|
|
5415
5415
|
supported legacy revision, and every other request — the modern `'2026-07-28'`,
|
|
5416
5416
|
an unsupported revision, a non-string, or an absent one — falls back to the
|
|
@@ -5435,7 +5435,7 @@ capabilities: { tools: {} }, serverInfo: { name, version } }`, the version negot
|
|
|
5435
5435
|
into a `success: false` result, the server adds no try/catch: that branch's
|
|
5436
5436
|
`error` maps to `{ content: [{ type: 'text', text: <error> }], isError: true }`;
|
|
5437
5437
|
a valued `success: true` branch maps to `{ content: [{ type: 'text', text:
|
|
5438
|
-
JSON.stringify(value) }], structuredContent: value }`, carrying the value unchanged
|
|
5438
|
+
JSON.stringify(value) }], structuredContent: value }`, carrying the value unchanged
|
|
5439
5439
|
alongside the backwards-compatible text. A value-less success retains the required
|
|
5440
5440
|
empty text block and omits `structuredContent`.
|
|
5441
5441
|
6. **One modern seam, subscriptions included, and `-32601` for anything off it.**
|
|
@@ -5469,7 +5469,7 @@ JSON.stringify(value) }], structuredContent: value }`, carrying the value unchan
|
|
|
5469
5469
|
carries the same stamp. Ending the consumer's producer closes gracefully when the
|
|
5470
5470
|
honoured filter omits `toolsListChanged`, with
|
|
5471
5471
|
`{ resultType: 'complete', _meta: { 'io.modelcontextprotocol/subscriptionId': id,
|
|
5472
|
-
… } }`. A stream honouring the tools family stays open until failure or signal abort.
|
|
5472
|
+
… } }`. A stream honouring the tools family stays open until failure or signal abort.
|
|
5473
5473
|
The request id is only stream identity: a later request does not supersede
|
|
5474
5474
|
an earlier one. The legacy method remains absent and answers `-32601`.
|
|
5475
5475
|
7. **`handle` maps the boundary failures.** A `JSON.parse` throw (malformed
|
|
@@ -5520,7 +5520,7 @@ JSON.stringify(value) }], structuredContent: value }`, carrying the value unchan
|
|
|
5520
5520
|
continuation, or principal — carrying the caught value the wire never sees; the
|
|
5521
5521
|
emitter isolates a listener throw, routing it
|
|
5522
5522
|
to its own `error` handler (the `error` option, surfaced as `(error,
|
|
5523
|
-
event)`, not a domain event) — so a buggy observer can never corrupt a
|
|
5523
|
+
event)`, not a domain event) — so a buggy observer can never corrupt a
|
|
5524
5524
|
dispatch, and a throwing `error` handler neither escapes nor recurses.
|
|
5525
5525
|
11. **doc ↔ source method bijection.** The `## Methods` tables list exactly
|
|
5526
5526
|
the public methods of each behavioral interface — `MCPServerInterface`,
|
|
@@ -5565,7 +5565,7 @@ event)`, not a domain event) — so a buggy observer can never corrupt a
|
|
|
5565
5565
|
own JSON-parse `try`/`catch`) and draws a sharp line: a TRANSPORT-level
|
|
5566
5566
|
failure — malformed JSON (`-32700`) or a parsed value that is not a
|
|
5567
5567
|
JSON-RPC request (`-32600`, narrowed with `parseJSONRPCMessage` + `'method'
|
|
5568
|
-
in request`, no `as`) — is HTTP **400** with a JSON-RPC error body carrying no
|
|
5568
|
+
in request`, no `as`) — is HTTP **400** with a JSON-RPC error body carrying no
|
|
5569
5569
|
`id` member. A legacy dispatch result — success or in-band JSON-RPC error — is
|
|
5570
5570
|
HTTP **200**. A modern result is **400** for `-32020` / `-32021` / `-32022`
|
|
5571
5571
|
/ `-32602`, **404** for `-32601`, and **200** otherwise; every notification
|
|
@@ -5620,7 +5620,7 @@ in request`, no `as`) — is HTTP **400** with a JSON-RPC error body carrying no
|
|
|
5620
5620
|
consumer-provided list.
|
|
5621
5621
|
13. **The client is the modern-only egress mirror (`src/core`).**
|
|
5622
5622
|
`createMCPClient({ transport, identity?, capabilities?, version?, timeout?,
|
|
5623
|
-
on? })` drives a remote server over an injected `MCPMessageTransportInterface`
|
|
5623
|
+
on? })` drives a remote server over an injected `MCPMessageTransportInterface`
|
|
5624
5624
|
(transport-abstract, like the server). `connect()` issues a modern
|
|
5625
5625
|
`server/discover` carrying `_meta` with the offered revision,
|
|
5626
5626
|
client capabilities, and client identity. It intersects the peer's
|
|
@@ -5708,9 +5708,9 @@ on? })` drives a remote server over an injected `MCPMessageTransportInterface`
|
|
|
5708
5708
|
`error` option, not a domain event). Consumers subscribe through `emitter.on`.
|
|
5709
5709
|
15. **The HTTP client transport drives a remote server over `fetch`
|
|
5710
5710
|
(`src/server`).** `createHTTPClientTransport({ url, headers?, fetch?,
|
|
5711
|
-
timeout? })` returns a `MCPMessageTransportInterface` whose `send` POSTs one
|
|
5711
|
+
timeout? })` returns a `MCPMessageTransportInterface` whose `send` POSTs one
|
|
5712
5712
|
JSON-serialized message to `url` with `content-type:
|
|
5713
|
-
application/json` and an `Accept` of both `application/json` and
|
|
5713
|
+
application/json` and an `Accept` of both `application/json` and
|
|
5714
5714
|
`text/event-stream` (plus any `headers`), then decodes the reply and
|
|
5715
5715
|
emits each carried `JSONRPCMessage` on the `message` event: an
|
|
5716
5716
|
`application/json` body is narrowed with `parseJSONRPCMessage`; a
|
|
@@ -5762,7 +5762,7 @@ application/json` and an `Accept` of both `application/json` and
|
|
|
5762
5762
|
(`upgradeRequestPath`) is not `options.path` (default `DEFAULT_MCP_PATH`),
|
|
5763
5763
|
the `Sec-WebSocket-Key` is absent, or the `Sec-WebSocket-Version` is not
|
|
5764
5764
|
`13`. Otherwise it claims (returns `true`): `createNodeWebSocket({
|
|
5765
|
-
socket, key, head, protocol })` (server mode → writes the `101` handshake,
|
|
5765
|
+
socket, key, head, protocol })` (server mode → writes the `101` handshake,
|
|
5766
5766
|
selecting the configured subprotocol only when the client's offer contains it,
|
|
5767
5767
|
and sends unmasked frames), wraps it in a `WebSocketServerTransport`, and
|
|
5768
5768
|
pumps — each inbound `JSONRPCMessage` that `isJSONRPCRequest` runs
|
|
@@ -5831,7 +5831,7 @@ socket, key, head, protocol })` (server mode → writes the `101` handshake,
|
|
|
5831
5831
|
(`src/server`).** `createMCPSession({ path?, ttl?, session?, clock?, origin?, keepalive? })`
|
|
5832
5832
|
returns a `MiddlewareHandler<TState>` (`TState extends MCPSessionState`)
|
|
5833
5833
|
that owns its own closure `Map<string, { session: MCPSession; touched:
|
|
5834
|
-
number; version: MCPVersion }>` — no dependency on `@orkestrel/middleware` and no shared
|
|
5834
|
+
number; version: MCPVersion }>` — no dependency on `@orkestrel/middleware` and no shared
|
|
5835
5835
|
session primitive; the store, mint, and validation are all native to
|
|
5836
5836
|
this package. Compose it with `router.use(createMCPSession())` in front
|
|
5837
5837
|
of a session-agnostic `createMCPRoutes(mcp)`; it owns its `path` (default
|
|
@@ -5875,7 +5875,7 @@ number; version: MCPVersion }>` — no dependency on `@orkestrel/middleware` and
|
|
|
5875
5875
|
the log under a monotone base36 event id (returned), evicting the oldest
|
|
5876
5876
|
past `capacity` + any entry older than the per-event TTL, and fans the
|
|
5877
5877
|
message out to every `attach`ed open stream as `stream.write({ id, data:
|
|
5878
|
-
JSON.stringify(message) })`. `session.replay(afterId)` returns every
|
|
5878
|
+
JSON.stringify(message) })`. `session.replay(afterId)` returns every
|
|
5879
5879
|
retained log entry strictly after `afterId` in append order — an unknown
|
|
5880
5880
|
/ evicted cursor replays nothing. The `createMCPSession` middleware
|
|
5881
5881
|
serves the resumable `GET {path}`: it validates the `mcp-session-id`
|
|
@@ -5999,7 +5999,7 @@ JSON.stringify(message) })`. `session.replay(afterId)` returns every
|
|
|
5999
5999
|
contract over native host APIs (`src/browser`).**
|
|
6000
6000
|
`createWebSocketClientTransport({ url, protocols? })` returns a
|
|
6001
6001
|
`MCPMessageTransportInterface` whose `start()` opens `new WebSocket(url,
|
|
6002
|
-
protocols)` and awaits the native `'open'` event (the RFC 6455 handshake
|
|
6002
|
+
protocols)` and awaits the native `'open'` event (the RFC 6455 handshake
|
|
6003
6003
|
is the host's concern; a connection failure — the native `'error'` event
|
|
6004
6004
|
while not yet `OPEN` — rejects `start()`); `send` writes each message as
|
|
6005
6005
|
one text frame once `OPEN`, queuing (in order) any message sent before —
|
|
@@ -6051,7 +6051,7 @@ protocols)` and awaits the native `'open'` event (the RFC 6455 handshake
|
|
|
6051
6051
|
(the implicit, portless channel — bound once, for the whole lifetime of
|
|
6052
6052
|
the returned handle, so a dedicated worker's very first portless message
|
|
6053
6053
|
needs no first-use setup), and registers one `scope.addEventListener(
|
|
6054
|
-
'message', …)` listener built by `createScopeMessageListener`. That one
|
|
6054
|
+
'message', …)` listener built by `createScopeMessageListener`. That one
|
|
6055
6055
|
listener handles every shape uniformly, per event, with no upfront
|
|
6056
6056
|
detection flag: `event.ports.length > 0` spawns a fresh
|
|
6057
6057
|
`createMessagePortTransport` + `bindServer` for that port (tracked for
|