@jobshimo/browser-link 0.22.0 → 0.23.0
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 +5 -0
- package/dist/agent-instructions/content.js +11 -0
- package/dist/agent-instructions/content.js.map +1 -1
- package/dist/cdp/client.d.ts +35 -0
- package/dist/cdp/client.js +149 -0
- package/dist/cdp/client.js.map +1 -0
- package/dist/cdp/flow.d.ts +178 -0
- package/dist/cdp/flow.js +217 -0
- package/dist/cdp/flow.js.map +1 -0
- package/dist/cdp/gate.d.ts +31 -0
- package/dist/cdp/gate.js +35 -0
- package/dist/cdp/gate.js.map +1 -0
- package/dist/cdp/grant.d.ts +45 -0
- package/dist/cdp/grant.js +81 -0
- package/dist/cdp/grant.js.map +1 -0
- package/dist/cdp/inpage/builders.d.ts +165 -0
- package/dist/cdp/inpage/builders.js +501 -0
- package/dist/cdp/inpage/builders.js.map +1 -0
- package/dist/cdp/inpage/deep-query.d.ts +57 -0
- package/dist/cdp/inpage/deep-query.js +325 -0
- package/dist/cdp/inpage/deep-query.js.map +1 -0
- package/dist/cdp/inpage/dom-helpers.d.ts +27 -0
- package/dist/cdp/inpage/dom-helpers.js +147 -0
- package/dist/cdp/inpage/dom-helpers.js.map +1 -0
- package/dist/cdp/keymap.d.ts +83 -0
- package/dist/cdp/keymap.js +205 -0
- package/dist/cdp/keymap.js.map +1 -0
- package/dist/cdp/settle.d.ts +38 -0
- package/dist/cdp/settle.js +76 -0
- package/dist/cdp/settle.js.map +1 -0
- package/dist/cdp/support.d.ts +26 -0
- package/dist/cdp/support.js +58 -0
- package/dist/cdp/support.js.map +1 -0
- package/dist/cdp/targets.d.ts +54 -0
- package/dist/cdp/targets.js +176 -0
- package/dist/cdp/targets.js.map +1 -0
- package/dist/cdp/transport.d.ts +31 -0
- package/dist/cdp/transport.js +531 -0
- package/dist/cdp/transport.js.map +1 -0
- package/dist/cli.js +50 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/about.js +13 -0
- package/dist/commands/about.js.map +1 -1
- package/dist/commands/cdp.d.ts +28 -0
- package/dist/commands/cdp.js +172 -0
- package/dist/commands/cdp.js.map +1 -0
- package/dist/commands/config.d.ts +92 -0
- package/dist/commands/config.js +173 -12
- package/dist/commands/config.js.map +1 -1
- package/dist/config.d.ts +70 -0
- package/dist/config.js +94 -1
- package/dist/config.js.map +1 -1
- package/dist/extension/manifest.json +1 -1
- package/dist/server.js +9 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/browser-definitions.js +4 -3
- package/dist/tools/browser-definitions.js.map +1 -1
- package/dist/tools/browser-dispatch.d.ts +31 -0
- package/dist/tools/browser-dispatch.js +88 -40
- package/dist/tools/browser-dispatch.js.map +1 -1
- package/dist/tools/server-instructions.js +19 -0
- package/dist/tools/server-instructions.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,6 +118,11 @@ browser-link map import map.json # restore it (merge by default, --re
|
|
|
118
118
|
the same bridge and map. `browser-link multi-agent` shows the current
|
|
119
119
|
state; see [Multi-agent mode](https://github.com/jobshimo/browser-link#multi-agent-mode)
|
|
120
120
|
for how it works.
|
|
121
|
+
- **cdp-direct mode** (off by default): an extension-free transport gated
|
|
122
|
+
behind `browser-link config set cdp-direct.enabled true` PLUS a
|
|
123
|
+
time-boxed `browser-link cdp allow` grant — see
|
|
124
|
+
[cdp-direct mode](https://github.com/jobshimo/browser-link#cdp-direct-mode-no-extension)
|
|
125
|
+
for the security tradeoff and the v1 tool-support table.
|
|
121
126
|
|
|
122
127
|
## Where the data lives
|
|
123
128
|
|
|
@@ -74,6 +74,17 @@ function body() {
|
|
|
74
74
|
'→ `browser.claim_tab` before operating on a tab so other agents see it',
|
|
75
75
|
'in use. `browser.release_tab` when done.',
|
|
76
76
|
'',
|
|
77
|
+
'A `list_tabs` entry has `tab_id` starting with `cdp:` (`transport: "cdp"`):',
|
|
78
|
+
'→ that tab is reached via cdp-direct, not the extension — every tool',
|
|
79
|
+
'works the same EXCEPT drag/console/network/network_body/',
|
|
80
|
+
'canvas_screenshot/dialog_respond/set_permission/wait_for_tab (clear',
|
|
81
|
+
'error naming the extension as the fallback). cdp-direct only appears',
|
|
82
|
+
'when the user has both enabled it AND granted access — you cannot',
|
|
83
|
+
'enable or grant it yourself. A "cdp-direct is disabled" or "requires an',
|
|
84
|
+
'active grant" error means relay the suggested command to the user',
|
|
85
|
+
'(`browser-link config set cdp-direct.enabled true` or',
|
|
86
|
+
'`browser-link cdp allow`) — there is no workaround from here.',
|
|
87
|
+
'',
|
|
77
88
|
'### SELF-CHECK after each user message',
|
|
78
89
|
'',
|
|
79
90
|
'"Is the user talking about a web page, UI, or anything visible in a browser?',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/agent-instructions/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,sCAAsC,CAAC;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,wCAAwC,CAAC;AAEnE,MAAM,UAAU,WAAW,CAAC,OAAO,GAAG,OAAO;IAC3C,OAAO,GAAG,YAAY,KAAK,OAAO,MAAM,CAAC;AAC3C,CAAC;AAED;;;;yCAIyC;AACzC,MAAM,CAAC,MAAM,QAAQ,GACnB,gFAAgF,CAAC;AACnF,MAAM,CAAC,MAAM,MAAM,GAAG,4CAA4C,CAAC;AAEnE;;;;mBAImB;AACnB,SAAS,IAAI;IACX,OAAO;QACL,mDAAmD;QACnD,EAAE;QACF,kFAAkF;QAClF,wEAAwE;QACxE,+DAA+D;QAC/D,EAAE;QACF,0DAA0D;QAC1D,EAAE;QACF,kDAAkD;QAClD,qEAAqE;QACrE,+DAA+D;QAC/D,yEAAyE;QACzE,oDAAoD;QACpD,yEAAyE;QACzE,sEAAsE;QACtE,kFAAkF;QAClF,EAAE;QACF,iDAAiD;QACjD,kCAAkC;QAClC,mEAAmE;QACnE,sEAAsE;QACtE,qEAAqE;QACrE,EAAE;QACF,qDAAqD;QACrD,qEAAqE;QACrE,EAAE;QACF,yCAAyC;QACzC,gEAAgE;QAChE,EAAE;QACF,yEAAyE;QACzE,mBAAmB;QACnB,qEAAqE;QACrE,wEAAwE;QACxE,qDAAqD;QACrD,EAAE;QACF,2DAA2D;QAC3D,iEAAiE;QACjE,sEAAsE;QACtE,qEAAqE;QACrE,0CAA0C;QAC1C,EAAE;QACF,4DAA4D;QAC5D,wEAAwE;QACxE,0CAA0C;QAC1C,EAAE;QACF,wCAAwC;QACxC,EAAE;QACF,8EAA8E;QAC9E,2EAA2E;QAC3E,EAAE;QACF,WAAW;QACX,EAAE;QACF,iDAAiD;QACjD,4EAA4E;QAC5E,2DAA2D;QAC3D,2EAA2E;QAC3E,yEAAyE;QACzE,uEAAuE;QACvE,gEAAgE;QAChE,EAAE;QACF,8EAA8E;QAC9E,EAAE;QACF,uEAAuE;QACvE,oEAAoE;QACpE,EAAE;QACF,sEAAsE;QACtE,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,wEAAwE;QACxE,6DAA6D;QAC7D,sEAAsE;QACtE,sEAAsE;QACtE,wCAAwC;QACxC,yEAAyE;QACzE,mEAAmE;QACnE,sEAAsE;QACtE,iEAAiE;QACjE,kEAAkE;QAClE,qEAAqE;QACrE,uEAAuE;QACvE,oEAAoE;QACpE,mCAAmC;QACnC,oEAAoE;QACpE,qEAAqE;QACrE,wEAAwE;QACxE,oEAAoE;QACpE,iCAAiC;QACjC,yEAAyE;QACzE,sEAAsE;QACtE,8DAA8D;QAC9D,kEAAkE;QAClE,uEAAuE;QACvE,oEAAoE;QACpE,4BAA4B;QAC5B,oEAAoE;QACpE,sEAAsE;QACtE,wEAAwE;QACxE,6DAA6D;QAC7D,iHAAiH;QACjH,2EAA2E;QAC3E,oEAAoE;QACpE,mDAAmD;QACnD,kEAAkE;QAClE,oEAAoE;QACpE,2CAA2C;QAC3C,+DAA+D;QAC/D,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,sDAAsD;QACtD,kEAAkE;QAClE,wEAAwE;QACxE,sEAAsE;QACtE,mEAAmE;QACnE,sEAAsE;QACtE,sEAAsE;QACtE,sEAAsE;QACtE,qEAAqE;QACrE,kEAAkE;QAClE,gDAAgD;QAChD,sEAAsE;QACtE,qEAAqE;QACrE,+CAA+C;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;kDAOkD;AAClD,MAAM,UAAU,KAAK,CAAC,OAAO,GAAG,OAAO,EAAE,MAAqB,IAAI;IAChE,MAAM,KAAK,GAAG;QACZ,WAAW,CAAC,OAAO,CAAC;QACpB,kCAAkC,OAAO,0FAA0F;QACnI,EAAE;QACF,IAAI,EAAE;QACN,EAAE;QACF,UAAU;QACV,EAAE;KACH,CAAC;IACF,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,4EAA4E;IAC5E,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;+DAE+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,qEAAqE,CAAC,IAAI,EAAE,CAAC;SAC7F,MAAM,CAAC;AACZ,CAAC;AAED;;4DAE4D;AAC5D,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAChD,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAWD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,sBAAsB,GAAG,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC;IACtD,MAAM,oBAAoB,GAAG,sBAAsB,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACrF,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,KAAK;QACvB,QAAQ;QACR,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;KAChD,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/agent-instructions/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,sCAAsC,CAAC;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,wCAAwC,CAAC;AAEnE,MAAM,UAAU,WAAW,CAAC,OAAO,GAAG,OAAO;IAC3C,OAAO,GAAG,YAAY,KAAK,OAAO,MAAM,CAAC;AAC3C,CAAC;AAED;;;;yCAIyC;AACzC,MAAM,CAAC,MAAM,QAAQ,GACnB,gFAAgF,CAAC;AACnF,MAAM,CAAC,MAAM,MAAM,GAAG,4CAA4C,CAAC;AAEnE;;;;mBAImB;AACnB,SAAS,IAAI;IACX,OAAO;QACL,mDAAmD;QACnD,EAAE;QACF,kFAAkF;QAClF,wEAAwE;QACxE,+DAA+D;QAC/D,EAAE;QACF,0DAA0D;QAC1D,EAAE;QACF,kDAAkD;QAClD,qEAAqE;QACrE,+DAA+D;QAC/D,yEAAyE;QACzE,oDAAoD;QACpD,yEAAyE;QACzE,sEAAsE;QACtE,kFAAkF;QAClF,EAAE;QACF,iDAAiD;QACjD,kCAAkC;QAClC,mEAAmE;QACnE,sEAAsE;QACtE,qEAAqE;QACrE,EAAE;QACF,qDAAqD;QACrD,qEAAqE;QACrE,EAAE;QACF,yCAAyC;QACzC,gEAAgE;QAChE,EAAE;QACF,yEAAyE;QACzE,mBAAmB;QACnB,qEAAqE;QACrE,wEAAwE;QACxE,qDAAqD;QACrD,EAAE;QACF,2DAA2D;QAC3D,iEAAiE;QACjE,sEAAsE;QACtE,qEAAqE;QACrE,0CAA0C;QAC1C,EAAE;QACF,4DAA4D;QAC5D,wEAAwE;QACxE,0CAA0C;QAC1C,EAAE;QACF,6EAA6E;QAC7E,sEAAsE;QACtE,0DAA0D;QAC1D,qEAAqE;QACrE,sEAAsE;QACtE,mEAAmE;QACnE,yEAAyE;QACzE,mEAAmE;QACnE,uDAAuD;QACvD,+DAA+D;QAC/D,EAAE;QACF,wCAAwC;QACxC,EAAE;QACF,8EAA8E;QAC9E,2EAA2E;QAC3E,EAAE;QACF,WAAW;QACX,EAAE;QACF,iDAAiD;QACjD,4EAA4E;QAC5E,2DAA2D;QAC3D,2EAA2E;QAC3E,yEAAyE;QACzE,uEAAuE;QACvE,gEAAgE;QAChE,EAAE;QACF,8EAA8E;QAC9E,EAAE;QACF,uEAAuE;QACvE,oEAAoE;QACpE,EAAE;QACF,sEAAsE;QACtE,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,wEAAwE;QACxE,6DAA6D;QAC7D,sEAAsE;QACtE,sEAAsE;QACtE,wCAAwC;QACxC,yEAAyE;QACzE,mEAAmE;QACnE,sEAAsE;QACtE,iEAAiE;QACjE,kEAAkE;QAClE,qEAAqE;QACrE,uEAAuE;QACvE,oEAAoE;QACpE,mCAAmC;QACnC,oEAAoE;QACpE,qEAAqE;QACrE,wEAAwE;QACxE,oEAAoE;QACpE,iCAAiC;QACjC,yEAAyE;QACzE,sEAAsE;QACtE,8DAA8D;QAC9D,kEAAkE;QAClE,uEAAuE;QACvE,oEAAoE;QACpE,4BAA4B;QAC5B,oEAAoE;QACpE,sEAAsE;QACtE,wEAAwE;QACxE,6DAA6D;QAC7D,iHAAiH;QACjH,2EAA2E;QAC3E,oEAAoE;QACpE,mDAAmD;QACnD,kEAAkE;QAClE,oEAAoE;QACpE,2CAA2C;QAC3C,+DAA+D;QAC/D,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,sDAAsD;QACtD,kEAAkE;QAClE,wEAAwE;QACxE,sEAAsE;QACtE,mEAAmE;QACnE,sEAAsE;QACtE,sEAAsE;QACtE,sEAAsE;QACtE,qEAAqE;QACrE,kEAAkE;QAClE,gDAAgD;QAChD,sEAAsE;QACtE,qEAAqE;QACrE,+CAA+C;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;kDAOkD;AAClD,MAAM,UAAU,KAAK,CAAC,OAAO,GAAG,OAAO,EAAE,MAAqB,IAAI;IAChE,MAAM,KAAK,GAAG;QACZ,WAAW,CAAC,OAAO,CAAC;QACpB,kCAAkC,OAAO,0FAA0F;QACnI,EAAE;QACF,IAAI,EAAE;QACN,EAAE;QACF,UAAU;QACV,EAAE;KACH,CAAC;IACF,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,4EAA4E;IAC5E,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;+DAE+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,qEAAqE,CAAC,IAAI,EAAE,CAAC;SAC7F,MAAM,CAAC;AACZ,CAAC;AAED;;4DAE4D;AAC5D,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAChD,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAWD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,sBAAsB,GAAG,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC;IACtD,MAAM,oBAAoB,GAAG,sBAAsB,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACrF,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,KAAK;QACvB,QAAQ;QACR,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type CdpEventHandler = (params: unknown) => void;
|
|
2
|
+
export interface CdpClientOptions {
|
|
3
|
+
/** How long `connect()` waits for the WS handshake before giving up.
|
|
4
|
+
* Default 5s — a local loopback connection should be near-instant; a
|
|
5
|
+
* long default here would make a dead/stale target hang tool calls. */
|
|
6
|
+
connectTimeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class CdpClient {
|
|
9
|
+
private readonly url;
|
|
10
|
+
private readonly options;
|
|
11
|
+
private ws;
|
|
12
|
+
private nextId;
|
|
13
|
+
private readonly pending;
|
|
14
|
+
private readonly eventHandlers;
|
|
15
|
+
private closed;
|
|
16
|
+
constructor(url: string, options?: CdpClientOptions);
|
|
17
|
+
/** Open the WebSocket and wait for it to be ready. Rejects on a bind
|
|
18
|
+
* failure or on timeout — never leaves the caller waiting forever on a
|
|
19
|
+
* target that vanished between discovery and connect. */
|
|
20
|
+
connect(): Promise<void>;
|
|
21
|
+
private handleMessage;
|
|
22
|
+
private handleClose;
|
|
23
|
+
/** Whether the underlying WebSocket is open and this client has not been
|
|
24
|
+
* explicitly closed. Used by the transport's connection cache to decide
|
|
25
|
+
* whether a cached client is still worth reusing. */
|
|
26
|
+
get isOpen(): boolean;
|
|
27
|
+
/** Send one CDP command and wait for its matching response. */
|
|
28
|
+
send<T = unknown>(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<T>;
|
|
29
|
+
/** Subscribe to a CDP event by method name (e.g. `Page.loadEventFired`).
|
|
30
|
+
* Returns an unsubscribe function. Multiple handlers for the same method
|
|
31
|
+
* may be registered independently. */
|
|
32
|
+
on(method: string, handler: CdpEventHandler): () => void;
|
|
33
|
+
close(): void;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
function frameToText(raw) {
|
|
3
|
+
if (typeof raw === 'string')
|
|
4
|
+
return raw;
|
|
5
|
+
if (Buffer.isBuffer(raw))
|
|
6
|
+
return raw.toString('utf8');
|
|
7
|
+
if (Array.isArray(raw))
|
|
8
|
+
return Buffer.concat(raw).toString('utf8');
|
|
9
|
+
return Buffer.from(raw).toString('utf8');
|
|
10
|
+
}
|
|
11
|
+
export class CdpClient {
|
|
12
|
+
url;
|
|
13
|
+
options;
|
|
14
|
+
ws = null;
|
|
15
|
+
nextId = 1;
|
|
16
|
+
pending = new Map();
|
|
17
|
+
eventHandlers = new Map();
|
|
18
|
+
closed = false;
|
|
19
|
+
constructor(url, options = {}) {
|
|
20
|
+
this.url = url;
|
|
21
|
+
this.options = options;
|
|
22
|
+
}
|
|
23
|
+
/** Open the WebSocket and wait for it to be ready. Rejects on a bind
|
|
24
|
+
* failure or on timeout — never leaves the caller waiting forever on a
|
|
25
|
+
* target that vanished between discovery and connect. */
|
|
26
|
+
connect() {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
let settled = false;
|
|
29
|
+
const ws = new WebSocket(this.url);
|
|
30
|
+
const timeoutMs = this.options.connectTimeoutMs ?? 5_000;
|
|
31
|
+
const timer = setTimeout(() => {
|
|
32
|
+
if (settled)
|
|
33
|
+
return;
|
|
34
|
+
settled = true;
|
|
35
|
+
ws.terminate();
|
|
36
|
+
reject(new Error(`cdp-direct: connection to ${this.url} timed out after ${timeoutMs}ms`));
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
ws.once('open', () => {
|
|
39
|
+
if (settled)
|
|
40
|
+
return;
|
|
41
|
+
settled = true;
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
this.ws = ws;
|
|
44
|
+
resolve();
|
|
45
|
+
});
|
|
46
|
+
ws.once('error', (err) => {
|
|
47
|
+
if (settled)
|
|
48
|
+
return;
|
|
49
|
+
settled = true;
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
52
|
+
});
|
|
53
|
+
ws.on('message', (raw) => {
|
|
54
|
+
this.handleMessage(raw);
|
|
55
|
+
});
|
|
56
|
+
ws.on('close', () => {
|
|
57
|
+
this.handleClose();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
handleMessage(raw) {
|
|
62
|
+
let msg;
|
|
63
|
+
try {
|
|
64
|
+
msg = JSON.parse(frameToText(raw));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (typeof msg.id === 'number') {
|
|
70
|
+
const pending = this.pending.get(msg.id);
|
|
71
|
+
if (!pending)
|
|
72
|
+
return;
|
|
73
|
+
this.pending.delete(msg.id);
|
|
74
|
+
if (msg.error) {
|
|
75
|
+
pending.reject(new Error(msg.error.message ?? 'CDP command failed'));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
pending.resolve(msg.result);
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (typeof msg.method === 'string') {
|
|
83
|
+
const handlers = this.eventHandlers.get(msg.method);
|
|
84
|
+
if (handlers)
|
|
85
|
+
for (const handler of handlers)
|
|
86
|
+
handler(msg.params);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
handleClose() {
|
|
90
|
+
this.closed = true;
|
|
91
|
+
const err = new Error('cdp-direct: connection closed');
|
|
92
|
+
for (const pending of this.pending.values())
|
|
93
|
+
pending.reject(err);
|
|
94
|
+
this.pending.clear();
|
|
95
|
+
}
|
|
96
|
+
/** Whether the underlying WebSocket is open and this client has not been
|
|
97
|
+
* explicitly closed. Used by the transport's connection cache to decide
|
|
98
|
+
* whether a cached client is still worth reusing. */
|
|
99
|
+
get isOpen() {
|
|
100
|
+
return !this.closed && this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
101
|
+
}
|
|
102
|
+
/** Send one CDP command and wait for its matching response. */
|
|
103
|
+
send(method, params = {}, timeoutMs = 15_000) {
|
|
104
|
+
if (!this.ws || this.closed) {
|
|
105
|
+
return Promise.reject(new Error('cdp-direct: client is not connected'));
|
|
106
|
+
}
|
|
107
|
+
const id = this.nextId++;
|
|
108
|
+
const ws = this.ws;
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const timer = setTimeout(() => {
|
|
111
|
+
this.pending.delete(id);
|
|
112
|
+
reject(new Error(`cdp-direct: command "${method}" timed out after ${timeoutMs}ms`));
|
|
113
|
+
}, timeoutMs);
|
|
114
|
+
this.pending.set(id, {
|
|
115
|
+
resolve: (value) => {
|
|
116
|
+
clearTimeout(timer);
|
|
117
|
+
resolve(value);
|
|
118
|
+
},
|
|
119
|
+
reject: (err) => {
|
|
120
|
+
clearTimeout(timer);
|
|
121
|
+
reject(err);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
ws.send(JSON.stringify({ id, method, params }));
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Subscribe to a CDP event by method name (e.g. `Page.loadEventFired`).
|
|
128
|
+
* Returns an unsubscribe function. Multiple handlers for the same method
|
|
129
|
+
* may be registered independently. */
|
|
130
|
+
on(method, handler) {
|
|
131
|
+
let set = this.eventHandlers.get(method);
|
|
132
|
+
if (!set) {
|
|
133
|
+
set = new Set();
|
|
134
|
+
this.eventHandlers.set(method, set);
|
|
135
|
+
}
|
|
136
|
+
set.add(handler);
|
|
137
|
+
return () => set.delete(handler);
|
|
138
|
+
}
|
|
139
|
+
close() {
|
|
140
|
+
this.closed = true;
|
|
141
|
+
try {
|
|
142
|
+
this.ws?.close();
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
/* best effort */
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cdp/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Independent copy of `packages/extension/src/flow.ts` — see
|
|
3
|
+
* `inpage/deep-query.ts`'s header comment for why this package duplicates
|
|
4
|
+
* rather than imports extension-side modules. Byte-identical logic, so
|
|
5
|
+
* `browser.flow` behaves identically whether the target tab is reached
|
|
6
|
+
* through the extension or through cdp-direct. Kept transport-agnostic ON
|
|
7
|
+
* PURPOSE — it does NOT re-check the cdp-direct gate per step; a mid-flow
|
|
8
|
+
* `cdp revoke` is grandfathered until the flow finishes (bounded ≤60s by
|
|
9
|
+
* the flow budget), documented in the README's cdp-direct section.
|
|
10
|
+
* `cdp/drift.test.ts` asserts `MAX_FLOW_STEPS` stays in lockstep with the
|
|
11
|
+
* sibling at `packages/extension/src/flow.ts`.
|
|
12
|
+
*
|
|
13
|
+
* browser.flow step sequencing — the logic behind the composite action
|
|
14
|
+
* tool. Runs a short, declarative list of find/click/type/press/wait_for
|
|
15
|
+
* steps strictly in order, fails fast on the first step that does not
|
|
16
|
+
* succeed, and threads an "implicit target" from a `find` step into the
|
|
17
|
+
* very next click/type/press step that omits its own `selector`.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately decoupled from any transport: every side effect goes
|
|
20
|
+
* through the `FlowDeps` the caller injects. `cdp/transport.ts` wires the
|
|
21
|
+
* real perform* functions (already closed over the CDP client); tests wire
|
|
22
|
+
* fakes. This is what makes the sequencing logic — step-shape validation,
|
|
23
|
+
* implicit-target threading, fail-fast, result shaping — unit-testable
|
|
24
|
+
* without a real Chrome target.
|
|
25
|
+
*/
|
|
26
|
+
/** Structured success/failure outcome shared by every perform* function in
|
|
27
|
+
* `cdp/transport.ts`. `ok:false` carries the exact same error string the
|
|
28
|
+
* standalone tool.response would have returned for that failure — both the
|
|
29
|
+
* thin case wrappers and this module's step executor consume this shape,
|
|
30
|
+
* so the two call paths can never drift. */
|
|
31
|
+
export type ActionOutcome<T> = {
|
|
32
|
+
ok: true;
|
|
33
|
+
result: T;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
error: string;
|
|
37
|
+
};
|
|
38
|
+
/** Hard cap on steps per flow — mirrors the `maxItems: 20` on the MCP
|
|
39
|
+
* schema (`browser-definitions.ts`) and the server-side validation
|
|
40
|
+
* (`browser-dispatch.ts`). Enforced again here so cdp-direct never runs an
|
|
41
|
+
* oversized flow even if a future caller bypasses the server's own check. */
|
|
42
|
+
export declare const MAX_FLOW_STEPS = 20;
|
|
43
|
+
export interface FindStepParams {
|
|
44
|
+
text: string;
|
|
45
|
+
role?: string;
|
|
46
|
+
exact?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface FindStepResult {
|
|
49
|
+
matched: boolean;
|
|
50
|
+
reason?: string;
|
|
51
|
+
candidates?: {
|
|
52
|
+
selector: string;
|
|
53
|
+
text: string;
|
|
54
|
+
tag: string;
|
|
55
|
+
}[];
|
|
56
|
+
/** Up to 3 near-miss candidates on a `not-found` result — see
|
|
57
|
+
* `buildFindJs` in `inpage/builders.ts` for the ranking rules. Not
|
|
58
|
+
* consumed by `runFlow` today (the flow failure message stays as-is);
|
|
59
|
+
* carried through so a future caller of the raw `performFind` outcome
|
|
60
|
+
* (or a richer flow error message) can use it without a shape change. */
|
|
61
|
+
near_misses?: {
|
|
62
|
+
text: string;
|
|
63
|
+
selector: string;
|
|
64
|
+
role?: string;
|
|
65
|
+
}[];
|
|
66
|
+
/** Human-readable detail on a `not-found` result — currently only set
|
|
67
|
+
* when `role` excluded matches that existed under a broader scan. */
|
|
68
|
+
error?: string;
|
|
69
|
+
selector?: string;
|
|
70
|
+
ambiguous?: boolean;
|
|
71
|
+
tag?: string;
|
|
72
|
+
text?: string;
|
|
73
|
+
coords?: {
|
|
74
|
+
x: number;
|
|
75
|
+
y: number;
|
|
76
|
+
};
|
|
77
|
+
frame?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface ClickStepParams {
|
|
80
|
+
selector?: string;
|
|
81
|
+
force?: boolean;
|
|
82
|
+
settle_ms?: number;
|
|
83
|
+
}
|
|
84
|
+
export interface ClickStepResult {
|
|
85
|
+
clicked: string;
|
|
86
|
+
tag: string;
|
|
87
|
+
settle?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
export interface TypeStepParams {
|
|
90
|
+
selector?: string;
|
|
91
|
+
text: string;
|
|
92
|
+
clear?: boolean;
|
|
93
|
+
settle_ms?: number;
|
|
94
|
+
}
|
|
95
|
+
export interface TypeStepResult {
|
|
96
|
+
typed: number;
|
|
97
|
+
selector?: string;
|
|
98
|
+
settle?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
export interface PressStepParams {
|
|
101
|
+
key: string;
|
|
102
|
+
modifiers?: string[];
|
|
103
|
+
selector?: string;
|
|
104
|
+
settle_ms?: number;
|
|
105
|
+
}
|
|
106
|
+
export interface PressStepResult {
|
|
107
|
+
key: string;
|
|
108
|
+
modifiers: string[];
|
|
109
|
+
settle?: Record<string, unknown>;
|
|
110
|
+
}
|
|
111
|
+
export interface WaitForStepParams {
|
|
112
|
+
selector?: string;
|
|
113
|
+
expression?: string;
|
|
114
|
+
network_url?: string;
|
|
115
|
+
condition?: string;
|
|
116
|
+
timeout_ms?: number;
|
|
117
|
+
poll_interval_ms?: number;
|
|
118
|
+
}
|
|
119
|
+
export interface WaitForStepResult {
|
|
120
|
+
matched: boolean;
|
|
121
|
+
elapsed_ms: number;
|
|
122
|
+
checks: number;
|
|
123
|
+
reason?: string;
|
|
124
|
+
}
|
|
125
|
+
export type FlowStep = {
|
|
126
|
+
find: FindStepParams;
|
|
127
|
+
} | {
|
|
128
|
+
click: ClickStepParams;
|
|
129
|
+
} | {
|
|
130
|
+
type: TypeStepParams;
|
|
131
|
+
} | {
|
|
132
|
+
press: PressStepParams;
|
|
133
|
+
} | {
|
|
134
|
+
wait_for: WaitForStepParams;
|
|
135
|
+
};
|
|
136
|
+
/** Everything the step executor needs from the outside world. `cdp/transport.ts`
|
|
137
|
+
* binds each method to the real perform* function; tests bind fakes.
|
|
138
|
+
* `buildRecoverySnapshot` is called only on failure, and always renders the
|
|
139
|
+
* same focused view (`only_interactive:true, max_interactive:40`) via the
|
|
140
|
+
* shared `buildSnapshotJs` builder — same DOM walk `browser.snapshot` uses,
|
|
141
|
+
* just pre-filtered so the agent sees where the flow stopped without a
|
|
142
|
+
* follow-up round trip. */
|
|
143
|
+
export interface FlowDeps {
|
|
144
|
+
performFind(params: FindStepParams): Promise<ActionOutcome<FindStepResult>>;
|
|
145
|
+
performClick(params: ClickStepParams & {
|
|
146
|
+
selector: string;
|
|
147
|
+
}): Promise<ActionOutcome<ClickStepResult>>;
|
|
148
|
+
performType(params: TypeStepParams): Promise<ActionOutcome<TypeStepResult>>;
|
|
149
|
+
performPress(params: PressStepParams): Promise<ActionOutcome<PressStepResult>>;
|
|
150
|
+
performWaitFor(params: WaitForStepParams): Promise<ActionOutcome<WaitForStepResult>>;
|
|
151
|
+
buildRecoverySnapshot(): Promise<unknown>;
|
|
152
|
+
}
|
|
153
|
+
export interface FlowSuccess {
|
|
154
|
+
ok: true;
|
|
155
|
+
steps_completed: number;
|
|
156
|
+
results: unknown[];
|
|
157
|
+
}
|
|
158
|
+
export interface FlowFailure {
|
|
159
|
+
ok: false;
|
|
160
|
+
failed_step: number;
|
|
161
|
+
step_kind: string;
|
|
162
|
+
error: string;
|
|
163
|
+
steps_completed: number;
|
|
164
|
+
recovery_snapshot: unknown;
|
|
165
|
+
}
|
|
166
|
+
export type FlowResult = FlowSuccess | FlowFailure;
|
|
167
|
+
/**
|
|
168
|
+
* Run a declarative sequence of steps strictly in order, stopping at the
|
|
169
|
+
* first failure. See the module doc comment for the implicit-target and
|
|
170
|
+
* result-shaping rules.
|
|
171
|
+
*
|
|
172
|
+
* `steps` is typed as `FlowStep[]` for ergonomic test-writing, but every
|
|
173
|
+
* element is re-validated at runtime via `stepKind()` before use — the
|
|
174
|
+
* array may originate from an untrusted JSON payload cast at the wire
|
|
175
|
+
* boundary in `cdp/transport.ts`, and a malformed entry must fail the flow
|
|
176
|
+
* cleanly rather than throw.
|
|
177
|
+
*/
|
|
178
|
+
export declare function runFlow(steps: readonly FlowStep[], deps: FlowDeps): Promise<FlowResult>;
|
package/dist/cdp/flow.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Independent copy of `packages/extension/src/flow.ts` — see
|
|
3
|
+
* `inpage/deep-query.ts`'s header comment for why this package duplicates
|
|
4
|
+
* rather than imports extension-side modules. Byte-identical logic, so
|
|
5
|
+
* `browser.flow` behaves identically whether the target tab is reached
|
|
6
|
+
* through the extension or through cdp-direct. Kept transport-agnostic ON
|
|
7
|
+
* PURPOSE — it does NOT re-check the cdp-direct gate per step; a mid-flow
|
|
8
|
+
* `cdp revoke` is grandfathered until the flow finishes (bounded ≤60s by
|
|
9
|
+
* the flow budget), documented in the README's cdp-direct section.
|
|
10
|
+
* `cdp/drift.test.ts` asserts `MAX_FLOW_STEPS` stays in lockstep with the
|
|
11
|
+
* sibling at `packages/extension/src/flow.ts`.
|
|
12
|
+
*
|
|
13
|
+
* browser.flow step sequencing — the logic behind the composite action
|
|
14
|
+
* tool. Runs a short, declarative list of find/click/type/press/wait_for
|
|
15
|
+
* steps strictly in order, fails fast on the first step that does not
|
|
16
|
+
* succeed, and threads an "implicit target" from a `find` step into the
|
|
17
|
+
* very next click/type/press step that omits its own `selector`.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately decoupled from any transport: every side effect goes
|
|
20
|
+
* through the `FlowDeps` the caller injects. `cdp/transport.ts` wires the
|
|
21
|
+
* real perform* functions (already closed over the CDP client); tests wire
|
|
22
|
+
* fakes. This is what makes the sequencing logic — step-shape validation,
|
|
23
|
+
* implicit-target threading, fail-fast, result shaping — unit-testable
|
|
24
|
+
* without a real Chrome target.
|
|
25
|
+
*/
|
|
26
|
+
/** Hard cap on steps per flow — mirrors the `maxItems: 20` on the MCP
|
|
27
|
+
* schema (`browser-definitions.ts`) and the server-side validation
|
|
28
|
+
* (`browser-dispatch.ts`). Enforced again here so cdp-direct never runs an
|
|
29
|
+
* oversized flow even if a future caller bypasses the server's own check. */
|
|
30
|
+
export const MAX_FLOW_STEPS = 20;
|
|
31
|
+
const STEP_KINDS = ['find', 'click', 'type', 'press', 'wait_for'];
|
|
32
|
+
function isStepKind(key) {
|
|
33
|
+
return STEP_KINDS.includes(key);
|
|
34
|
+
}
|
|
35
|
+
/** Identify which of the 5 step kinds a raw (untrusted) step object is.
|
|
36
|
+
* Returns `null` unless the object has EXACTLY ONE key and that key is a
|
|
37
|
+
* recognized kind — extra keys (`{find: {...}, mystery: 1}`) reject, in
|
|
38
|
+
* line with the MCP schema's `additionalProperties: false`. The caller
|
|
39
|
+
* treats `null` as an "unknown step shape" flow failure. */
|
|
40
|
+
function stepKind(step) {
|
|
41
|
+
if (typeof step !== 'object' || step === null)
|
|
42
|
+
return null;
|
|
43
|
+
const keys = Object.keys(step);
|
|
44
|
+
if (keys.length !== 1)
|
|
45
|
+
return null;
|
|
46
|
+
return isStepKind(keys[0]) ? keys[0] : null;
|
|
47
|
+
}
|
|
48
|
+
/** Drop the noisy fields of a click/type/press result down to `{ ok, settle? }`
|
|
49
|
+
* for the flow's per-step result — the agent already knows what it asked
|
|
50
|
+
* for (the selector, the text length, the key); echoing that back N times
|
|
51
|
+
* in a row is not worth the tokens. `settle` is kept because it carries
|
|
52
|
+
* NEW information (did the page go quiet, did focus/URL drift). */
|
|
53
|
+
function compactActionResult(result) {
|
|
54
|
+
return result.settle ? { ok: true, settle: result.settle } : { ok: true };
|
|
55
|
+
}
|
|
56
|
+
async function withRecoverySnapshot(deps, index, kind, error, stepsCompleted) {
|
|
57
|
+
let recovery_snapshot = null;
|
|
58
|
+
try {
|
|
59
|
+
recovery_snapshot = await deps.buildRecoverySnapshot();
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Best-effort: if the tab is gone or CDP throws on the recovery
|
|
63
|
+
// snapshot too, still report the original step failure rather than
|
|
64
|
+
// masking it behind a secondary snapshot error.
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
failed_step: index,
|
|
69
|
+
step_kind: kind,
|
|
70
|
+
error,
|
|
71
|
+
steps_completed: stepsCompleted,
|
|
72
|
+
recovery_snapshot,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Resolve a click/type/press step's target: an explicit `selector` always
|
|
76
|
+
* wins; otherwise fall back to the implicit target left by a preceding
|
|
77
|
+
* `find` step. `consumed` is true only when the implicit target was the
|
|
78
|
+
* one actually used — a step providing its own selector leaves the
|
|
79
|
+
* implicit target untouched for a LATER step to pick up. */
|
|
80
|
+
function resolveTarget(explicit, implicit) {
|
|
81
|
+
if (explicit !== undefined)
|
|
82
|
+
return { resolved: explicit, consumed: false };
|
|
83
|
+
return { resolved: implicit, consumed: implicit !== undefined };
|
|
84
|
+
}
|
|
85
|
+
/** Appended to a step failure when the PREVIOUS step's settle wait reported
|
|
86
|
+
* `context-destroyed` — that reason means the page navigated during or right
|
|
87
|
+
* after that step, so the failing step almost certainly raced the loading
|
|
88
|
+
* document rather than genuinely missing its target. */
|
|
89
|
+
const NAVIGATION_RACE_HINT = " (previous step's settle reported context-destroyed — the page likely navigated;" +
|
|
90
|
+
' insert a wait_for step after the navigating action so this step does not race the page load)';
|
|
91
|
+
/**
|
|
92
|
+
* Run a declarative sequence of steps strictly in order, stopping at the
|
|
93
|
+
* first failure. See the module doc comment for the implicit-target and
|
|
94
|
+
* result-shaping rules.
|
|
95
|
+
*
|
|
96
|
+
* `steps` is typed as `FlowStep[]` for ergonomic test-writing, but every
|
|
97
|
+
* element is re-validated at runtime via `stepKind()` before use — the
|
|
98
|
+
* array may originate from an untrusted JSON payload cast at the wire
|
|
99
|
+
* boundary in `cdp/transport.ts`, and a malformed entry must fail the flow
|
|
100
|
+
* cleanly rather than throw.
|
|
101
|
+
*/
|
|
102
|
+
export async function runFlow(steps, deps) {
|
|
103
|
+
if (!Array.isArray(steps) || steps.length === 0) {
|
|
104
|
+
return withRecoverySnapshot(deps, 0, 'none', 'flow: steps must be a non-empty array', 0);
|
|
105
|
+
}
|
|
106
|
+
if (steps.length > MAX_FLOW_STEPS) {
|
|
107
|
+
return withRecoverySnapshot(deps, 0, 'none', `flow: at most ${MAX_FLOW_STEPS} steps allowed, got ${steps.length}`, 0);
|
|
108
|
+
}
|
|
109
|
+
const results = [];
|
|
110
|
+
let implicitTarget;
|
|
111
|
+
/** `settle.reason` from the most recent SUCCESSFUL action step. When it
|
|
112
|
+
* is 'context-destroyed', the next step failure gets the page-load-race
|
|
113
|
+
* hint appended. Reset by any successful find/wait_for step — those
|
|
114
|
+
* prove the page is reachable again. */
|
|
115
|
+
let lastSettleReason;
|
|
116
|
+
const raceHint = () => lastSettleReason === 'context-destroyed' ? NAVIGATION_RACE_HINT : '';
|
|
117
|
+
for (let i = 0; i < steps.length; i++) {
|
|
118
|
+
const raw = steps[i];
|
|
119
|
+
const kind = stepKind(raw);
|
|
120
|
+
if (!kind) {
|
|
121
|
+
return withRecoverySnapshot(deps, i, 'unknown', 'flow: each step must be exactly one of find | click | type | press | wait_for', results.length);
|
|
122
|
+
}
|
|
123
|
+
const stepRecord = raw;
|
|
124
|
+
if (kind === 'find') {
|
|
125
|
+
const params = stepRecord.find;
|
|
126
|
+
const outcome = await deps.performFind(params);
|
|
127
|
+
if (!outcome.ok) {
|
|
128
|
+
return withRecoverySnapshot(deps, i, kind, outcome.error + raceHint(), results.length);
|
|
129
|
+
}
|
|
130
|
+
const r = outcome.result;
|
|
131
|
+
if (!r.matched) {
|
|
132
|
+
const candidateNote = r.reason === 'multiple-matches' && r.candidates
|
|
133
|
+
? ` — candidates: ${JSON.stringify(r.candidates)}`
|
|
134
|
+
: '';
|
|
135
|
+
return withRecoverySnapshot(deps, i, kind, `find: ${r.reason ?? 'not-found'}${candidateNote}${raceHint()}`, results.length);
|
|
136
|
+
}
|
|
137
|
+
if (r.ambiguous) {
|
|
138
|
+
return withRecoverySnapshot(deps, i, kind, `find: selector "${r.selector ?? ''}" is ambiguous across shadow roots/iframes — refine text/role for a unique match`, results.length);
|
|
139
|
+
}
|
|
140
|
+
implicitTarget = r.selector;
|
|
141
|
+
lastSettleReason = undefined;
|
|
142
|
+
results.push({ selector: r.selector });
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (kind === 'wait_for') {
|
|
146
|
+
const params = stepRecord.wait_for;
|
|
147
|
+
const outcome = await deps.performWaitFor(params);
|
|
148
|
+
if (!outcome.ok) {
|
|
149
|
+
return withRecoverySnapshot(deps, i, kind, outcome.error + raceHint(), results.length);
|
|
150
|
+
}
|
|
151
|
+
if (!outcome.result.matched) {
|
|
152
|
+
// No race hint here: a wait_for step IS the recommended remedy for
|
|
153
|
+
// a navigation race — a plain timeout is a genuine non-match.
|
|
154
|
+
return withRecoverySnapshot(deps, i, kind, `wait_for: condition not met within timeout (${outcome.result.elapsed_ms}ms, ${outcome.result.checks} checks)`, results.length);
|
|
155
|
+
}
|
|
156
|
+
lastSettleReason = undefined;
|
|
157
|
+
results.push({ ok: true });
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (kind === 'click') {
|
|
161
|
+
const params = stepRecord.click;
|
|
162
|
+
const { resolved, consumed } = resolveTarget(params.selector, implicitTarget);
|
|
163
|
+
if (consumed)
|
|
164
|
+
implicitTarget = undefined;
|
|
165
|
+
if (resolved === undefined) {
|
|
166
|
+
return withRecoverySnapshot(deps, i, kind, 'click: no selector provided and no implicit target from a preceding find', results.length);
|
|
167
|
+
}
|
|
168
|
+
const outcome = await deps.performClick({
|
|
169
|
+
force: params.force,
|
|
170
|
+
settle_ms: params.settle_ms,
|
|
171
|
+
selector: resolved,
|
|
172
|
+
});
|
|
173
|
+
if (!outcome.ok) {
|
|
174
|
+
return withRecoverySnapshot(deps, i, kind, outcome.error + raceHint(), results.length);
|
|
175
|
+
}
|
|
176
|
+
lastSettleReason = outcome.result.settle?.reason;
|
|
177
|
+
results.push(compactActionResult(outcome.result));
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (kind === 'type') {
|
|
181
|
+
const params = stepRecord.type;
|
|
182
|
+
const { resolved, consumed } = resolveTarget(params.selector, implicitTarget);
|
|
183
|
+
if (consumed)
|
|
184
|
+
implicitTarget = undefined;
|
|
185
|
+
const outcome = await deps.performType({
|
|
186
|
+
text: params.text,
|
|
187
|
+
clear: params.clear,
|
|
188
|
+
settle_ms: params.settle_ms,
|
|
189
|
+
selector: resolved,
|
|
190
|
+
});
|
|
191
|
+
if (!outcome.ok) {
|
|
192
|
+
return withRecoverySnapshot(deps, i, kind, outcome.error + raceHint(), results.length);
|
|
193
|
+
}
|
|
194
|
+
lastSettleReason = outcome.result.settle?.reason;
|
|
195
|
+
results.push(compactActionResult(outcome.result));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
// press — the only kind left after the checks above.
|
|
199
|
+
const params = stepRecord.press;
|
|
200
|
+
const { resolved, consumed } = resolveTarget(params.selector, implicitTarget);
|
|
201
|
+
if (consumed)
|
|
202
|
+
implicitTarget = undefined;
|
|
203
|
+
const outcome = await deps.performPress({
|
|
204
|
+
key: params.key,
|
|
205
|
+
modifiers: params.modifiers,
|
|
206
|
+
settle_ms: params.settle_ms,
|
|
207
|
+
selector: resolved,
|
|
208
|
+
});
|
|
209
|
+
if (!outcome.ok) {
|
|
210
|
+
return withRecoverySnapshot(deps, i, kind, outcome.error + raceHint(), results.length);
|
|
211
|
+
}
|
|
212
|
+
lastSettleReason = outcome.result.settle?.reason;
|
|
213
|
+
results.push(compactActionResult(outcome.result));
|
|
214
|
+
}
|
|
215
|
+
return { ok: true, steps_completed: results.length, results };
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/cdp/flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AASH;;;6EAG6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AA2FjC,MAAM,UAAU,GAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAEvF,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAQ,UAAgC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACzD,CAAC;AAED;;;;4DAI4D;AAC5D,SAAS,QAAQ,CAAC,IAAa;IAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAqCD;;;;mEAImE;AACnE,SAAS,mBAAmB,CAAC,MAA4C;IAIvE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,IAAc,EACd,KAAa,EACb,IAAY,EACZ,KAAa,EACb,cAAsB;IAEtB,IAAI,iBAAiB,GAAY,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,iBAAiB,GAAG,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,mEAAmE;QACnE,gDAAgD;IAClD,CAAC;IACD,OAAO;QACL,EAAE,EAAE,KAAK;QACT,WAAW,EAAE,KAAK;QAClB,SAAS,EAAE,IAAI;QACf,KAAK;QACL,eAAe,EAAE,cAAc;QAC/B,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;4DAI4D;AAC5D,SAAS,aAAa,CACpB,QAA4B,EAC5B,QAA4B;IAE5B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC3E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,KAAK,SAAS,EAAE,CAAC;AAClE,CAAC;AAED;;;wDAGwD;AACxD,MAAM,oBAAoB,GACxB,kFAAkF;IAClF,+FAA+F,CAAC;AAElG;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAA0B,EAAE,IAAc;IACtE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,uCAAuC,EAAE,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;QAClC,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,MAAM,EACN,iBAAiB,cAAc,uBAAuB,KAAK,CAAC,MAAM,EAAE,EACpE,CAAC,CACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,IAAI,cAAkC,CAAC;IACvC;;;4CAGwC;IACxC,IAAI,gBAAyB,CAAC;IAC9B,MAAM,QAAQ,GAAG,GAAW,EAAE,CAC5B,gBAAgB,KAAK,mBAAmB,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,GAAY,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,SAAS,EACT,+EAA+E,EAC/E,OAAO,CAAC,MAAM,CACf,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,GAAgC,CAAC;QAEpD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAsB,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACzF,CAAC;YACD,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;YACzB,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBACf,MAAM,aAAa,GACjB,CAAC,CAAC,MAAM,KAAK,kBAAkB,IAAI,CAAC,CAAC,UAAU;oBAC7C,CAAC,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE;oBAClD,CAAC,CAAC,EAAE,CAAC;gBACT,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,SAAS,CAAC,CAAC,MAAM,IAAI,WAAW,GAAG,aAAa,GAAG,QAAQ,EAAE,EAAE,EAC/D,OAAO,CAAC,MAAM,CACf,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;gBAChB,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,mBAAmB,CAAC,CAAC,QAAQ,IAAI,EAAE,kFAAkF,EACrH,OAAO,CAAC,MAAM,CACf,CAAC;YACJ,CAAC;YACD,cAAc,GAAG,CAAC,CAAC,QAAQ,CAAC;YAC5B,gBAAgB,GAAG,SAAS,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvC,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,UAAU,CAAC,QAA6B,CAAC;YACxD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACzF,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC5B,mEAAmE;gBACnE,8DAA8D;gBAC9D,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,+CAA+C,OAAO,CAAC,MAAM,CAAC,UAAU,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,UAAU,EAC9G,OAAO,CAAC,MAAM,CACf,CAAC;YACJ,CAAC;YACD,gBAAgB,GAAG,SAAS,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,UAAU,CAAC,KAAwB,CAAC;YACnD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC9E,IAAI,QAAQ;gBAAE,cAAc,GAAG,SAAS,CAAC;YACzC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO,oBAAoB,CACzB,IAAI,EACJ,CAAC,EACD,IAAI,EACJ,0EAA0E,EAC1E,OAAO,CAAC,MAAM,CACf,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;gBACtC,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,QAAQ,EAAE,QAAQ;aACnB,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACzF,CAAC;YACD,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAClD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAsB,CAAC;YACjD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC9E,IAAI,QAAQ;gBAAE,cAAc,GAAG,SAAS,CAAC;YACzC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;gBACrC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,QAAQ,EAAE,QAAQ;aACnB,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACzF,CAAC;YACD,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAClD,SAAS;QACX,CAAC;QAED,qDAAqD;QACrD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAwB,CAAC;QACnD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC9E,IAAI,QAAQ;YAAE,cAAc,GAAG,SAAS,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YACtC,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,oBAAoB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,GAAG,QAAQ,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACzF,CAAC;QACD,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AAChE,CAAC"}
|