browser-pilot-cli 0.3.0-rc.4 → 0.3.0-rc.6
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/README.md +1 -1
- package/dist/cli.js +4 -7
- package/dist/daemon.js +49 -13
- package/docs/plans/v0.3.0-stabilization.md +7 -2
- package/docs/releases/v0.3.0-rc.5.md +26 -0
- package/docs/releases/v0.3.0-rc.6.md +24 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -182,7 +182,7 @@ A project can pin Browser Pilot locally and run the same CLI without a global
|
|
|
182
182
|
installation:
|
|
183
183
|
|
|
184
184
|
```bash
|
|
185
|
-
npm install --save-exact browser-pilot-cli@0.3.0-rc.
|
|
185
|
+
npm install --save-exact browser-pilot-cli@0.3.0-rc.6
|
|
186
186
|
npx --no-install browser-pilot tabs
|
|
187
187
|
```
|
|
188
188
|
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { writeFileSync as writeFileSync2, readFileSync as readFileSync4, existsS
|
|
|
6
6
|
import { resolve as resolvePath } from "path";
|
|
7
7
|
|
|
8
8
|
// src/version.ts
|
|
9
|
-
var BROWSER_PILOT_VERSION = "0.3.0-rc.
|
|
9
|
+
var BROWSER_PILOT_VERSION = "0.3.0-rc.6";
|
|
10
10
|
|
|
11
11
|
// src/protocol/errors.ts
|
|
12
12
|
var ERROR_CODES = [
|
|
@@ -1804,7 +1804,7 @@ var scrollEvidenceSchema = objectSchema({
|
|
|
1804
1804
|
afterX: numberSchema({ minimum: 0 }),
|
|
1805
1805
|
afterY: numberSchema({ minimum: 0 }),
|
|
1806
1806
|
matchedText: sensitive(stringSchema({ maxLength: 4096 }), "browser_data"),
|
|
1807
|
-
reason: stringSchema({ enum: ["at_boundary", "text_not_found"] })
|
|
1807
|
+
reason: stringSchema({ enum: ["at_boundary", "text_not_found", "text_not_revealed"] })
|
|
1808
1808
|
}, [
|
|
1809
1809
|
"action",
|
|
1810
1810
|
"status",
|
|
@@ -4368,9 +4368,6 @@ program.command("close").description("Close current browser tab").option("-a, --
|
|
|
4368
4368
|
context: { failedTargetIds: failed }
|
|
4369
4369
|
});
|
|
4370
4370
|
}
|
|
4371
|
-
if (remainingTabs.length > 0 && !remainingTabs.some((tab) => tab.active)) {
|
|
4372
|
-
await client.callTool("browser.tabs.switch", { targetId: remainingTabs[0].targetId });
|
|
4373
|
-
}
|
|
4374
4371
|
emit(
|
|
4375
4372
|
{ ok: true, closed, remaining: remainingTabs.length },
|
|
4376
4373
|
`\u2713 Closed ${closed} Pilot tab(s)`
|
|
@@ -4381,8 +4378,8 @@ program.command("close").description("Close current browser tab").option("-a, --
|
|
|
4381
4378
|
const remainingTabs = await client.listTabs("all");
|
|
4382
4379
|
if (remainingTabs.length > 0) {
|
|
4383
4380
|
if (!remainingTabs.some((tab) => tab.active)) {
|
|
4384
|
-
const fallback = remainingTabs.find((tab) => tab.origin !== "user_tab")
|
|
4385
|
-
await client.callTool("browser.tabs.switch", { targetId: fallback.targetId });
|
|
4381
|
+
const fallback = remainingTabs.find((tab) => tab.origin !== "user_tab");
|
|
4382
|
+
if (fallback) await client.callTool("browser.tabs.switch", { targetId: fallback.targetId });
|
|
4386
4383
|
}
|
|
4387
4384
|
emit({ ok: true, remaining: remainingTabs.length }, "\u2713 Tab closed");
|
|
4388
4385
|
} else {
|
package/dist/daemon.js
CHANGED
|
@@ -747,7 +747,7 @@ var scrollEvidenceSchema = objectSchema({
|
|
|
747
747
|
afterX: numberSchema({ minimum: 0 }),
|
|
748
748
|
afterY: numberSchema({ minimum: 0 }),
|
|
749
749
|
matchedText: sensitive(stringSchema({ maxLength: 4096 }), "browser_data"),
|
|
750
|
-
reason: stringSchema({ enum: ["at_boundary", "text_not_found"] })
|
|
750
|
+
reason: stringSchema({ enum: ["at_boundary", "text_not_found", "text_not_revealed"] })
|
|
751
751
|
}, [
|
|
752
752
|
"action",
|
|
753
753
|
"status",
|
|
@@ -7769,9 +7769,9 @@ var MemoryControlledTargetRegistry = class {
|
|
|
7769
7769
|
(record) => record.state === "active" && record.principalId === context.principalId && record.workspaceId === context.workspaceId
|
|
7770
7770
|
).map(cloneRecord2);
|
|
7771
7771
|
}
|
|
7772
|
-
isManagedCdpTarget(browserInstanceId, cdpTargetId) {
|
|
7772
|
+
isManagedCdpTarget(browserInstanceId, cdpTargetId, browserConnectionGeneration) {
|
|
7773
7773
|
for (const record of this.records.values()) {
|
|
7774
|
-
if (record.
|
|
7774
|
+
if (record.browserInstanceId === browserInstanceId && record.cdpTargetId === cdpTargetId && record.browserConnectionGeneration === browserConnectionGeneration && record.origin !== "user_tab") return true;
|
|
7775
7775
|
}
|
|
7776
7776
|
return false;
|
|
7777
7777
|
}
|
|
@@ -9012,6 +9012,10 @@ var ScrollService = class {
|
|
|
9012
9012
|
const exact=${exact};
|
|
9013
9013
|
const normalize=value=>String(value||'').replace(/\\s+/g,' ').trim();
|
|
9014
9014
|
const needle=normalize(query).toLocaleLowerCase();
|
|
9015
|
+
const slash=String.fromCharCode(92);
|
|
9016
|
+
const regexSpecials='^$.*+?()[]{}|'+slash;
|
|
9017
|
+
const escapeRegex=value=>Array.from(value,char=>regexSpecials.includes(char)?slash+char:char).join('');
|
|
9018
|
+
const queryPattern=exact?null:new RegExp(normalize(query).split(' ').map(escapeRegex).join(slash+'s+'),'iu');
|
|
9015
9019
|
const roots=[document];
|
|
9016
9020
|
let visited=0;
|
|
9017
9021
|
while(roots.length&&visited<20000){
|
|
@@ -9029,21 +9033,50 @@ var ScrollService = class {
|
|
|
9029
9033
|
if(!element)continue;
|
|
9030
9034
|
const tag=String(element.tagName||'').toLowerCase();
|
|
9031
9035
|
if(['script','style','noscript','template'].includes(tag))continue;
|
|
9032
|
-
const
|
|
9036
|
+
const raw=String(node.nodeValue||'');
|
|
9037
|
+
const content=normalize(raw);
|
|
9033
9038
|
const normalized=content.toLocaleLowerCase();
|
|
9034
9039
|
if(!(exact?normalized===needle:normalized.includes(needle)))continue;
|
|
9040
|
+
let matchStart=0;
|
|
9041
|
+
let matchEnd=raw.length;
|
|
9042
|
+
if(exact){
|
|
9043
|
+
matchStart=Math.max(0,raw.search(/\\S/u));
|
|
9044
|
+
matchEnd=Math.max(matchStart,raw.length-((raw.match(/\\s*$/u)||[''])[0].length));
|
|
9045
|
+
}else{
|
|
9046
|
+
const match=queryPattern.exec(raw);
|
|
9047
|
+
if(!match)continue;
|
|
9048
|
+
matchStart=match.index;
|
|
9049
|
+
matchEnd=match.index+match[0].length;
|
|
9050
|
+
}
|
|
9035
9051
|
const style=getComputedStyle(element);
|
|
9036
9052
|
if(style.display==='none'||style.visibility==='hidden'||style.visibility==='collapse'||element.getClientRects().length===0)continue;
|
|
9053
|
+
const viewportWidth=Math.max(0,window.innerWidth||document.documentElement.clientWidth||0);
|
|
9054
|
+
const viewportHeight=Math.max(0,window.innerHeight||document.documentElement.clientHeight||0);
|
|
9055
|
+
const range=document.createRange();
|
|
9056
|
+
range.setStart(node,matchStart);
|
|
9057
|
+
range.setEnd(node,matchEnd);
|
|
9058
|
+
const rangeRect=()=>range.getBoundingClientRect();
|
|
9059
|
+
const intersectsViewport=rect=>rect.width>0&&rect.height>0&&rect.bottom>0&&rect.right>0&&rect.top<viewportHeight&&rect.left<viewportWidth;
|
|
9037
9060
|
const beforeX=Math.max(0,window.scrollX||document.documentElement.scrollLeft||0);
|
|
9038
9061
|
const beforeY=Math.max(0,window.scrollY||document.documentElement.scrollTop||0);
|
|
9039
9062
|
element.scrollIntoView({block:'center',inline:'nearest',behavior:'instant'});
|
|
9040
|
-
|
|
9041
|
-
|
|
9063
|
+
let afterX=Math.max(0,window.scrollX||document.documentElement.scrollLeft||0);
|
|
9064
|
+
let afterY=Math.max(0,window.scrollY||document.documentElement.scrollTop||0);
|
|
9065
|
+
let rect=rangeRect();
|
|
9066
|
+
if(!intersectsViewport(rect)){
|
|
9067
|
+
const left=Math.max(0,afterX+rect.left-Math.max(0,(viewportWidth-rect.width)/2));
|
|
9068
|
+
const top=Math.max(0,afterY+rect.top-Math.max(0,(viewportHeight-rect.height)/2));
|
|
9069
|
+
window.scrollTo({left,top,behavior:'instant'});
|
|
9070
|
+
afterX=Math.max(0,window.scrollX||document.documentElement.scrollLeft||0);
|
|
9071
|
+
afterY=Math.max(0,window.scrollY||document.documentElement.scrollTop||0);
|
|
9072
|
+
rect=rangeRect();
|
|
9073
|
+
}
|
|
9042
9074
|
const round=value=>Math.round(Number(value)||0);
|
|
9043
9075
|
const moved=Math.abs(afterX-beforeX)>=1||Math.abs(afterY-beforeY)>=1;
|
|
9044
|
-
|
|
9076
|
+
const revealed=intersectsViewport(rect);
|
|
9077
|
+
return{ok:true,action:'scroll',status:revealed?'verified':'mismatch',mode:'text',target:'text',moved,
|
|
9045
9078
|
deltaX:round(afterX-beforeX),deltaY:round(afterY-beforeY),beforeX:round(beforeX),beforeY:round(beforeY),
|
|
9046
|
-
afterX:round(afterX),afterY:round(afterY),matchedText:content.slice(0,4096)};
|
|
9079
|
+
afterX:round(afterX),afterY:round(afterY),matchedText:content.slice(0,4096),...(revealed?{}:{reason:'text_not_revealed'})};
|
|
9047
9080
|
}
|
|
9048
9081
|
}
|
|
9049
9082
|
return{ok:true,action:'scroll',status:'mismatch',mode:'text',target:'text',moved:false,
|
|
@@ -9066,11 +9099,13 @@ var ScrollService = class {
|
|
|
9066
9099
|
var MAX_ANNOTATIONS = 200;
|
|
9067
9100
|
function annotationScript(data, annotations, viewport) {
|
|
9068
9101
|
return `(async() => {
|
|
9069
|
-
const
|
|
9102
|
+
const base64=${JSON.stringify(data)};
|
|
9070
9103
|
const annotations=${JSON.stringify(annotations)};
|
|
9071
9104
|
const viewport=${JSON.stringify(viewport)};
|
|
9072
|
-
const
|
|
9073
|
-
const
|
|
9105
|
+
const binary=atob(base64);
|
|
9106
|
+
const bytes=new Uint8Array(binary.length);
|
|
9107
|
+
for(let index=0;index<binary.length;index+=1)bytes[index]=binary.charCodeAt(index);
|
|
9108
|
+
const bitmap=await createImageBitmap(new Blob([bytes],{type:'image/png'}));
|
|
9074
9109
|
const canvas=document.createElement('canvas');
|
|
9075
9110
|
canvas.width=bitmap.width;canvas.height=bitmap.height;
|
|
9076
9111
|
const context=canvas.getContext('2d');
|
|
@@ -10405,7 +10440,8 @@ var BrowserToolService = class {
|
|
|
10405
10440
|
profileContexts: this.profileContexts,
|
|
10406
10441
|
isExcludedTarget: (target) => this.registry.isManagedCdpTarget(
|
|
10407
10442
|
binding.instance.id,
|
|
10408
|
-
target.cdpTargetId
|
|
10443
|
+
target.cdpTargetId,
|
|
10444
|
+
binding.instance.connectionGeneration
|
|
10409
10445
|
)
|
|
10410
10446
|
}
|
|
10411
10447
|
);
|
|
@@ -13979,7 +14015,7 @@ var ManagedTargetJanitorClient = class {
|
|
|
13979
14015
|
};
|
|
13980
14016
|
|
|
13981
14017
|
// src/version.ts
|
|
13982
|
-
var BROWSER_PILOT_VERSION = "0.3.0-rc.
|
|
14018
|
+
var BROWSER_PILOT_VERSION = "0.3.0-rc.6";
|
|
13983
14019
|
|
|
13984
14020
|
// src/daemon.ts
|
|
13985
14021
|
var CLI_EXECUTABLE_PATH = publicExecutablePath(import.meta.url);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Browser Pilot v0.3.0 Stabilization Plan
|
|
2
2
|
|
|
3
3
|
Status: **In progress**
|
|
4
|
-
Candidate baseline: `v0.3.0-rc.
|
|
4
|
+
Candidate baseline: `v0.3.0-rc.5`; correction target: `v0.3.0-rc.6`, protocol `1.2`
|
|
5
5
|
|
|
6
6
|
## Goal
|
|
7
7
|
|
|
@@ -35,8 +35,13 @@ products depend on. No Agent-specific behavior enters Browser Pilot.
|
|
|
35
35
|
integration checks against the installed standalone release executable.
|
|
36
36
|
- [x] Run one controlled user-Chrome host acceptance with explicit Profile
|
|
37
37
|
choices and a single authorization attempt.
|
|
38
|
-
- [
|
|
38
|
+
- [x] Publish `v0.3.0-rc.4` with Broker-backed CLI browser status and verify
|
|
39
39
|
that passive discovery reports the live authorized connection.
|
|
40
|
+
- [x] Publish `v0.3.0-rc.5` and verify text-targeted scrolling plus annotated
|
|
41
|
+
capture on GitHub. Managed cleanup preserved all user tabs but exposed a
|
|
42
|
+
transient closing-target inventory race.
|
|
43
|
+
- [ ] Publish `v0.3.0-rc.6` with generation-scoped managed-target tombstones and
|
|
44
|
+
rerun managed cleanup against the installed standalone release.
|
|
40
45
|
- [ ] Soak several real Agent tasks through the installed candidate.
|
|
41
46
|
- [ ] Tag `v0.3.0`, publish npm `latest`, and verify upgrade/rollback metadata.
|
|
42
47
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Browser Pilot 0.3.0-rc.5
|
|
2
|
+
|
|
3
|
+
This release candidate fixes three edge cases found by running RC.4 through
|
|
4
|
+
real Agent tasks in two live Chrome Profiles.
|
|
5
|
+
|
|
6
|
+
- Text-targeted scrolling now verifies that the matched text actually entered
|
|
7
|
+
the viewport. If a site's `scrollIntoView` path is ineffective, Browser Pilot
|
|
8
|
+
falls back to the matched text Range's page coordinates; an unrevealed match
|
|
9
|
+
returns an explicit mismatch instead of a false success.
|
|
10
|
+
- Screenshot annotations no longer decode captured PNGs through
|
|
11
|
+
`fetch(data:)`. They use in-memory base64, Blob, and ImageBitmap conversion in
|
|
12
|
+
the isolated world, so restrictive site `connect-src` policies such as
|
|
13
|
+
GitHub's cannot break annotation.
|
|
14
|
+
- Tab cleanup no longer switches control to a user tab when Chrome has not yet
|
|
15
|
+
reported its next active target. `bp close --all` still closes only managed
|
|
16
|
+
tabs.
|
|
17
|
+
|
|
18
|
+
The soak otherwise completed public GitHub reading and targeted search, a
|
|
19
|
+
disposable HTTP form with verified input and control state, submission result
|
|
20
|
+
verification, multi-Profile routing, ordinary screenshots, annotated form
|
|
21
|
+
screenshots, PDF export, connection-status checks, and preservation of every
|
|
22
|
+
user tab and exported file.
|
|
23
|
+
|
|
24
|
+
RC.5 keeps protocol 1.2 and the Agent-neutral stdio contract unchanged.
|
|
25
|
+
Candidate gates passed with 276 Node tests, 109 isolated Playwright tests, and
|
|
26
|
+
TypeScript type checking.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Browser Pilot 0.3.0-rc.6
|
|
2
|
+
|
|
3
|
+
This release candidate fixes the remaining managed-tab cleanup race found by
|
|
4
|
+
running RC.5 against a live multi-Profile Chrome browser.
|
|
5
|
+
|
|
6
|
+
- A managed target that Chrome has accepted for closure remains classified as
|
|
7
|
+
managed for the rest of that browser connection generation. If Chrome still
|
|
8
|
+
reports the physical target briefly before its asynchronous destroyed event,
|
|
9
|
+
Browser Pilot no longer reintroduces it as a transient available user tab.
|
|
10
|
+
- The tombstone is generation-scoped, so browser reconnection cannot exclude a
|
|
11
|
+
target from a later connection even if Chrome were to reuse an identifier.
|
|
12
|
+
- `bp close` and `bp close --all` therefore preserve accurate user-tab
|
|
13
|
+
inventory without implicitly acquiring a closing target.
|
|
14
|
+
|
|
15
|
+
The RC.5 soak otherwise passed its two real-site corrections: text-targeted
|
|
16
|
+
scrolling revealed the requested GitHub text with verified movement, and a
|
|
17
|
+
three-ref annotated GitHub screenshot succeeded under the site's restrictive
|
|
18
|
+
content security policy. All six eligible user tabs remained available and no
|
|
19
|
+
user tab was controlled after managed cleanup.
|
|
20
|
+
|
|
21
|
+
RC.6 keeps protocol 1.2 and the Agent-neutral CLI and stdio contracts unchanged.
|
|
22
|
+
Candidate gates passed with 277 Node tests, 109 isolated Playwright tests,
|
|
23
|
+
TypeScript type checking, all three npm distribution modes, 13 stdio
|
|
24
|
+
conformance checks, and 13 isolated Host integration checks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-pilot-cli",
|
|
3
|
-
"version": "0.3.0-rc.
|
|
3
|
+
"version": "0.3.0-rc.6",
|
|
4
4
|
"description": "CLI tool to control your browser via Chrome DevTools Protocol",
|
|
5
5
|
"repository": "https://github.com/relixiaobo/browser-pilot",
|
|
6
6
|
"type": "module",
|
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
"docs/releases/v0.3.0-rc.2.md",
|
|
49
49
|
"docs/releases/v0.3.0-rc.3.md",
|
|
50
50
|
"docs/releases/v0.3.0-rc.4.md",
|
|
51
|
+
"docs/releases/v0.3.0-rc.5.md",
|
|
52
|
+
"docs/releases/v0.3.0-rc.6.md",
|
|
51
53
|
"README.md",
|
|
52
54
|
"LICENSE"
|
|
53
55
|
],
|