browser-broker 0.1.0 → 0.3.1
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/.env.example +0 -16
- package/README.md +55 -23
- package/dist/package.json +3 -3
- package/dist/src/adapter/conformance/cases.js +138 -1
- package/dist/src/adapter/conformance/run.js +135 -0
- package/dist/src/adapter/conformance/service-subject.js +5 -1
- package/dist/src/browser/fake.js +69 -3
- package/dist/src/browser/real.js +23 -33
- package/dist/src/capture/tiers.js +53 -0
- package/dist/src/cli/adapter.js +37 -3
- package/dist/src/cli/commands.js +42 -1
- package/dist/src/cli/index.js +12 -1
- package/dist/src/cli/operations-commands.js +82 -4
- package/dist/src/cli/reconcile-command.js +90 -7
- package/dist/src/config/environment.js +0 -44
- package/dist/src/doctor/checks.js +64 -0
- package/dist/src/doctor/report.js +10 -1
- package/dist/src/service/arbitration.js +61 -0
- package/dist/src/service/bridge.js +148 -2
- package/dist/src/service/broker.js +52 -1
- package/dist/src/service/browser-session.js +147 -8
- package/dist/src/service/comparison.js +23 -5
- package/dist/src/service/operations/claim.js +63 -0
- package/dist/src/service/operations/pages.js +150 -5
- package/dist/src/service/operations/status.js +8 -0
- package/dist/src/service/pages.js +81 -0
- package/dist/src/service/reconcile.js +75 -3
- package/dist/src/service/runtime.js +26 -1
- package/dist/src/service/tabs.js +70 -0
- package/dist/src/tool/session.js +17 -4
- package/dist/src/tool/tools.js +162 -6
- package/package.json +3 -3
- package/RELEASES.md +0 -97
package/dist/src/tool/session.js
CHANGED
|
@@ -14,13 +14,26 @@ import { TOOLS_BY_NAME, TOOL_DEFINITIONS } from "./tools.js";
|
|
|
14
14
|
*
|
|
15
15
|
* Read once at module load rather than per handshake: it cannot change while
|
|
16
16
|
* the process runs, and a session serves one client.
|
|
17
|
+
*
|
|
18
|
+
* ── Why the read is allowed to fail ─────────────────────────────────────
|
|
19
|
+
*
|
|
20
|
+
* A missing or unreadable manifest must not take the surface down with it.
|
|
21
|
+
* This module is imported by the executable a client spawns, so a throw here
|
|
22
|
+
* happens *before* anything can be served and before the protocol exists to
|
|
23
|
+
* describe it — the client sees the process exit, not an error it can act on.
|
|
24
|
+
* Weighed against that, the cost of not knowing the version is a cosmetic
|
|
25
|
+
* field in one handshake.
|
|
26
|
+
*
|
|
27
|
+
* The command line degrades this way already, and by accident rather than by
|
|
28
|
+
* design: it reads the manifest inside the function behind `--version`, so
|
|
29
|
+
* every other command keeps working when the file is gone. Matching that
|
|
30
|
+
* behaviour deliberately is the point of the `catch` — the fallback is the
|
|
31
|
+
* same literal this constant held before it read anything.
|
|
17
32
|
*/
|
|
18
|
-
const manifest = await import('../../package.json', { with: { type: 'json' } });
|
|
33
|
+
const manifest = await import('../../package.json', { with: { type: 'json' } }).catch(() => undefined);
|
|
19
34
|
export const SERVER_INFO = {
|
|
20
35
|
name: 'browser-broker',
|
|
21
|
-
version: typeof manifest
|
|
22
|
-
? manifest.default.version
|
|
23
|
-
: '0.0.0',
|
|
36
|
+
version: typeof manifest?.default?.version === 'string' ? manifest.default.version : '0.0.0',
|
|
24
37
|
};
|
|
25
38
|
/**
|
|
26
39
|
* What `initialize` returns: the negotiated revision, what this server can
|
package/dist/src/tool/tools.js
CHANGED
|
@@ -1,5 +1,136 @@
|
|
|
1
1
|
import { OPERATION_NAMES } from "../adapter/operations.js";
|
|
2
2
|
import { BROWSER_CHOICE_GUIDANCE } from "../browser/driver.js";
|
|
3
|
+
/**
|
|
4
|
+
* The twelve tools, their descriptions, and their argument schemas.
|
|
5
|
+
*
|
|
6
|
+
* ── Surface area is a standing tax, and this file is where it is paid ────
|
|
7
|
+
*
|
|
8
|
+
* `SCHEMA.md` §3.1 opens with it: every description here sits in a connected
|
|
9
|
+
* session's context **on every turn**, whether or not anything calls the
|
|
10
|
+
* tool. Twelve descriptions is the whole agent-facing documentation of this
|
|
11
|
+
* service and it is also a per-turn cost on every session, so each one is
|
|
12
|
+
* written to be the shortest text that still prevents a wrong call.
|
|
13
|
+
*
|
|
14
|
+
* **The description is the only place a calling agent reliably reads.** Not
|
|
15
|
+
* `SCHEMA.md`, not a wiki, not a refusal it has not hit yet. So where a fact
|
|
16
|
+
* changes what a caller does — that `browser_status` is also the renew verb,
|
|
17
|
+
* that the browser choice has no default, that feedback needs no lease — the
|
|
18
|
+
* fact is in the description rather than only in the argument list.
|
|
19
|
+
*
|
|
20
|
+
* **`browser_sign_in`'s description is the strongest case of that rule, and
|
|
21
|
+
* the reason it reads as an instruction rather than a summary.** The failure
|
|
22
|
+
* it exists to end is a caller hitting a login wall and never learning it
|
|
23
|
+
* could ask — and **no refusal can reach that caller**, because it never
|
|
24
|
+
* makes a call to be refused. It abandons the task or fabricates a session
|
|
25
|
+
* instead, which is what 25 measured sessions did in a month. There is no
|
|
26
|
+
* second surface for that guidance to live on, so the description names the
|
|
27
|
+
* alternative outright, the way a refusal would.
|
|
28
|
+
*
|
|
29
|
+
* ── What is deliberately absent ─────────────────────────────────────────
|
|
30
|
+
*
|
|
31
|
+
* **There is no browser-scoped destructive verb, and there must never be
|
|
32
|
+
* one.** No close-browser, no kill-all, no restart. `SCHEMA.md` §3.13 makes
|
|
33
|
+
* that part of the contract rather than an omission: the administrative
|
|
34
|
+
* operations act on something every caller shares, so they are commands a
|
|
35
|
+
* person runs (§4.3, §5.4) and the ledger records that a person did.
|
|
36
|
+
* **The worst thing an agent can do through this surface is close its own
|
|
37
|
+
* tab**, and that ceiling is the reason this surface can be handed to an
|
|
38
|
+
* arbitrary caller at all.
|
|
39
|
+
*
|
|
40
|
+
* **`browser_sign_in` and `browser_sign_in_done` move a browser's state and
|
|
41
|
+
* do not breach that ceiling**, which is worth stating because they look like
|
|
42
|
+
* the exception. Both are keyed, and both act only on the lease that called
|
|
43
|
+
* them: the first takes the browser only when no *other* lease holds a tab on
|
|
44
|
+
* it, and the second is refused unless the calling lease is the one that
|
|
45
|
+
* asked — so a caller can neither interrupt somebody else's work nor end a
|
|
46
|
+
* person's sign-in command mid-password. The unkeyed pair that could do those
|
|
47
|
+
* things, `begin_sign_in` and `end_sign_in`, is deliberately not on this
|
|
48
|
+
* surface at all.
|
|
49
|
+
*
|
|
50
|
+
* `browser_tab_close` is absent for a second, separate reason (§3.1): it
|
|
51
|
+
* closed a caller's only tab while keeping the lease, producing a lease that
|
|
52
|
+
* owned nothing and still consumed budget. It is gone rather than deprecated,
|
|
53
|
+
* and it should not be reintroduced.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* What a capture can and cannot be trusted to show (§3.11).
|
|
57
|
+
*
|
|
58
|
+
* ── A picture is the one result a caller cannot check against itself ─────
|
|
59
|
+
*
|
|
60
|
+
* Every other operation here returns something self-describing: a claim
|
|
61
|
+
* returns a key, an evaluation returns a value, a refusal explains itself. A
|
|
62
|
+
* capture returns a path to an image, and **an image of a half-rendered page
|
|
63
|
+
* looks exactly like an image of a broken one.** There is no field in the
|
|
64
|
+
* result to distrust, so a caller has nothing to weigh the picture against —
|
|
65
|
+
* which makes a wrong conclusion from a capture both easy to reach and hard
|
|
66
|
+
* to notice.
|
|
67
|
+
*
|
|
68
|
+
* The consequence is not hypothetical, and it is what puts this text on the
|
|
69
|
+
* description rather than in a document: a field session captured a canvas
|
|
70
|
+
* before it had drawn, read the dark frame as the page's real appearance, and
|
|
71
|
+
* **reported a fault against an application that did not have one.** It was
|
|
72
|
+
* caught only because a second measurement happened to disagree — which is
|
|
73
|
+
* not a mechanism anything can rely on.
|
|
74
|
+
*
|
|
75
|
+
* ── Why settling does not already cover this ─────────────────────────────
|
|
76
|
+
*
|
|
77
|
+
* Every capture settles the page first, and settling is worth exactly what
|
|
78
|
+
* §3.11 claims: it stops animations and transitions, hides the caret, and
|
|
79
|
+
* waits for web fonts, so the same page yields the same pixels run to run.
|
|
80
|
+
* **That is repeatability, not completeness.** It makes a moving page hold
|
|
81
|
+
* still; it cannot make an unfinished page finish. A canvas that has not
|
|
82
|
+
* drawn its first frame is not moving — it is absent — and holding it still
|
|
83
|
+
* is not the same as waiting for it.
|
|
84
|
+
*
|
|
85
|
+
* ── Why this names a check rather than a duration ────────────────────────
|
|
86
|
+
*
|
|
87
|
+
* The tempting sentence is *"allow the page to settle first"*, and it is
|
|
88
|
+
* advice a caller cannot act on: **the right wait is a property of the page,
|
|
89
|
+
* not of this service**, and a caller that has never seen the page rendered
|
|
90
|
+
* has no way to pick a number. Any figure written here would be wrong for
|
|
91
|
+
* some page and would be trusted anyway, which is worse than saying nothing.
|
|
92
|
+
*
|
|
93
|
+
* So the guidance is a **check** instead — capture twice and compare, which
|
|
94
|
+
* this tool can already express through `compare_to`. A caller can act on it
|
|
95
|
+
* without knowing anything about the page in advance, and it answers the
|
|
96
|
+
* question actually being asked, which is not *"has enough time passed"* but
|
|
97
|
+
* *"has this stopped changing"*. Two identical frames are evidence; one frame
|
|
98
|
+
* and a duration are an assumption.
|
|
99
|
+
*/
|
|
100
|
+
const CAPTURE_SETTLE_CAVEAT = 'Captures are settled — animations stopped, fonts waited for — so a page yields the same ' +
|
|
101
|
+
'pixels twice; that steadies a moving page but does not wait for one still drawing. A canvas ' +
|
|
102
|
+
'or a deferred region can be captured before it has rendered, and the picture will look like a ' +
|
|
103
|
+
'broken page rather than an early one. When a frame looks wrong, capture again with compare_to ' +
|
|
104
|
+
'and check it against the first: no difference means you are seeing the page, not a moment of it.';
|
|
105
|
+
/**
|
|
106
|
+
* What this tool's unit is wrong for, so a caller with the other job does not
|
|
107
|
+
* reach for it anyway.
|
|
108
|
+
*
|
|
109
|
+
* ── The distinction this exists to draw ──────────────────────────────────
|
|
110
|
+
*
|
|
111
|
+
* `compare_to` answers *"did this page change since a moment ago, on this
|
|
112
|
+
* same tab"* — a before-and-after over time, one lease, one running build.
|
|
113
|
+
* That is a different question from *"how do these two builds differ"*,
|
|
114
|
+
* where the two things being compared are not two moments of one tab but two
|
|
115
|
+
* separate runs, often of separate processes. This surface's unit is one
|
|
116
|
+
* lease holding one tab, which is the right shape for the first question and
|
|
117
|
+
* the wrong one for the second: a two-build comparison wants something that
|
|
118
|
+
* reads the scene or the DOM directly, not pixels from whichever tab happened
|
|
119
|
+
* to be open.
|
|
120
|
+
*
|
|
121
|
+
* ── Why this is worth a sentence rather than leaving it to be inferred ────
|
|
122
|
+
*
|
|
123
|
+
* A caller framing its task as "compare two builds" will reach for whatever
|
|
124
|
+
* on this surface has the word "compare" in it, and `compare_to` is the only
|
|
125
|
+
* candidate. Nothing here refuses that call — a diff still runs and still
|
|
126
|
+
* answers a real question about the two pixels it was given — so the caller
|
|
127
|
+
* gets an answer that looks like the one it asked for while measuring
|
|
128
|
+
* something else. A routing hint at the point of the call is the only thing
|
|
129
|
+
* that can catch this before the wrong tool is already in use; there is no
|
|
130
|
+
* refusal to word better; the call succeeds.
|
|
131
|
+
*/
|
|
132
|
+
const CAPTURE_BUILD_COMPARISON_CAVEAT = 'For comparing two builds — not two moments of the one tab you hold — a tool reading the scene ' +
|
|
133
|
+
'or DOM directly beats this one: this surface is one lease, one tab, pixels.';
|
|
3
134
|
/** Every tool takes the key except the first and the last (§3.1). */
|
|
4
135
|
const LEASE_KEY = {
|
|
5
136
|
name: 'lease_key',
|
|
@@ -91,9 +222,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
91
222
|
{
|
|
92
223
|
name: 'browser_navigate',
|
|
93
224
|
operation: 'navigate',
|
|
94
|
-
description: 'Point your tab at an address. Returns the final address after redirects
|
|
95
|
-
'
|
|
96
|
-
'
|
|
225
|
+
description: 'Point your tab at an address. Returns the final address after redirects — which is not ' +
|
|
226
|
+
'always the address you asked for, and is the field to check when you need to know ' +
|
|
227
|
+
'whether something sent you elsewhere — plus the title and the status. ' +
|
|
228
|
+
'It does NOT take a snapshot: use browser_read for one.',
|
|
97
229
|
arguments: [
|
|
98
230
|
LEASE_KEY,
|
|
99
231
|
{
|
|
@@ -107,7 +239,16 @@ export const TOOL_DEFINITIONS = [
|
|
|
107
239
|
name: 'wait_ms',
|
|
108
240
|
type: 'integer',
|
|
109
241
|
required: false,
|
|
110
|
-
description: 'How long
|
|
242
|
+
description: 'How long the navigation may take before it is abandoned, in whole milliseconds. ' +
|
|
243
|
+
'A bound, not a pause: the call returns as soon as the page is there, so a larger ' +
|
|
244
|
+
'value costs nothing on a page that loads quickly and two calls differing only in ' +
|
|
245
|
+
'this argument tell you nothing about how long the page was given to settle. ' +
|
|
246
|
+
'It bounds the load only, and does not wait for work the page starts afterwards, so ' +
|
|
247
|
+
'a canvas or a lazily-loaded region can still be unfinished when this returns; see ' +
|
|
248
|
+
'browser_capture on how to tell. ' +
|
|
249
|
+
'At most the lease lifetime, because a wait outliving the lease would hold the tab ' +
|
|
250
|
+
'past the point it becomes reclaimable; the refusal names the accepted range. ' +
|
|
251
|
+
'Omit it to leave the browser default in force.',
|
|
111
252
|
},
|
|
112
253
|
],
|
|
113
254
|
},
|
|
@@ -175,7 +316,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
175
316
|
operation: 'capture',
|
|
176
317
|
description: 'Take a picture of the page — and, if you name an earlier capture, what changed since it. ' +
|
|
177
318
|
'Returns paths, never the image itself. A selector and a full page cannot both be asked ' +
|
|
178
|
-
'for. Never refused for cost.'
|
|
319
|
+
'for. Never refused for cost. ' +
|
|
320
|
+
CAPTURE_SETTLE_CAVEAT +
|
|
321
|
+
' ' +
|
|
322
|
+
CAPTURE_BUILD_COMPARISON_CAVEAT,
|
|
179
323
|
arguments: [
|
|
180
324
|
LEASE_KEY,
|
|
181
325
|
{
|
|
@@ -196,11 +340,23 @@ export const TOOL_DEFINITIONS = [
|
|
|
196
340
|
required: false,
|
|
197
341
|
description: 'An earlier capture to diff against. The diff rides here rather than being its own tool.',
|
|
198
342
|
},
|
|
343
|
+
{
|
|
344
|
+
name: 'tier',
|
|
345
|
+
type: 'string',
|
|
346
|
+
required: false,
|
|
347
|
+
description: '"detail" or "max" for a higher resolution. Omit for the default — there is no way to ' +
|
|
348
|
+
'ask for the default by name. "max" also requires reason. **A tier raises the LONGEST ' +
|
|
349
|
+
'edge, not the width**, so on a full_page capture of a page taller than it is wide the ' +
|
|
350
|
+
'height takes the whole budget and the width stays small at every rung — a 1030px-wide ' +
|
|
351
|
+
'page 6400px tall is about 165px wide by default and about 414px wide at "max". For ' +
|
|
352
|
+
'legible text on a tall page, capture a selector instead, or read the page as text.',
|
|
353
|
+
},
|
|
199
354
|
{
|
|
200
355
|
name: 'reason',
|
|
201
356
|
type: 'string',
|
|
202
357
|
required: false,
|
|
203
|
-
description: 'Free text, recorded, never refused — why this capture needed more
|
|
358
|
+
description: 'Free text, 8-200 characters, recorded, never refused — why this capture needed more ' +
|
|
359
|
+
'than the default tier. Required with tier="max".',
|
|
204
360
|
},
|
|
205
361
|
],
|
|
206
362
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-broker",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Leases over tabs in a fixed set of browsers: bounded capacity, a queue, reclamation, and an enforced capture policy.",
|
|
6
6
|
"type": "module",
|
|
@@ -19,12 +19,13 @@
|
|
|
19
19
|
"check:operations": "node scripts/check-operations.mjs",
|
|
20
20
|
"check:argument-refusals": "node scripts/check-argument-refusals.mjs",
|
|
21
21
|
"check:injected-tests": "node scripts/check-injected-tests.mjs",
|
|
22
|
+
"check:argument-reachability": "node scripts/check-argument-reachability.mjs",
|
|
22
23
|
"typecheck": "tsc --noEmit",
|
|
23
24
|
"lint": "eslint .",
|
|
24
25
|
"format": "prettier --write .",
|
|
25
26
|
"format:check": "prettier --check .",
|
|
26
27
|
"test": "node --test \"tests/**/*.test.mjs\" \"tests/**/*.test.ts\"",
|
|
27
|
-
"check": "npm run check:external-refs && npm run check:doc-links && npm run check:arbitration && npm run check:capture-isolation && npm run check:artifact-path && npm run typecheck && npm run lint && npm run format:check && npm test && npm run check:install && npm run check:operations && npm run check:argument-refusals && npm run check:injected-tests",
|
|
28
|
+
"check": "npm run check:external-refs && npm run check:doc-links && npm run check:arbitration && npm run check:capture-isolation && npm run check:artifact-path && npm run typecheck && npm run lint && npm run format:check && npm test && npm run check:install && npm run check:operations && npm run check:argument-refusals && npm run check:argument-reachability && npm run check:injected-tests && npm run check:package",
|
|
28
29
|
"check:arbitration": "node scripts/check-arbitration.mjs",
|
|
29
30
|
"check:artifact-path": "node scripts/check-artifact-path.mjs",
|
|
30
31
|
"build": "tsc --project tsconfig.build.json",
|
|
@@ -52,7 +53,6 @@
|
|
|
52
53
|
"dist/",
|
|
53
54
|
".env.example",
|
|
54
55
|
"README.md",
|
|
55
|
-
"RELEASES.md",
|
|
56
56
|
"LICENSE"
|
|
57
57
|
]
|
|
58
58
|
}
|
package/RELEASES.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Release notes
|
|
2
|
-
|
|
3
|
-
**What changes between versions, and specifically what changes *behaviour* on an installation that
|
|
4
|
-
sets nothing.**
|
|
5
|
-
|
|
6
|
-
That second half is the reason this file exists rather than the commit log being enough. A new
|
|
7
|
-
setting with a neutral default is not news: an installation that does not set it behaves exactly as
|
|
8
|
-
before. **A changed default is news**, because it moves an installation that has taken no action and
|
|
9
|
-
made no decision. `docs/plans/DECISIONS.md` §6.3 puts a changed default here rather than in a quiet
|
|
10
|
-
edit for that reason.
|
|
11
|
-
|
|
12
|
-
Entries are newest first. Each names what moved, what an installation has to do about it, and what
|
|
13
|
-
happens if it does nothing.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Unreleased
|
|
18
|
-
|
|
19
|
-
### The package is published, and it ships compiled JavaScript
|
|
20
|
-
|
|
21
|
-
**What moved.** The service is installable from the registry as `browser-broker`, so a caller can
|
|
22
|
-
spawn it without a checkout. The manifest's `bin` entries now name emitted JavaScript under `dist/`
|
|
23
|
-
rather than the TypeScript sources.
|
|
24
|
-
|
|
25
|
-
**Why the build exists**, given that the development path deliberately has none: **Node refuses to
|
|
26
|
-
strip types from any file under a `node_modules` path**, and an installed package is a directory
|
|
27
|
-
under `node_modules`. A manifest whose `bin` named a `.ts` file would install cleanly and then fail
|
|
28
|
-
on the machine of whoever installed it. There is no flag that changes this. The compiler therefore
|
|
29
|
-
runs once per release rather than on every machine that consumes the package, and `erasableSyntaxOnly`
|
|
30
|
-
stays on so the sources still run unbuilt — the two paths execute the same dialect.
|
|
31
|
-
|
|
32
|
-
**What an installation has to do.** Nothing. A checkout is unaffected: `node src/bin/broker.ts` still
|
|
33
|
-
runs the sources with no build. An installation that would rather not track a checkout can point at
|
|
34
|
-
the package instead, and npm revalidates the version on every spawn:
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{ "command": "npx", "args": ["-y", "browser-broker"] }
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Worth weighing before switching:** `npx` performs a registry round-trip on every spawn, costing
|
|
41
|
-
seconds where a path on disk costs a fraction of one. It buys an upgrade path, not speed.
|
|
42
|
-
|
|
43
|
-
**One surface changes what it reports.** The tool handshake's `serverInfo.version` was the literal
|
|
44
|
-
`0.0.0` while the package was unversioned, and now reads the manifest — so a client logging it sees
|
|
45
|
-
the released version rather than a placeholder.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### ⚠ Behaviour change: the default browser engine is Edge
|
|
49
|
-
|
|
50
|
-
**What moved.** A browser launched by this service uses **`msedge`** by default. The previous
|
|
51
|
-
behaviour was to launch whatever `chromium.executablePath()` resolved to — the Chromium build the
|
|
52
|
-
automation library had fetched.
|
|
53
|
-
|
|
54
|
-
**Why.** Edge is present on every Windows machine, so a fresh install runs with nothing set, with no
|
|
55
|
-
separate browser download step. That is `DECISIONS.md` §6.1's *"a fresh install runs with nothing
|
|
56
|
-
set"* applied to the one prerequisite `npm install` genuinely could not cover.
|
|
57
|
-
|
|
58
|
-
**What an installation has to do.** Nothing, if Edge is acceptable. To keep the prior behaviour, or
|
|
59
|
-
to pick a different browser, set the engine per kind:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
BROKER_REGULAR_BROWSER_ENGINE=chrome # chrome | brave | msedge
|
|
63
|
-
BROKER_PRIVATE_BROWSER_ENGINE=chrome # may differ from the line above
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**If it does nothing:** browsers launch under Edge. **Profiles are per browser and are not shared
|
|
67
|
-
between engines**, so an installation whose signed-in profile was established under a different
|
|
68
|
-
binary will find that browser signed out, and a person will be asked to sign in once more with
|
|
69
|
-
`broker login`. Nothing is destroyed — `setup.profile_never_destroyed` still holds, and the earlier
|
|
70
|
-
profile directory is left exactly where it is.
|
|
71
|
-
|
|
72
|
-
### Browsers are a configured list, and `browser` on a claim is optional
|
|
73
|
-
|
|
74
|
-
**What moved.** Two things, both reversals of recorded decisions — the argument for each is in
|
|
75
|
-
`DECISIONS.md` §13i:
|
|
76
|
-
|
|
77
|
-
- **The fixed pair of browsers becomes a bounded list per kind**, at most three each, named in
|
|
78
|
-
configuration. A name is what a caller claims by and what its profile directory is called.
|
|
79
|
-
- **`browser` on `browser_claim` becomes optional.** Unstated resolves to the first signed-in
|
|
80
|
-
browser; `regular` or `private` resolves to the first of that kind; a configured name resolves to
|
|
81
|
-
that browser exactly.
|
|
82
|
-
|
|
83
|
-
**What an installation has to do.** Nothing. The defaults name one browser of each kind, `regular`
|
|
84
|
-
and `private`, which is the pair that existed before — so an installation that sets nothing has the
|
|
85
|
-
same two browsers under the same two names, and a caller that states `browser` explicitly is
|
|
86
|
-
unaffected.
|
|
87
|
-
|
|
88
|
-
**Worth reading before configuring more than the default two:** the tab budget counts *tabs*, and
|
|
89
|
-
each browser costs a process **before it holds a single tab**. `BROKER_TAB_BUDGET=15` with six
|
|
90
|
-
browsers is six browser processes, plus up to fifteen tabs, plus six keeper tabs that are not
|
|
91
|
-
counted against the budget at all. `.env.example` states this beside the variables.
|
|
92
|
-
|
|
93
|
-
**One schema step.** The store gains a `kind` column on `browsers` and drops the check constraint
|
|
94
|
-
that limited a browser's name to two literals. It is applied on the next spawn, like every step, and
|
|
95
|
-
the two existing rows are backfilled to their own kinds. **A store stepped by this build is not
|
|
96
|
-
readable by an earlier one**, which is the ordinary direction — a build refuses a store newer than
|
|
97
|
-
itself rather than downgrading it.
|