@kaitranntt/ccs 7.74.0-dev.1 → 7.74.0-dev.11
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/api/services/profile-writer.d.ts +1 -1
- package/dist/api/services/profile-writer.d.ts.map +1 -1
- package/dist/api/services/profile-writer.js +11 -5
- package/dist/api/services/profile-writer.js.map +1 -1
- package/dist/bin/ccsxp-runtime.d.ts +8 -0
- package/dist/bin/ccsxp-runtime.d.ts.map +1 -1
- package/dist/bin/ccsxp-runtime.js +60 -3
- package/dist/bin/ccsxp-runtime.js.map +1 -1
- package/dist/cliproxy/binary/lifecycle.d.ts.map +1 -1
- package/dist/cliproxy/binary/lifecycle.js +2 -1
- package/dist/cliproxy/binary/lifecycle.js.map +1 -1
- package/dist/cliproxy/codex-plan-compatibility.d.ts.map +1 -1
- package/dist/cliproxy/codex-plan-compatibility.js +1 -0
- package/dist/cliproxy/codex-plan-compatibility.js.map +1 -1
- package/dist/cliproxy/model-catalog.d.ts.map +1 -1
- package/dist/cliproxy/model-catalog.js +12 -0
- package/dist/cliproxy/model-catalog.js.map +1 -1
- package/dist/cliproxy/service-manager.d.ts +17 -1
- package/dist/cliproxy/service-manager.d.ts.map +1 -1
- package/dist/cliproxy/service-manager.js +10 -5
- package/dist/cliproxy/service-manager.js.map +1 -1
- package/dist/cliproxy/sync/profile-mapper.d.ts.map +1 -1
- package/dist/cliproxy/sync/profile-mapper.js +21 -0
- package/dist/cliproxy/sync/profile-mapper.js.map +1 -1
- package/dist/cliproxy/types.d.ts +8 -0
- package/dist/cliproxy/types.d.ts.map +1 -1
- package/dist/cliproxy/types.js.map +1 -1
- package/dist/commands/api-command/create-command.d.ts.map +1 -1
- package/dist/commands/api-command/create-command.js +4 -1
- package/dist/commands/api-command/create-command.js.map +1 -1
- package/dist/commands/api-command/help.d.ts.map +1 -1
- package/dist/commands/api-command/help.js +4 -0
- package/dist/commands/api-command/help.js.map +1 -1
- package/dist/commands/api-command/shared.d.ts +2 -1
- package/dist/commands/api-command/shared.d.ts.map +1 -1
- package/dist/commands/api-command/shared.js +9 -0
- package/dist/commands/api-command/shared.js.map +1 -1
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +4 -1
- package/dist/commands/command-catalog.js.map +1 -1
- package/dist/targets/target-metadata.js +1 -1
- package/dist/targets/target-metadata.js.map +1 -1
- package/dist/ui/assets/{accounts-D0Z5AVKW.js → accounts-ld6H4qVb.js} +1 -1
- package/dist/ui/assets/{alert-dialog-CzJucE0e.js → alert-dialog-BZ2goqtW.js} +1 -1
- package/dist/ui/assets/{api-DXAf4i-v.js → api-CthvA4sH.js} +1 -1
- package/dist/ui/assets/{auth-section-BrnnHBi-.js → auth-section-o5qejfmB.js} +1 -1
- package/dist/ui/assets/{backups-section-DCBcfZ-C.js → backups-section-DH2I1yD9.js} +1 -1
- package/dist/ui/assets/{channels-BSapONLx.js → channels-PcQ1oO0o.js} +1 -1
- package/dist/ui/assets/{checkbox-Bd7X5Xud.js → checkbox-DehBjrNH.js} +1 -1
- package/dist/ui/assets/{claude-extension-BYJxm4B5.js → claude-extension-PyHYNmSG.js} +1 -1
- package/dist/ui/assets/{cliproxy-ai-providers-D7r2Us_Y.js → cliproxy-ai-providers-BEHZy9gR.js} +1 -1
- package/dist/ui/assets/{cliproxy-control-panel-Cmo3ArVL.js → cliproxy-control-panel-34szpAk4.js} +1 -1
- package/dist/ui/assets/{cliproxy-G5JuFm2j.js → cliproxy-lrpHXFMA.js} +1 -1
- package/dist/ui/assets/codex-UKB2QUN1.js +27 -0
- package/dist/ui/assets/{confirm-dialog--zJgz4y0.js → confirm-dialog-64G67ESH.js} +1 -1
- package/dist/ui/assets/{copilot-2ARJ9YVb.js → copilot-Bd-ViL4n.js} +1 -1
- package/dist/ui/assets/{cursor-CQNCrVt0.js → cursor-DH3z6BLJ.js} +1 -1
- package/dist/ui/assets/{droid-Dl5wRjDv.js → droid-Cng3BkQg.js} +1 -1
- package/dist/ui/assets/{globalenv-section-T1imQsSA.js → globalenv-section-D3aT-fYK.js} +1 -1
- package/dist/ui/assets/health-BRqYO0xG.js +1 -0
- package/dist/ui/assets/index-1MP3pDe8.js +1 -0
- package/dist/ui/assets/index-B2XY4MhT.js +72 -0
- package/dist/ui/assets/{index-DH916Tyi.js → index-CDoChLrM.js} +1 -1
- package/dist/ui/assets/{index-fV5BBuAO.js → index-DA5G610p.js} +1 -1
- package/dist/ui/assets/{index-BcLnqcxD.js → index-DJmpCPja.js} +1 -1
- package/dist/ui/assets/{index-DFgCoUVv.js → index-DLIKuUBI.js} +1 -1
- package/dist/ui/assets/{index-CqJFugM4.js → index-FPQVUJ_q.js} +1 -1
- package/dist/ui/assets/index-yeM6bOxL.css +1 -0
- package/dist/ui/assets/{logs-CZsWbq7X.js → logs-DNAtdY6A.js} +1 -1
- package/dist/ui/assets/masked-input-B4x8rBbs.js +1 -0
- package/dist/ui/assets/proxy-g4_N-fbB.js +9 -0
- package/dist/ui/assets/{proxy-status-widget-D82T2X4F.js → proxy-status-widget-EuDHDJAP.js} +1 -1
- package/dist/ui/assets/{raw-json-settings-editor-panel-DNmb_vR-.js → raw-json-settings-editor-panel-DZRYrywv.js} +1 -1
- package/dist/ui/assets/{searchable-select--iFe00dY.js → searchable-select-CwJpfFVb.js} +1 -1
- package/dist/ui/assets/{separator-CaGbNw8E.js → separator-CD-HBQ24.js} +1 -1
- package/dist/ui/assets/{shared-Cgk48Wu3.js → shared-BlqdoNm4.js} +1 -1
- package/dist/ui/assets/{table-CKuoPAz4.js → table-FmKRMU4a.js} +1 -1
- package/dist/ui/assets/updates-Bo-HBoN0.js +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/web-server/routes/profile-routes.d.ts.map +1 -1
- package/dist/web-server/routes/profile-routes.js +13 -3
- package/dist/web-server/routes/profile-routes.js.map +1 -1
- package/dist/web-server/routes/route-helpers.d.ts +1 -0
- package/dist/web-server/routes/route-helpers.d.ts.map +1 -1
- package/dist/web-server/routes/route-helpers.js +11 -0
- package/dist/web-server/routes/route-helpers.js.map +1 -1
- package/lib/mcp/ccs-browser-server.cjs +309 -121
- package/package.json +1 -1
- package/dist/ui/assets/codex-4VNBJ4Nb.js +0 -27
- package/dist/ui/assets/health-CNous3WN.js +0 -1
- package/dist/ui/assets/index-2X8-14xr.js +0 -72
- package/dist/ui/assets/index-Be3dhMW3.js +0 -9
- package/dist/ui/assets/index-DuTB1_9r.css +0 -1
- package/dist/ui/assets/masked-input-_EkW1Pzo.js +0 -1
- package/dist/ui/assets/updates-Dr8Yq-Pm.js +0 -1
|
@@ -298,7 +298,8 @@ function getTools() {
|
|
|
298
298
|
pageIndex: {
|
|
299
299
|
type: 'integer',
|
|
300
300
|
minimum: 0,
|
|
301
|
-
description:
|
|
301
|
+
description:
|
|
302
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
302
303
|
},
|
|
303
304
|
},
|
|
304
305
|
additionalProperties: false,
|
|
@@ -314,7 +315,8 @@ function getTools() {
|
|
|
314
315
|
pageIndex: {
|
|
315
316
|
type: 'integer',
|
|
316
317
|
minimum: 0,
|
|
317
|
-
description:
|
|
318
|
+
description:
|
|
319
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
318
320
|
},
|
|
319
321
|
},
|
|
320
322
|
additionalProperties: false,
|
|
@@ -330,7 +332,8 @@ function getTools() {
|
|
|
330
332
|
pageIndex: {
|
|
331
333
|
type: 'integer',
|
|
332
334
|
minimum: 0,
|
|
333
|
-
description:
|
|
335
|
+
description:
|
|
336
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
334
337
|
},
|
|
335
338
|
},
|
|
336
339
|
additionalProperties: false,
|
|
@@ -346,7 +349,8 @@ function getTools() {
|
|
|
346
349
|
pageIndex: {
|
|
347
350
|
type: 'integer',
|
|
348
351
|
minimum: 0,
|
|
349
|
-
description:
|
|
352
|
+
description:
|
|
353
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
350
354
|
},
|
|
351
355
|
url: {
|
|
352
356
|
type: 'string',
|
|
@@ -367,7 +371,8 @@ function getTools() {
|
|
|
367
371
|
pageIndex: {
|
|
368
372
|
type: 'integer',
|
|
369
373
|
minimum: 0,
|
|
370
|
-
description:
|
|
374
|
+
description:
|
|
375
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
371
376
|
},
|
|
372
377
|
selector: {
|
|
373
378
|
type: 'string',
|
|
@@ -376,11 +381,13 @@ function getTools() {
|
|
|
376
381
|
nth: {
|
|
377
382
|
type: 'integer',
|
|
378
383
|
minimum: 0,
|
|
379
|
-
description:
|
|
384
|
+
description:
|
|
385
|
+
'Optional zero-based match index for selectors returning multiple elements.',
|
|
380
386
|
},
|
|
381
387
|
frameSelector: {
|
|
382
388
|
type: 'string',
|
|
383
|
-
description:
|
|
389
|
+
description:
|
|
390
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
384
391
|
},
|
|
385
392
|
pierceShadow: {
|
|
386
393
|
type: 'boolean',
|
|
@@ -388,11 +395,13 @@ function getTools() {
|
|
|
388
395
|
},
|
|
389
396
|
offsetX: {
|
|
390
397
|
type: 'number',
|
|
391
|
-
description:
|
|
398
|
+
description:
|
|
399
|
+
"Optional horizontal offset in CSS pixels from the target element's left edge.",
|
|
392
400
|
},
|
|
393
401
|
offsetY: {
|
|
394
402
|
type: 'number',
|
|
395
|
-
description:
|
|
403
|
+
description:
|
|
404
|
+
"Optional vertical offset in CSS pixels from the target element's top edge.",
|
|
396
405
|
},
|
|
397
406
|
button: {
|
|
398
407
|
type: 'string',
|
|
@@ -419,7 +428,8 @@ function getTools() {
|
|
|
419
428
|
pageIndex: {
|
|
420
429
|
type: 'integer',
|
|
421
430
|
minimum: 0,
|
|
422
|
-
description:
|
|
431
|
+
description:
|
|
432
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
423
433
|
},
|
|
424
434
|
selector: {
|
|
425
435
|
type: 'string',
|
|
@@ -448,7 +458,8 @@ function getTools() {
|
|
|
448
458
|
pageIndex: {
|
|
449
459
|
type: 'integer',
|
|
450
460
|
minimum: 0,
|
|
451
|
-
description:
|
|
461
|
+
description:
|
|
462
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
452
463
|
},
|
|
453
464
|
key: {
|
|
454
465
|
type: 'string',
|
|
@@ -482,7 +493,8 @@ function getTools() {
|
|
|
482
493
|
pageIndex: {
|
|
483
494
|
type: 'integer',
|
|
484
495
|
minimum: 0,
|
|
485
|
-
description:
|
|
496
|
+
description:
|
|
497
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
486
498
|
},
|
|
487
499
|
selector: {
|
|
488
500
|
type: 'string',
|
|
@@ -490,7 +502,8 @@ function getTools() {
|
|
|
490
502
|
},
|
|
491
503
|
frameSelector: {
|
|
492
504
|
type: 'string',
|
|
493
|
-
description:
|
|
505
|
+
description:
|
|
506
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
494
507
|
},
|
|
495
508
|
pierceShadow: {
|
|
496
509
|
type: 'boolean',
|
|
@@ -516,7 +529,8 @@ function getTools() {
|
|
|
516
529
|
},
|
|
517
530
|
{
|
|
518
531
|
name: TOOL_SELECT_PAGE,
|
|
519
|
-
description:
|
|
532
|
+
description:
|
|
533
|
+
'Select the current page target by page index or page id for subsequent browser tool calls.',
|
|
520
534
|
inputSchema: {
|
|
521
535
|
type: 'object',
|
|
522
536
|
properties: {
|
|
@@ -539,7 +553,8 @@ function getTools() {
|
|
|
539
553
|
},
|
|
540
554
|
{
|
|
541
555
|
name: TOOL_CLOSE_PAGE,
|
|
542
|
-
description:
|
|
556
|
+
description:
|
|
557
|
+
'Close a browser page target by page index or page id. Defaults to the selected page.',
|
|
543
558
|
inputSchema: {
|
|
544
559
|
type: 'object',
|
|
545
560
|
properties: {
|
|
@@ -769,7 +784,8 @@ function getTools() {
|
|
|
769
784
|
},
|
|
770
785
|
{
|
|
771
786
|
name: TOOL_START_RECORDING,
|
|
772
|
-
description:
|
|
787
|
+
description:
|
|
788
|
+
'Start recording real browser interactions on the selected page and store them as structured steps.',
|
|
773
789
|
inputSchema: {
|
|
774
790
|
type: 'object',
|
|
775
791
|
properties: {
|
|
@@ -781,7 +797,8 @@ function getTools() {
|
|
|
781
797
|
},
|
|
782
798
|
{
|
|
783
799
|
name: TOOL_STOP_RECORDING,
|
|
784
|
-
description:
|
|
800
|
+
description:
|
|
801
|
+
'Stop the active browser recording session and keep the recorded result in session-local state.',
|
|
785
802
|
inputSchema: {
|
|
786
803
|
type: 'object',
|
|
787
804
|
properties: {},
|
|
@@ -808,7 +825,8 @@ function getTools() {
|
|
|
808
825
|
},
|
|
809
826
|
{
|
|
810
827
|
name: TOOL_START_REPLAY,
|
|
811
|
-
description:
|
|
828
|
+
description:
|
|
829
|
+
'Start replaying a sequence of structured Browser MCP steps on the selected page.',
|
|
812
830
|
inputSchema: {
|
|
813
831
|
type: 'object',
|
|
814
832
|
properties: {
|
|
@@ -840,7 +858,8 @@ function getTools() {
|
|
|
840
858
|
},
|
|
841
859
|
{
|
|
842
860
|
name: TOOL_START_ORCHESTRATION,
|
|
843
|
-
description:
|
|
861
|
+
description:
|
|
862
|
+
'Start an orchestration session that runs fixed browser workflow blocks on the selected page.',
|
|
844
863
|
inputSchema: {
|
|
845
864
|
type: 'object',
|
|
846
865
|
properties: {
|
|
@@ -854,7 +873,8 @@ function getTools() {
|
|
|
854
873
|
},
|
|
855
874
|
{
|
|
856
875
|
name: TOOL_GET_ORCHESTRATION,
|
|
857
|
-
description:
|
|
876
|
+
description:
|
|
877
|
+
'Read the current orchestration status and result summary from session-local state.',
|
|
858
878
|
inputSchema: {
|
|
859
879
|
type: 'object',
|
|
860
880
|
properties: {},
|
|
@@ -863,7 +883,8 @@ function getTools() {
|
|
|
863
883
|
},
|
|
864
884
|
{
|
|
865
885
|
name: TOOL_CANCEL_ORCHESTRATION,
|
|
866
|
-
description:
|
|
886
|
+
description:
|
|
887
|
+
'Cancel the active orchestration session and keep the summary in session-local state.',
|
|
867
888
|
inputSchema: {
|
|
868
889
|
type: 'object',
|
|
869
890
|
properties: {},
|
|
@@ -872,7 +893,8 @@ function getTools() {
|
|
|
872
893
|
},
|
|
873
894
|
{
|
|
874
895
|
name: TOOL_EXPORT_ARTIFACT,
|
|
875
|
-
description:
|
|
896
|
+
description:
|
|
897
|
+
'Export the current recording, replay, or orchestration artifact to a local JSON file.',
|
|
876
898
|
inputSchema: {
|
|
877
899
|
type: 'object',
|
|
878
900
|
properties: {
|
|
@@ -885,7 +907,8 @@ function getTools() {
|
|
|
885
907
|
},
|
|
886
908
|
{
|
|
887
909
|
name: TOOL_IMPORT_ARTIFACT,
|
|
888
|
-
description:
|
|
910
|
+
description:
|
|
911
|
+
'Import a recording, replay, or orchestration artifact from a local JSON file into session-local state.',
|
|
889
912
|
inputSchema: {
|
|
890
913
|
type: 'object',
|
|
891
914
|
properties: {
|
|
@@ -926,7 +949,8 @@ function getTools() {
|
|
|
926
949
|
pageIndex: {
|
|
927
950
|
type: 'integer',
|
|
928
951
|
minimum: 0,
|
|
929
|
-
description:
|
|
952
|
+
description:
|
|
953
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
930
954
|
},
|
|
931
955
|
fullPage: {
|
|
932
956
|
type: 'boolean',
|
|
@@ -946,7 +970,8 @@ function getTools() {
|
|
|
946
970
|
pageIndex: {
|
|
947
971
|
type: 'integer',
|
|
948
972
|
minimum: 0,
|
|
949
|
-
description:
|
|
973
|
+
description:
|
|
974
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
950
975
|
},
|
|
951
976
|
selector: {
|
|
952
977
|
type: 'string',
|
|
@@ -955,11 +980,13 @@ function getTools() {
|
|
|
955
980
|
nth: {
|
|
956
981
|
type: 'integer',
|
|
957
982
|
minimum: 0,
|
|
958
|
-
description:
|
|
983
|
+
description:
|
|
984
|
+
'Optional zero-based match index for selectors returning multiple elements.',
|
|
959
985
|
},
|
|
960
986
|
frameSelector: {
|
|
961
987
|
type: 'string',
|
|
962
|
-
description:
|
|
988
|
+
description:
|
|
989
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
963
990
|
},
|
|
964
991
|
pierceShadow: {
|
|
965
992
|
type: 'boolean',
|
|
@@ -994,7 +1021,8 @@ function getTools() {
|
|
|
994
1021
|
pageIndex: {
|
|
995
1022
|
type: 'integer',
|
|
996
1023
|
minimum: 0,
|
|
997
|
-
description:
|
|
1024
|
+
description:
|
|
1025
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
998
1026
|
},
|
|
999
1027
|
expression: {
|
|
1000
1028
|
type: 'string',
|
|
@@ -1020,7 +1048,8 @@ function getTools() {
|
|
|
1020
1048
|
pageIndex: {
|
|
1021
1049
|
type: 'integer',
|
|
1022
1050
|
minimum: 0,
|
|
1023
|
-
description:
|
|
1051
|
+
description:
|
|
1052
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
1024
1053
|
},
|
|
1025
1054
|
selector: {
|
|
1026
1055
|
type: 'string',
|
|
@@ -1028,7 +1057,8 @@ function getTools() {
|
|
|
1028
1057
|
},
|
|
1029
1058
|
frameSelector: {
|
|
1030
1059
|
type: 'string',
|
|
1031
|
-
description:
|
|
1060
|
+
description:
|
|
1061
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
1032
1062
|
},
|
|
1033
1063
|
pierceShadow: {
|
|
1034
1064
|
type: 'boolean',
|
|
@@ -1049,7 +1079,8 @@ function getTools() {
|
|
|
1049
1079
|
pageIndex: {
|
|
1050
1080
|
type: 'integer',
|
|
1051
1081
|
minimum: 0,
|
|
1052
|
-
description:
|
|
1082
|
+
description:
|
|
1083
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
1053
1084
|
},
|
|
1054
1085
|
selector: {
|
|
1055
1086
|
type: 'string',
|
|
@@ -1058,11 +1089,13 @@ function getTools() {
|
|
|
1058
1089
|
nth: {
|
|
1059
1090
|
type: 'integer',
|
|
1060
1091
|
minimum: 0,
|
|
1061
|
-
description:
|
|
1092
|
+
description:
|
|
1093
|
+
'Optional zero-based match index for selectors returning multiple elements.',
|
|
1062
1094
|
},
|
|
1063
1095
|
frameSelector: {
|
|
1064
1096
|
type: 'string',
|
|
1065
|
-
description:
|
|
1097
|
+
description:
|
|
1098
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
1066
1099
|
},
|
|
1067
1100
|
pierceShadow: {
|
|
1068
1101
|
type: 'boolean',
|
|
@@ -1088,7 +1121,8 @@ function getTools() {
|
|
|
1088
1121
|
pageIndex: {
|
|
1089
1122
|
type: 'integer',
|
|
1090
1123
|
minimum: 0,
|
|
1091
|
-
description:
|
|
1124
|
+
description:
|
|
1125
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
1092
1126
|
},
|
|
1093
1127
|
selector: {
|
|
1094
1128
|
type: 'string',
|
|
@@ -1096,7 +1130,8 @@ function getTools() {
|
|
|
1096
1130
|
},
|
|
1097
1131
|
frameSelector: {
|
|
1098
1132
|
type: 'string',
|
|
1099
|
-
description:
|
|
1133
|
+
description:
|
|
1134
|
+
'Optional CSS selector for an iframe whose document should be used as the query root.',
|
|
1100
1135
|
},
|
|
1101
1136
|
pierceShadow: {
|
|
1102
1137
|
type: 'boolean',
|
|
@@ -1116,7 +1151,8 @@ function getTools() {
|
|
|
1116
1151
|
pageIndex: {
|
|
1117
1152
|
type: 'integer',
|
|
1118
1153
|
minimum: 0,
|
|
1119
|
-
description:
|
|
1154
|
+
description:
|
|
1155
|
+
'Optional zero-based page index from browser_get_session_info. Defaults to the first page.',
|
|
1120
1156
|
},
|
|
1121
1157
|
timeoutMs: {
|
|
1122
1158
|
type: 'integer',
|
|
@@ -1135,14 +1171,25 @@ function getTools() {
|
|
|
1135
1171
|
];
|
|
1136
1172
|
}
|
|
1137
1173
|
|
|
1138
|
-
async function fetchJson(url) {
|
|
1139
|
-
const response = await fetch(url);
|
|
1174
|
+
async function fetchJson(url, options = undefined) {
|
|
1175
|
+
const response = await fetch(url, options);
|
|
1140
1176
|
if (!response.ok) {
|
|
1141
1177
|
throw new Error(`HTTP ${response.status} for ${url}`);
|
|
1142
1178
|
}
|
|
1143
1179
|
return await response.json();
|
|
1144
1180
|
}
|
|
1145
1181
|
|
|
1182
|
+
function isUsablePageTarget(target) {
|
|
1183
|
+
if (!target || typeof target !== 'object' || target.type !== 'page') {
|
|
1184
|
+
return false;
|
|
1185
|
+
}
|
|
1186
|
+
const url = typeof target.url === 'string' ? target.url : '';
|
|
1187
|
+
if (url.startsWith('chrome://omnibox-popup') || url.startsWith('chrome://top-chrome')) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
return true;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1146
1193
|
function getHttpUrl() {
|
|
1147
1194
|
const value = process.env.CCS_BROWSER_DEVTOOLS_HTTP_URL;
|
|
1148
1195
|
if (!value) {
|
|
@@ -1157,16 +1204,14 @@ async function listPageTargets() {
|
|
|
1157
1204
|
throw new Error('Browser MCP received an invalid /json/list response.');
|
|
1158
1205
|
}
|
|
1159
1206
|
|
|
1160
|
-
return targets
|
|
1161
|
-
|
|
1162
|
-
.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
typeof target.webSocketDebuggerUrl === 'string' ? target.webSocketDebuggerUrl : '',
|
|
1169
|
-
}));
|
|
1207
|
+
return targets.filter(isUsablePageTarget).map((target) => ({
|
|
1208
|
+
id: typeof target.id === 'string' ? target.id : '',
|
|
1209
|
+
title: typeof target.title === 'string' ? target.title : '',
|
|
1210
|
+
url: typeof target.url === 'string' ? target.url : '',
|
|
1211
|
+
type: typeof target.type === 'string' ? target.type : 'page',
|
|
1212
|
+
webSocketDebuggerUrl:
|
|
1213
|
+
typeof target.webSocketDebuggerUrl === 'string' ? target.webSocketDebuggerUrl : '',
|
|
1214
|
+
}));
|
|
1170
1215
|
}
|
|
1171
1216
|
|
|
1172
1217
|
function parsePageIndex(toolArgs) {
|
|
@@ -1314,9 +1359,13 @@ function parseOptionalHeaderMatchers(value) {
|
|
|
1314
1359
|
}
|
|
1315
1360
|
const name = requireNonEmptyString(entry.name, 'headerMatchers.name');
|
|
1316
1361
|
const valueIncludes =
|
|
1317
|
-
entry.valueIncludes === undefined
|
|
1362
|
+
entry.valueIncludes === undefined
|
|
1363
|
+
? ''
|
|
1364
|
+
: requireNonEmptyString(entry.valueIncludes, 'headerMatchers.valueIncludes');
|
|
1318
1365
|
const valueRegex =
|
|
1319
|
-
entry.valueRegex === undefined
|
|
1366
|
+
entry.valueRegex === undefined
|
|
1367
|
+
? ''
|
|
1368
|
+
: requireNonEmptyString(entry.valueRegex, 'headerMatchers.valueRegex');
|
|
1320
1369
|
if (!valueIncludes && !valueRegex) {
|
|
1321
1370
|
throw new Error('headerMatchers entry must include valueIncludes or valueRegex');
|
|
1322
1371
|
}
|
|
@@ -1342,7 +1391,14 @@ function validateInterceptMatcherSet({
|
|
|
1342
1391
|
if (urlPattern && urlRegex) {
|
|
1343
1392
|
throw new Error('urlPattern and urlRegex cannot be used together');
|
|
1344
1393
|
}
|
|
1345
|
-
if (
|
|
1394
|
+
if (
|
|
1395
|
+
!urlIncludes &&
|
|
1396
|
+
!method &&
|
|
1397
|
+
!resourceType &&
|
|
1398
|
+
!urlPattern &&
|
|
1399
|
+
!urlRegex &&
|
|
1400
|
+
headerMatchers.length === 0
|
|
1401
|
+
) {
|
|
1346
1402
|
throw new Error('at least one matching condition is required');
|
|
1347
1403
|
}
|
|
1348
1404
|
}
|
|
@@ -1505,7 +1561,9 @@ function resolveTargetPage(pages, toolArgs, defaultSelectedId = selectedPageId,
|
|
|
1505
1561
|
const selectedIndex = findPageIndexById(pages, defaultSelectedId);
|
|
1506
1562
|
if (selectedIndex === -1) {
|
|
1507
1563
|
if (!allowImplicitFallback && defaultSelectedId) {
|
|
1508
|
-
throw new Error(
|
|
1564
|
+
throw new Error(
|
|
1565
|
+
'Selected page is no longer available; specify pageIndex or pageId explicitly.'
|
|
1566
|
+
);
|
|
1509
1567
|
}
|
|
1510
1568
|
const fallbackPage = pages[0];
|
|
1511
1569
|
if (!fallbackPage) {
|
|
@@ -1526,7 +1584,9 @@ async function getSelectedPage(toolArgs) {
|
|
|
1526
1584
|
const pageIndex = parsePageIndex(toolArgs);
|
|
1527
1585
|
const page = pages[pageIndex];
|
|
1528
1586
|
if (!page) {
|
|
1529
|
-
throw new Error(
|
|
1587
|
+
throw new Error(
|
|
1588
|
+
`Browser MCP page index ${pageIndex} is out of range (found ${pages.length} pages).`
|
|
1589
|
+
);
|
|
1530
1590
|
}
|
|
1531
1591
|
if (!page.webSocketDebuggerUrl) {
|
|
1532
1592
|
throw new Error(`Browser MCP page ${pageIndex} does not expose a websocket debugger URL.`);
|
|
@@ -1655,7 +1715,11 @@ async function getBrowserTarget() {
|
|
|
1655
1715
|
const browserTarget = Array.isArray(targets)
|
|
1656
1716
|
? targets.find((target) => target && typeof target === 'object' && target.type === 'browser')
|
|
1657
1717
|
: null;
|
|
1658
|
-
if (
|
|
1718
|
+
if (
|
|
1719
|
+
!browserTarget ||
|
|
1720
|
+
typeof browserTarget.webSocketDebuggerUrl !== 'string' ||
|
|
1721
|
+
!browserTarget.webSocketDebuggerUrl
|
|
1722
|
+
) {
|
|
1659
1723
|
throw new Error('browser-level download events are unavailable');
|
|
1660
1724
|
}
|
|
1661
1725
|
return browserTarget;
|
|
@@ -1795,11 +1859,15 @@ async function ensureBrowserDownloadSession() {
|
|
|
1795
1859
|
receivedBytes: Number(message.params?.receivedBytes || 0),
|
|
1796
1860
|
totalBytes: Number(message.params?.totalBytes || 0),
|
|
1797
1861
|
savedPath: typeof message.params?.filePath === 'string' ? message.params.filePath : '',
|
|
1798
|
-
finishedAt:
|
|
1862
|
+
finishedAt:
|
|
1863
|
+
status === 'completed' || status === 'canceled' ? new Date().toISOString() : '',
|
|
1799
1864
|
});
|
|
1800
1865
|
}
|
|
1801
1866
|
})();
|
|
1802
|
-
activityChain = activityChain
|
|
1867
|
+
activityChain = activityChain
|
|
1868
|
+
.catch(() => {})
|
|
1869
|
+
.then(() => activity)
|
|
1870
|
+
.catch(() => {});
|
|
1803
1871
|
void activity.catch(() => {});
|
|
1804
1872
|
});
|
|
1805
1873
|
|
|
@@ -1836,7 +1904,7 @@ async function evaluateInPage(page, kind) {
|
|
|
1836
1904
|
throw new Error(result.description || 'DevTools evaluation returned an error.');
|
|
1837
1905
|
}
|
|
1838
1906
|
|
|
1839
|
-
return typeof result.value === 'string' ? result.value : result.value ?? '';
|
|
1907
|
+
return typeof result.value === 'string' ? result.value : (result.value ?? '');
|
|
1840
1908
|
}
|
|
1841
1909
|
|
|
1842
1910
|
async function evaluateExpression(page, expression) {
|
|
@@ -1854,7 +1922,7 @@ async function evaluateExpression(page, expression) {
|
|
|
1854
1922
|
throw new Error(result.description || 'DevTools evaluation returned an error.');
|
|
1855
1923
|
}
|
|
1856
1924
|
|
|
1857
|
-
return typeof result.value === 'string' ? result.value : result.value ?? '';
|
|
1925
|
+
return typeof result.value === 'string' ? result.value : (result.value ?? '');
|
|
1858
1926
|
}
|
|
1859
1927
|
|
|
1860
1928
|
async function withPageCommandSession(page, callback) {
|
|
@@ -2084,7 +2152,10 @@ function requireOptionalStringArray(value, label, allowedValues) {
|
|
|
2084
2152
|
if (value === undefined) {
|
|
2085
2153
|
return [];
|
|
2086
2154
|
}
|
|
2087
|
-
if (
|
|
2155
|
+
if (
|
|
2156
|
+
!Array.isArray(value) ||
|
|
2157
|
+
value.some((item) => typeof item !== 'string' || item.trim() === '')
|
|
2158
|
+
) {
|
|
2088
2159
|
throw new Error(`${label} must be an array of non-empty strings`);
|
|
2089
2160
|
}
|
|
2090
2161
|
const normalized = value.map((item) => item.trim());
|
|
@@ -2282,7 +2353,10 @@ function buildScopedMatchesExpression(selector, nth, frameSelector, pierceShadow
|
|
|
2282
2353
|
}
|
|
2283
2354
|
|
|
2284
2355
|
async function getScopedDiagnostics(page, selector, nth, frameSelector, pierceShadow) {
|
|
2285
|
-
const raw = await evaluateExpression(
|
|
2356
|
+
const raw = await evaluateExpression(
|
|
2357
|
+
page,
|
|
2358
|
+
buildScopedMatchesExpression(selector, nth, frameSelector, pierceShadow)
|
|
2359
|
+
);
|
|
2286
2360
|
return JSON.parse(raw);
|
|
2287
2361
|
}
|
|
2288
2362
|
|
|
@@ -2573,9 +2647,7 @@ function readArtifactFile(filePath) {
|
|
|
2573
2647
|
throw new Error('artifact file is not a regular file');
|
|
2574
2648
|
}
|
|
2575
2649
|
if (stat.size > MAX_ARTIFACT_FILE_BYTES) {
|
|
2576
|
-
throw new Error(
|
|
2577
|
-
`artifact file exceeds maximum size of ${MAX_ARTIFACT_FILE_BYTES} bytes`
|
|
2578
|
-
);
|
|
2650
|
+
throw new Error(`artifact file exceeds maximum size of ${MAX_ARTIFACT_FILE_BYTES} bytes`);
|
|
2579
2651
|
}
|
|
2580
2652
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
2581
2653
|
let parsed;
|
|
@@ -2590,7 +2662,11 @@ function readArtifactFile(filePath) {
|
|
|
2590
2662
|
if (parsed.version !== 1) {
|
|
2591
2663
|
throw new Error('unsupported artifact version');
|
|
2592
2664
|
}
|
|
2593
|
-
if (
|
|
2665
|
+
if (
|
|
2666
|
+
typeof parsed.kind !== 'string' ||
|
|
2667
|
+
typeof parsed.name !== 'string' ||
|
|
2668
|
+
!('payload' in parsed)
|
|
2669
|
+
) {
|
|
2594
2670
|
throw new Error('invalid artifact payload');
|
|
2595
2671
|
}
|
|
2596
2672
|
return parsed;
|
|
@@ -2667,10 +2743,7 @@ function formatOrchestrationSummary(session) {
|
|
|
2667
2743
|
}
|
|
2668
2744
|
|
|
2669
2745
|
async function waitForSessionToSettle(task) {
|
|
2670
|
-
await Promise.race([
|
|
2671
|
-
task.then(() => undefined),
|
|
2672
|
-
sleep(SESSION_START_SETTLE_WINDOW_MS),
|
|
2673
|
-
]);
|
|
2746
|
+
await Promise.race([task.then(() => undefined), sleep(SESSION_START_SETTLE_WINDOW_MS)]);
|
|
2674
2747
|
}
|
|
2675
2748
|
|
|
2676
2749
|
function createReplaySession(page, pageIndex, steps) {
|
|
@@ -2961,7 +3034,12 @@ function validateSequenceStep(step) {
|
|
|
2961
3034
|
}
|
|
2962
3035
|
|
|
2963
3036
|
function requireCrossPageRunBlock(block) {
|
|
2964
|
-
if (
|
|
3037
|
+
if (
|
|
3038
|
+
!block.args ||
|
|
3039
|
+
typeof block.args !== 'object' ||
|
|
3040
|
+
!block.args.run ||
|
|
3041
|
+
typeof block.args.run !== 'object'
|
|
3042
|
+
) {
|
|
2965
3043
|
throw new Error('cross-page run block is required');
|
|
2966
3044
|
}
|
|
2967
3045
|
if (CROSS_PAGE_BLOCK_TYPES.has(block.args.run.type)) {
|
|
@@ -3117,7 +3195,8 @@ function matchesObservedEvent(event, observed) {
|
|
|
3117
3195
|
if (event.kind === 'download') {
|
|
3118
3196
|
return (
|
|
3119
3197
|
(!event.urlIncludes || String(observed.url || '').includes(event.urlIncludes)) &&
|
|
3120
|
-
(!event.suggestedFilenameIncludes ||
|
|
3198
|
+
(!event.suggestedFilenameIncludes ||
|
|
3199
|
+
String(observed.suggestedFilename || '').includes(event.suggestedFilenameIncludes))
|
|
3121
3200
|
);
|
|
3122
3201
|
}
|
|
3123
3202
|
return false;
|
|
@@ -3128,7 +3207,10 @@ function sleep(ms) {
|
|
|
3128
3207
|
}
|
|
3129
3208
|
|
|
3130
3209
|
async function getNavigationState(page) {
|
|
3131
|
-
const raw = await evaluateExpression(
|
|
3210
|
+
const raw = await evaluateExpression(
|
|
3211
|
+
page,
|
|
3212
|
+
`JSON.stringify({ href: location.href, readyState: document.readyState })`
|
|
3213
|
+
);
|
|
3132
3214
|
const parsed = JSON.parse(raw);
|
|
3133
3215
|
return {
|
|
3134
3216
|
href: typeof parsed.href === 'string' ? parsed.href : '',
|
|
@@ -3207,10 +3289,16 @@ async function handleClick(toolArgs) {
|
|
|
3207
3289
|
const targetIndex = nth ?? 0;
|
|
3208
3290
|
const frameSelector = parseOptionalNonEmptyString(toolArgs.frameSelector);
|
|
3209
3291
|
const pierceShadow = toolArgs.pierceShadow === true;
|
|
3210
|
-
const offsetX =
|
|
3211
|
-
|
|
3212
|
-
const
|
|
3213
|
-
|
|
3292
|
+
const offsetX =
|
|
3293
|
+
toolArgs.offsetX === undefined ? undefined : requireFiniteNumber(toolArgs.offsetX, 'offsetX');
|
|
3294
|
+
const offsetY =
|
|
3295
|
+
toolArgs.offsetY === undefined ? undefined : requireFiniteNumber(toolArgs.offsetY, 'offsetY');
|
|
3296
|
+
const button =
|
|
3297
|
+
requireEnumString(toolArgs.button, 'button', ['left', 'middle', 'right']) || 'left';
|
|
3298
|
+
const clickCount =
|
|
3299
|
+
toolArgs.clickCount === undefined
|
|
3300
|
+
? 1
|
|
3301
|
+
: requirePositiveInteger(toolArgs.clickCount, 'clickCount');
|
|
3214
3302
|
|
|
3215
3303
|
const expression = `(() => {
|
|
3216
3304
|
const selector = JSON.parse(${JSON.stringify(JSON.stringify(selector))});
|
|
@@ -3445,7 +3533,8 @@ async function handleType(toolArgs) {
|
|
|
3445
3533
|
|
|
3446
3534
|
const raw = await evaluateExpression(page, expression);
|
|
3447
3535
|
const parsed = JSON.parse(raw);
|
|
3448
|
-
const typedLength =
|
|
3536
|
+
const typedLength =
|
|
3537
|
+
typeof parsed.typedLength === 'number' ? parsed.typedLength : String(parsed.value || '').length;
|
|
3449
3538
|
return `pageIndex: ${pageIndex}\nselector: ${selector}\ntypedLength: ${typedLength}\nstatus: typed`;
|
|
3450
3539
|
}
|
|
3451
3540
|
|
|
@@ -3458,7 +3547,8 @@ async function handlePressKey(toolArgs) {
|
|
|
3458
3547
|
'Meta',
|
|
3459
3548
|
'Shift',
|
|
3460
3549
|
]);
|
|
3461
|
-
const repeat =
|
|
3550
|
+
const repeat =
|
|
3551
|
+
toolArgs.repeat === undefined ? 1 : requirePositiveInteger(toolArgs.repeat, 'repeat');
|
|
3462
3552
|
const modifierMask =
|
|
3463
3553
|
(modifiers.includes('Alt') ? 1 : 0) |
|
|
3464
3554
|
(modifiers.includes('Control') ? 2 : 0) |
|
|
@@ -3626,8 +3716,19 @@ async function handleScroll(toolArgs) {
|
|
|
3626
3716
|
return lines.join('\n');
|
|
3627
3717
|
}
|
|
3628
3718
|
|
|
3719
|
+
async function ensureDrawableViewport(page) {
|
|
3720
|
+
const metrics = await sendCdpCommand(page, 'Page.getLayoutMetrics');
|
|
3721
|
+
const viewport = metrics.cssVisualViewport || metrics.visualViewport || {};
|
|
3722
|
+
const width = Number(viewport.clientWidth || 0);
|
|
3723
|
+
const height = Number(viewport.clientHeight || 0);
|
|
3724
|
+
if (width <= 0 || height <= 0) {
|
|
3725
|
+
throw new Error('page has no drawable viewport for screenshot');
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3629
3729
|
async function handleScreenshot(toolArgs) {
|
|
3630
3730
|
const { page, pageIndex } = await getSelectedPage(toolArgs);
|
|
3731
|
+
await ensureDrawableViewport(page);
|
|
3631
3732
|
const fullPage = toolArgs.fullPage === true;
|
|
3632
3733
|
const response = await sendCdpCommand(page, 'Page.captureScreenshot', {
|
|
3633
3734
|
format: 'png',
|
|
@@ -3642,11 +3743,23 @@ async function handleScreenshot(toolArgs) {
|
|
|
3642
3743
|
return `pageIndex: ${pageIndex}\nformat: png\nfullPage: ${fullPage ? 'true' : 'false'}\ndata: ${data}`;
|
|
3643
3744
|
}
|
|
3644
3745
|
|
|
3645
|
-
async function getElementDiagnostics(
|
|
3746
|
+
async function getElementDiagnostics(
|
|
3747
|
+
page,
|
|
3748
|
+
selector,
|
|
3749
|
+
nth,
|
|
3750
|
+
frameSelector = '',
|
|
3751
|
+
pierceShadow = false
|
|
3752
|
+
) {
|
|
3646
3753
|
return await getScopedDiagnostics(page, selector, nth, frameSelector, pierceShadow);
|
|
3647
3754
|
}
|
|
3648
3755
|
|
|
3649
|
-
async function getScrolledElementStateAt(
|
|
3756
|
+
async function getScrolledElementStateAt(
|
|
3757
|
+
page,
|
|
3758
|
+
selector,
|
|
3759
|
+
nth,
|
|
3760
|
+
frameSelector = '',
|
|
3761
|
+
pierceShadow = false
|
|
3762
|
+
) {
|
|
3650
3763
|
const expression = `(() => {
|
|
3651
3764
|
const selector = JSON.parse(${JSON.stringify(JSON.stringify(selector))});
|
|
3652
3765
|
const nth = ${nth === undefined ? 'undefined' : String(nth)};
|
|
@@ -3860,7 +3973,9 @@ function formatQueryResponse(pageIndex, selector, nth, diagnostics, fields) {
|
|
|
3860
3973
|
}
|
|
3861
3974
|
if (diagnostics.targetMissing) {
|
|
3862
3975
|
if (hasTargetSpecificQueryField(fields)) {
|
|
3863
|
-
throw new Error(
|
|
3976
|
+
throw new Error(
|
|
3977
|
+
`element index ${diagnostics.targetIndex} is out of range for selector: ${selector}`
|
|
3978
|
+
);
|
|
3864
3979
|
}
|
|
3865
3980
|
for (const field of fields) {
|
|
3866
3981
|
if (field === 'exists') {
|
|
@@ -3897,7 +4012,11 @@ async function handleWaitFor(toolArgs) {
|
|
|
3897
4012
|
const nth = requireOptionalNonNegativeInteger(toolArgs.nth, 'nth');
|
|
3898
4013
|
const frameSelector = parseOptionalNonEmptyString(toolArgs.frameSelector);
|
|
3899
4014
|
const pierceShadow = toolArgs.pierceShadow === true;
|
|
3900
|
-
const timeoutMs = requirePositiveIntegerOrDefault(
|
|
4015
|
+
const timeoutMs = requirePositiveIntegerOrDefault(
|
|
4016
|
+
toolArgs.timeoutMs,
|
|
4017
|
+
'timeoutMs',
|
|
4018
|
+
DEFAULT_WAIT_TIMEOUT_MS
|
|
4019
|
+
);
|
|
3901
4020
|
const pollIntervalMs = requirePositiveIntegerOrDefault(
|
|
3902
4021
|
toolArgs.pollIntervalMs,
|
|
3903
4022
|
'pollIntervalMs',
|
|
@@ -3993,7 +4112,14 @@ function interpolatePoints(sourcePoint, targetPoint, steps) {
|
|
|
3993
4112
|
return points;
|
|
3994
4113
|
}
|
|
3995
4114
|
|
|
3996
|
-
async function resolveElementCenterPoint(
|
|
4115
|
+
async function resolveElementCenterPoint(
|
|
4116
|
+
page,
|
|
4117
|
+
selector,
|
|
4118
|
+
nth,
|
|
4119
|
+
frameSelector,
|
|
4120
|
+
pierceShadow,
|
|
4121
|
+
missingLabel
|
|
4122
|
+
) {
|
|
3997
4123
|
const state = await getScrolledElementStateAt(page, selector, nth, frameSelector, pierceShadow);
|
|
3998
4124
|
if (!state.exists) {
|
|
3999
4125
|
throw new Error(missingLabel);
|
|
@@ -4041,7 +4167,10 @@ async function handlePointerAction(toolArgs) {
|
|
|
4041
4167
|
}
|
|
4042
4168
|
|
|
4043
4169
|
if (action.type === 'pause') {
|
|
4044
|
-
const durationMs =
|
|
4170
|
+
const durationMs =
|
|
4171
|
+
action.durationMs === undefined
|
|
4172
|
+
? 0
|
|
4173
|
+
: requireNonNegativeInteger(action.durationMs, 'durationMs');
|
|
4045
4174
|
if (durationMs > 0) {
|
|
4046
4175
|
await sleep(durationMs);
|
|
4047
4176
|
}
|
|
@@ -4070,7 +4199,14 @@ async function handlePointerAction(toolArgs) {
|
|
|
4070
4199
|
|
|
4071
4200
|
pointerX = point.x;
|
|
4072
4201
|
pointerY = point.y;
|
|
4073
|
-
await dispatchMousePointerEvent(
|
|
4202
|
+
await dispatchMousePointerEvent(
|
|
4203
|
+
page,
|
|
4204
|
+
'mouseMoved',
|
|
4205
|
+
pointerX,
|
|
4206
|
+
pointerY,
|
|
4207
|
+
pressedButton || 'left',
|
|
4208
|
+
Boolean(pressedButton)
|
|
4209
|
+
);
|
|
4074
4210
|
continue;
|
|
4075
4211
|
}
|
|
4076
4212
|
|
|
@@ -4082,21 +4218,36 @@ async function handlePointerAction(toolArgs) {
|
|
|
4082
4218
|
if (pressedButton) {
|
|
4083
4219
|
throw new Error('pointer state error');
|
|
4084
4220
|
}
|
|
4085
|
-
pressedButton =
|
|
4086
|
-
|
|
4221
|
+
pressedButton =
|
|
4222
|
+
requireEnumString(action.button, 'button', ['left', 'middle', 'right']) || 'left';
|
|
4223
|
+
await dispatchMousePointerEvent(
|
|
4224
|
+
page,
|
|
4225
|
+
'mousePressed',
|
|
4226
|
+
pointerX,
|
|
4227
|
+
pointerY,
|
|
4228
|
+
pressedButton,
|
|
4229
|
+
true
|
|
4230
|
+
);
|
|
4087
4231
|
continue;
|
|
4088
4232
|
}
|
|
4089
4233
|
|
|
4090
4234
|
if (!pressedButton) {
|
|
4091
4235
|
throw new Error('pointer state error');
|
|
4092
4236
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4237
|
+
const releaseButton =
|
|
4238
|
+
requireEnumString(action.button, 'button', ['left', 'middle', 'right']) || pressedButton;
|
|
4239
|
+
if (releaseButton !== pressedButton) {
|
|
4240
|
+
throw new Error('pointer state error');
|
|
4241
|
+
}
|
|
4242
|
+
await dispatchMousePointerEvent(
|
|
4243
|
+
page,
|
|
4244
|
+
'mouseReleased',
|
|
4245
|
+
pointerX,
|
|
4246
|
+
pointerY,
|
|
4247
|
+
releaseButton,
|
|
4248
|
+
false
|
|
4249
|
+
);
|
|
4250
|
+
pressedButton = null;
|
|
4100
4251
|
}
|
|
4101
4252
|
|
|
4102
4253
|
if (pressedButton) {
|
|
@@ -4161,14 +4312,24 @@ async function handleDragElement(toolArgs) {
|
|
|
4161
4312
|
y: requireFiniteNumber(toolArgs.targetY, 'targetY'),
|
|
4162
4313
|
};
|
|
4163
4314
|
|
|
4164
|
-
const steps =
|
|
4315
|
+
const steps =
|
|
4316
|
+
toolArgs.steps === undefined
|
|
4317
|
+
? DEFAULT_DRAG_STEPS
|
|
4318
|
+
: requirePositiveInteger(toolArgs.steps, 'steps');
|
|
4165
4319
|
|
|
4166
4320
|
await dispatchMousePointerEvent(page, 'mouseMoved', sourcePoint.x, sourcePoint.y, 'left', false);
|
|
4167
4321
|
await dispatchMousePointerEvent(page, 'mousePressed', sourcePoint.x, sourcePoint.y, 'left', true);
|
|
4168
4322
|
for (const point of interpolatePoints(sourcePoint, targetPoint, steps)) {
|
|
4169
4323
|
await dispatchMousePointerEvent(page, 'mouseMoved', point.x, point.y, 'left', true);
|
|
4170
4324
|
}
|
|
4171
|
-
await dispatchMousePointerEvent(
|
|
4325
|
+
await dispatchMousePointerEvent(
|
|
4326
|
+
page,
|
|
4327
|
+
'mouseReleased',
|
|
4328
|
+
targetPoint.x,
|
|
4329
|
+
targetPoint.y,
|
|
4330
|
+
'left',
|
|
4331
|
+
false
|
|
4332
|
+
);
|
|
4172
4333
|
|
|
4173
4334
|
return [
|
|
4174
4335
|
`pageIndex: ${pageIndex}`,
|
|
@@ -4197,7 +4358,14 @@ async function handleHover(toolArgs) {
|
|
|
4197
4358
|
throw new Error(`element is hidden or not interactable for selector: ${selector}`);
|
|
4198
4359
|
}
|
|
4199
4360
|
|
|
4200
|
-
await dispatchMousePointerEvent(
|
|
4361
|
+
await dispatchMousePointerEvent(
|
|
4362
|
+
page,
|
|
4363
|
+
'mouseMoved',
|
|
4364
|
+
state.centerPoint.x,
|
|
4365
|
+
state.centerPoint.y,
|
|
4366
|
+
'left',
|
|
4367
|
+
false
|
|
4368
|
+
);
|
|
4201
4369
|
|
|
4202
4370
|
return `pageIndex: ${pageIndex}\nselector: ${selector}${formatScopedSelectorSuffix(frameSelector, pierceShadow)}\nstatus: hovered`;
|
|
4203
4371
|
}
|
|
@@ -4231,6 +4399,7 @@ async function handleElementScreenshot(toolArgs) {
|
|
|
4231
4399
|
if (state.visibleClip.width <= 0 || state.visibleClip.height <= 0) {
|
|
4232
4400
|
throw new Error(`element has empty bounds for selector: ${selector}`);
|
|
4233
4401
|
}
|
|
4402
|
+
await ensureDrawableViewport(page);
|
|
4234
4403
|
|
|
4235
4404
|
const response = await sendCdpCommand(page, 'Page.captureScreenshot', {
|
|
4236
4405
|
format: 'png',
|
|
@@ -4363,7 +4532,11 @@ async function waitForBrowserDownloadEvent(page, timeoutMs, event) {
|
|
|
4363
4532
|
const browserTarget = Array.isArray(targets)
|
|
4364
4533
|
? targets.find((target) => target && typeof target === 'object' && target.type === 'browser')
|
|
4365
4534
|
: null;
|
|
4366
|
-
if (
|
|
4535
|
+
if (
|
|
4536
|
+
!browserTarget ||
|
|
4537
|
+
typeof browserTarget.webSocketDebuggerUrl !== 'string' ||
|
|
4538
|
+
!browserTarget.webSocketDebuggerUrl
|
|
4539
|
+
) {
|
|
4367
4540
|
throw new Error('browser-level download events are unavailable');
|
|
4368
4541
|
}
|
|
4369
4542
|
|
|
@@ -4449,7 +4622,11 @@ async function waitForMatchingEvent({ page, timeoutMs, event }) {
|
|
|
4449
4622
|
|
|
4450
4623
|
async function handleWaitForEvent(toolArgs) {
|
|
4451
4624
|
const { page, pageIndex } = await getSelectedPage(toolArgs);
|
|
4452
|
-
const timeoutMs = requirePositiveIntegerOrDefault(
|
|
4625
|
+
const timeoutMs = requirePositiveIntegerOrDefault(
|
|
4626
|
+
toolArgs.timeoutMs,
|
|
4627
|
+
'timeoutMs',
|
|
4628
|
+
DEFAULT_WAIT_TIMEOUT_MS
|
|
4629
|
+
);
|
|
4453
4630
|
const event = parseEventCondition(toolArgs.event);
|
|
4454
4631
|
const observed = await waitForMatchingEvent({ page, pageIndex, timeoutMs, event });
|
|
4455
4632
|
return `pageIndex: ${pageIndex}\nevent: ${event.kind}\nstatus: observed\ndetail: ${JSON.stringify(observed)}`;
|
|
@@ -4628,7 +4805,9 @@ async function ensureInterceptSession(page) {
|
|
|
4628
4805
|
return;
|
|
4629
4806
|
}
|
|
4630
4807
|
const paused = message.params || {};
|
|
4631
|
-
const matchedRule = getRulesForMatching(page.id).find((rule) =>
|
|
4808
|
+
const matchedRule = getRulesForMatching(page.id).find((rule) =>
|
|
4809
|
+
matchesInterceptRule(rule, paused)
|
|
4810
|
+
);
|
|
4632
4811
|
const action = matchedRule ? matchedRule.action : 'continue';
|
|
4633
4812
|
if (action === 'fail') {
|
|
4634
4813
|
ws.send(
|
|
@@ -4671,7 +4850,10 @@ async function ensureInterceptSession(page) {
|
|
|
4671
4850
|
statusCode: action === 'fulfill' ? matchedRule.statusCode : 0,
|
|
4672
4851
|
});
|
|
4673
4852
|
})();
|
|
4674
|
-
activityChain = activityChain
|
|
4853
|
+
activityChain = activityChain
|
|
4854
|
+
.catch(() => {})
|
|
4855
|
+
.then(() => activity)
|
|
4856
|
+
.catch(() => {});
|
|
4675
4857
|
void activity.catch(() => {});
|
|
4676
4858
|
});
|
|
4677
4859
|
|
|
@@ -4716,7 +4898,7 @@ async function handleOpenPage(toolArgs) {
|
|
|
4716
4898
|
const query = toolArgs?.url
|
|
4717
4899
|
? `?${new URLSearchParams({ url: requireValidHttpUrl(toolArgs.url) }).toString()}`
|
|
4718
4900
|
: '';
|
|
4719
|
-
const createdTarget = await fetchJson(`${getHttpUrl()}/json/new${query}
|
|
4901
|
+
const createdTarget = await fetchJson(`${getHttpUrl()}/json/new${query}`, { method: 'PUT' });
|
|
4720
4902
|
const pageId = typeof createdTarget?.id === 'string' ? createdTarget.id : '';
|
|
4721
4903
|
if (!pageId) {
|
|
4722
4904
|
throw new Error('Browser MCP failed to create a new page target.');
|
|
@@ -4763,7 +4945,10 @@ async function handleClosePage(toolArgs) {
|
|
|
4763
4945
|
if (findPageIndexById(remainingPages, previousSelectedPageId) !== -1) {
|
|
4764
4946
|
selectedPageId = previousSelectedPageId;
|
|
4765
4947
|
} else {
|
|
4766
|
-
selectedPageId = resolveFallbackSelectedPageId(
|
|
4948
|
+
selectedPageId = resolveFallbackSelectedPageId(
|
|
4949
|
+
remainingPages,
|
|
4950
|
+
pageIndex > 0 ? pageIndex - 1 : 0
|
|
4951
|
+
);
|
|
4767
4952
|
}
|
|
4768
4953
|
const selectedIndex = findPageIndexById(remainingPages, selectedPageId);
|
|
4769
4954
|
return [
|
|
@@ -4805,7 +4990,9 @@ async function handleAddInterceptRule(toolArgs) {
|
|
|
4805
4990
|
});
|
|
4806
4991
|
const statusCode = parseOptionalStatusCode(toolArgs.statusCode);
|
|
4807
4992
|
const contentType =
|
|
4808
|
-
toolArgs.contentType === undefined
|
|
4993
|
+
toolArgs.contentType === undefined
|
|
4994
|
+
? ''
|
|
4995
|
+
: requireNonEmptyString(toolArgs.contentType, 'contentType');
|
|
4809
4996
|
const body = parseOptionalBody(toolArgs.body);
|
|
4810
4997
|
const responseHeaders = parseOptionalResponseHeaders(toolArgs.responseHeaders, contentType);
|
|
4811
4998
|
const rule = {
|
|
@@ -4900,7 +5087,8 @@ async function handleListRequests(toolArgs) {
|
|
|
4900
5087
|
async function handleSetDownloadBehavior(toolArgs) {
|
|
4901
5088
|
const behavior = requireEnumString(toolArgs.behavior, 'behavior', ['accept', 'deny']);
|
|
4902
5089
|
const downloadPath = parseOptionalNonEmptyString(toolArgs.downloadPath);
|
|
4903
|
-
const eventsEnabled =
|
|
5090
|
+
const eventsEnabled =
|
|
5091
|
+
toolArgs.eventsEnabled === undefined ? true : toolArgs.eventsEnabled === true;
|
|
4904
5092
|
|
|
4905
5093
|
if (behavior === 'deny' && downloadPath) {
|
|
4906
5094
|
throw new Error('downloadPath is only allowed when behavior=accept');
|
|
@@ -5172,7 +5360,9 @@ async function finalizeRecordingCapture(session) {
|
|
|
5172
5360
|
const warnings = Array.isArray(value.warnings) ? value.warnings : [];
|
|
5173
5361
|
|
|
5174
5362
|
session.rawEvents = rawEvents;
|
|
5175
|
-
session.steps = rawEvents
|
|
5363
|
+
session.steps = rawEvents
|
|
5364
|
+
.map((event) => normalizeRecordedEvent(session.pageId, event))
|
|
5365
|
+
.filter(Boolean);
|
|
5176
5366
|
session.warnings = warnings.map((warning) => String(warning.message || warning));
|
|
5177
5367
|
}
|
|
5178
5368
|
|
|
@@ -5225,9 +5415,7 @@ async function handleStopRecording() {
|
|
|
5225
5415
|
await finalizeRecordingCapture(session);
|
|
5226
5416
|
} catch (error) {
|
|
5227
5417
|
finalizeError = error instanceof Error ? error : new Error(String(error));
|
|
5228
|
-
session.warnings.push(
|
|
5229
|
-
`recording capture finalization failed: ${finalizeError.message}`
|
|
5230
|
-
);
|
|
5418
|
+
session.warnings.push(`recording capture finalization failed: ${finalizeError.message}`);
|
|
5231
5419
|
}
|
|
5232
5420
|
session.status = 'stopped';
|
|
5233
5421
|
session.stoppedAt = new Date().toISOString();
|
|
@@ -5325,7 +5513,9 @@ function buildReplayToolArgs(step, replayPage) {
|
|
|
5325
5513
|
nth: step.nth,
|
|
5326
5514
|
frameSelector: step.frameSelector,
|
|
5327
5515
|
pierceShadow: step.pierceShadow,
|
|
5328
|
-
...(step.args?.targetSelector !== undefined
|
|
5516
|
+
...(step.args?.targetSelector !== undefined
|
|
5517
|
+
? { targetSelector: step.args.targetSelector }
|
|
5518
|
+
: {}),
|
|
5329
5519
|
...(step.args?.targetNth !== undefined ? { targetNth: step.args.targetNth } : {}),
|
|
5330
5520
|
...(step.args?.targetX !== undefined ? { targetX: step.args.targetX } : {}),
|
|
5331
5521
|
...(step.args?.targetY !== undefined ? { targetY: step.args.targetY } : {}),
|
|
@@ -5430,9 +5620,7 @@ async function handleStartReplay(toolArgs) {
|
|
|
5430
5620
|
|
|
5431
5621
|
latestReplaySession = session;
|
|
5432
5622
|
activeReplaySession = session;
|
|
5433
|
-
const task = Promise.resolve().then(() =>
|
|
5434
|
-
runReplaySession(session, { manageActiveState: true })
|
|
5435
|
-
);
|
|
5623
|
+
const task = Promise.resolve().then(() => runReplaySession(session, { manageActiveState: true }));
|
|
5436
5624
|
activeReplayTask = task;
|
|
5437
5625
|
task.catch(() => {
|
|
5438
5626
|
// Session state is recorded in runReplaySession.
|
|
@@ -5718,9 +5906,7 @@ async function handleExportArtifact(toolArgs) {
|
|
|
5718
5906
|
const artifact = buildArtifact(kind, name, payload);
|
|
5719
5907
|
const serialized = JSON.stringify(artifact, null, 2);
|
|
5720
5908
|
if (Buffer.byteLength(serialized, 'utf8') > MAX_ARTIFACT_FILE_BYTES) {
|
|
5721
|
-
throw new Error(
|
|
5722
|
-
`artifact file exceeds maximum size of ${MAX_ARTIFACT_FILE_BYTES} bytes`
|
|
5723
|
-
);
|
|
5909
|
+
throw new Error(`artifact file exceeds maximum size of ${MAX_ARTIFACT_FILE_BYTES} bytes`);
|
|
5724
5910
|
}
|
|
5725
5911
|
fs.writeFileSync(filePath, serialized, { encoding: 'utf8', mode: 0o600 });
|
|
5726
5912
|
return `name: ${name}\nkind: ${kind}\npath: ${filePath}\nstatus: exported`;
|
|
@@ -5736,12 +5922,14 @@ async function handleListArtifacts() {
|
|
|
5736
5922
|
return 'artifacts: []';
|
|
5737
5923
|
}
|
|
5738
5924
|
return entries
|
|
5739
|
-
.map((entry) =>
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5925
|
+
.map((entry) =>
|
|
5926
|
+
[
|
|
5927
|
+
`name: ${entry.name}`,
|
|
5928
|
+
`kind: ${entry.kind}`,
|
|
5929
|
+
`createdAt: ${entry.createdAt}`,
|
|
5930
|
+
`path: ${getArtifactPath(entry.name)}`,
|
|
5931
|
+
].join('\n')
|
|
5932
|
+
)
|
|
5745
5933
|
.join('\n---\n');
|
|
5746
5934
|
}
|
|
5747
5935
|
|