@midscene/ios 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/bin.mjs +120 -131
- package/dist/es/cli.mjs +121 -132
- package/dist/es/index.mjs +120 -131
- package/dist/es/mcp-server.mjs +121 -132
- package/dist/lib/bin.js +118 -129
- package/dist/lib/cli.js +119 -130
- package/dist/lib/index.js +118 -129
- package/dist/lib/mcp-server.js +119 -130
- package/dist/types/index.d.ts +11 -7
- package/dist/types/mcp-server.d.ts +11 -7
- package/package.json +5 -5
- package/static/index.html +1 -1
- package/static/static/css/{index.63b028da.css → index.26c9c911.css} +2 -2
- package/static/static/css/{index.63b028da.css.map → index.26c9c911.css.map} +1 -1
- package/static/static/js/{889.c8e2e995.js → 596.5426be9e.js} +27 -27
- package/static/static/js/596.5426be9e.js.map +1 -0
- package/static/static/js/index.acaa5ec1.js +914 -0
- package/static/static/js/index.acaa5ec1.js.map +1 -0
- package/static/static/js/889.c8e2e995.js.map +0 -1
- package/static/static/js/index.7d3d953d.js +0 -914
- package/static/static/js/index.7d3d953d.js.map +0 -1
- /package/static/static/js/{889.c8e2e995.js.LICENSE.txt → 596.5426be9e.js.LICENSE.txt} +0 -0
- /package/static/static/js/{index.7d3d953d.js.LICENSE.txt → index.acaa5ec1.js.LICENSE.txt} +0 -0
package/dist/lib/index.js
CHANGED
|
@@ -506,16 +506,6 @@ function _define_property(obj, key, value) {
|
|
|
506
506
|
return obj;
|
|
507
507
|
}
|
|
508
508
|
const debugDevice = (0, logger_namespaceObject.getDebug)('ios:device');
|
|
509
|
-
const iosInputParamSchema = core_namespaceObject.z.object({
|
|
510
|
-
value: core_namespaceObject.z.string().describe('The text to input. Provide the final content for replace/append modes, or an empty string when using clear mode to remove existing text.'),
|
|
511
|
-
autoDismissKeyboard: core_namespaceObject.z.boolean().optional().describe('Whether to dismiss the keyboard after input. Defaults to true if not specified. Set to false to keep the keyboard visible after input.'),
|
|
512
|
-
mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
|
|
513
|
-
'replace',
|
|
514
|
-
'clear',
|
|
515
|
-
'typeOnly'
|
|
516
|
-
]).default('replace').optional().describe('Input mode: "replace" (default) - clear the field and input the value; "typeOnly" - type the value directly without clearing the field first; "clear" - clear the field without inputting new text.')),
|
|
517
|
-
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
518
|
-
});
|
|
519
509
|
const WDA_HTTP_METHODS = [
|
|
520
510
|
'GET',
|
|
521
511
|
'POST',
|
|
@@ -524,96 +514,39 @@ const WDA_HTTP_METHODS = [
|
|
|
524
514
|
];
|
|
525
515
|
const DEFAULT_WDA_MJPEG_PORT = 9100;
|
|
526
516
|
class IOSDevice {
|
|
517
|
+
async tapPoint(point) {
|
|
518
|
+
debugDevice(`tap at coordinates (${point.x}, ${point.y})`);
|
|
519
|
+
await this.wdaBackend.tap(Math.round(point.x), Math.round(point.y));
|
|
520
|
+
}
|
|
521
|
+
async doubleTapPoint(point) {
|
|
522
|
+
await this.wdaBackend.doubleTap(Math.round(point.x), Math.round(point.y));
|
|
523
|
+
}
|
|
524
|
+
async longPressPoint(point, duration = 1000) {
|
|
525
|
+
await this.wdaBackend.longPress(Math.round(point.x), Math.round(point.y), duration);
|
|
526
|
+
}
|
|
527
|
+
async swipePoint(start, end, duration = 500) {
|
|
528
|
+
await this.wdaBackend.swipe(Math.round(start.x), Math.round(start.y), Math.round(end.x), Math.round(end.y), duration);
|
|
529
|
+
}
|
|
530
|
+
async clearInputAt(point) {
|
|
531
|
+
if (point) {
|
|
532
|
+
await this.tapPoint(point);
|
|
533
|
+
await (0, utils_namespaceObject.sleep)(100);
|
|
534
|
+
}
|
|
535
|
+
debugDevice('Attempting to clear input with WebDriver Clear API');
|
|
536
|
+
const cleared = await this.wdaBackend.clearActiveElement();
|
|
537
|
+
cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
|
|
538
|
+
}
|
|
527
539
|
actionSpace() {
|
|
540
|
+
const mobileActionContext = {
|
|
541
|
+
input: this.inputPrimitives,
|
|
542
|
+
size: ()=>this.size(),
|
|
543
|
+
sleep: async (timeMs)=>{
|
|
544
|
+
await (0, utils_namespaceObject.sleep)(timeMs);
|
|
545
|
+
},
|
|
546
|
+
getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard
|
|
547
|
+
};
|
|
528
548
|
const defaultActions = [
|
|
529
|
-
(0, device_namespaceObject.
|
|
530
|
-
const element = param.locate;
|
|
531
|
-
external_node_assert_default()(element, 'Element not found, cannot tap');
|
|
532
|
-
await this.mouseClick(element.center[0], element.center[1]);
|
|
533
|
-
}),
|
|
534
|
-
(0, device_namespaceObject.defineActionDoubleClick)(async (param)=>{
|
|
535
|
-
const element = param.locate;
|
|
536
|
-
external_node_assert_default()(element, 'Element not found, cannot double click');
|
|
537
|
-
await this.doubleTap(element.center[0], element.center[1]);
|
|
538
|
-
}),
|
|
539
|
-
(0, device_namespaceObject.defineAction)({
|
|
540
|
-
name: 'Input',
|
|
541
|
-
description: 'Input text into the input field',
|
|
542
|
-
interfaceAlias: 'aiInput',
|
|
543
|
-
paramSchema: iosInputParamSchema,
|
|
544
|
-
sample: {
|
|
545
|
-
value: 'test@example.com',
|
|
546
|
-
locate: {
|
|
547
|
-
prompt: 'the email input field'
|
|
548
|
-
}
|
|
549
|
-
},
|
|
550
|
-
call: async (param)=>{
|
|
551
|
-
const element = param.locate;
|
|
552
|
-
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
553
|
-
if ('clear' === param.mode) return;
|
|
554
|
-
if (!param || !param.value) return;
|
|
555
|
-
const autoDismissKeyboard = param.autoDismissKeyboard ?? this.options?.autoDismissKeyboard;
|
|
556
|
-
await this.typeText(param.value, {
|
|
557
|
-
autoDismissKeyboard
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
}),
|
|
561
|
-
(0, device_namespaceObject.defineActionScroll)(async (param)=>{
|
|
562
|
-
const element = param.locate;
|
|
563
|
-
const startingPoint = element ? {
|
|
564
|
-
left: element.center[0],
|
|
565
|
-
top: element.center[1]
|
|
566
|
-
} : void 0;
|
|
567
|
-
const scrollToEventName = param?.scrollType;
|
|
568
|
-
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
569
|
-
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
570
|
-
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
571
|
-
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
572
|
-
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
573
|
-
else {
|
|
574
|
-
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
575
|
-
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
576
|
-
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
577
|
-
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
578
|
-
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
579
|
-
await (0, utils_namespaceObject.sleep)(500);
|
|
580
|
-
}
|
|
581
|
-
}),
|
|
582
|
-
(0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
|
|
583
|
-
const from = param.from;
|
|
584
|
-
const to = param.to;
|
|
585
|
-
external_node_assert_default()(from, 'missing "from" param for drag and drop');
|
|
586
|
-
external_node_assert_default()(to, 'missing "to" param for drag and drop');
|
|
587
|
-
await this.swipe(from.center[0], from.center[1], to.center[0], to.center[1], 1000);
|
|
588
|
-
}),
|
|
589
|
-
(0, device_namespaceObject.defineActionSwipe)(async (param)=>{
|
|
590
|
-
const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
|
|
591
|
-
for(let i = 0; i < repeatCount; i++)await this.swipe(startPoint.x, startPoint.y, endPoint.x, endPoint.y, duration);
|
|
592
|
-
}),
|
|
593
|
-
(0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
|
|
594
|
-
await this.pressKey(param.keyName);
|
|
595
|
-
}),
|
|
596
|
-
(0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
|
|
597
|
-
const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
|
|
598
|
-
const times = param.times ?? 1;
|
|
599
|
-
for(let i = 0; i < times; i++){
|
|
600
|
-
await this.pressKey(arrowKey);
|
|
601
|
-
await (0, utils_namespaceObject.sleep)(100);
|
|
602
|
-
}
|
|
603
|
-
}),
|
|
604
|
-
(0, device_namespaceObject.defineActionLongPress)(async (param)=>{
|
|
605
|
-
const element = param.locate;
|
|
606
|
-
external_node_assert_default()(element, 'LongPress requires an element to be located');
|
|
607
|
-
const [x, y] = element.center;
|
|
608
|
-
await this.longPress(x, y, param?.duration);
|
|
609
|
-
}),
|
|
610
|
-
(0, device_namespaceObject.defineActionPinch)(async (param)=>{
|
|
611
|
-
const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
|
|
612
|
-
await this.wdaBackend.pinch(centerX, centerY, startDistance, endDistance, duration);
|
|
613
|
-
}),
|
|
614
|
-
(0, device_namespaceObject.defineActionClearInput)(async (param)=>{
|
|
615
|
-
await this.clearInput(param.locate);
|
|
616
|
-
})
|
|
549
|
+
...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext)
|
|
617
550
|
];
|
|
618
551
|
const platformSpecificActions = Object.values(createPlatformActions(this));
|
|
619
552
|
const customActions = this.customActions || [];
|
|
@@ -623,6 +556,27 @@ class IOSDevice {
|
|
|
623
556
|
...customActions
|
|
624
557
|
];
|
|
625
558
|
}
|
|
559
|
+
async performActionScroll(param) {
|
|
560
|
+
const element = param.locate;
|
|
561
|
+
const startingPoint = element ? {
|
|
562
|
+
left: element.center[0],
|
|
563
|
+
top: element.center[1]
|
|
564
|
+
} : void 0;
|
|
565
|
+
const scrollToEventName = param?.scrollType;
|
|
566
|
+
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
567
|
+
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
568
|
+
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
569
|
+
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
570
|
+
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
571
|
+
else {
|
|
572
|
+
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
573
|
+
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
574
|
+
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
575
|
+
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
576
|
+
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
577
|
+
await (0, utils_namespaceObject.sleep)(500);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
626
580
|
describe() {
|
|
627
581
|
return this.description || `Device ID: ${this.deviceId}`;
|
|
628
582
|
}
|
|
@@ -734,35 +688,31 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
734
688
|
}
|
|
735
689
|
}
|
|
736
690
|
async clearInput(element) {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
}
|
|
741
|
-
debugDevice('Attempting to clear input with WebDriver Clear API');
|
|
742
|
-
const cleared = await this.wdaBackend.clearActiveElement();
|
|
743
|
-
cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
|
|
691
|
+
await this.clearInputAt(element ? {
|
|
692
|
+
x: element.center[0],
|
|
693
|
+
y: element.center[1]
|
|
694
|
+
} : void 0);
|
|
744
695
|
}
|
|
745
696
|
async url() {
|
|
746
697
|
return '';
|
|
747
698
|
}
|
|
748
699
|
async tap(x, y) {
|
|
749
|
-
await this.
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
await this.tap(x, y);
|
|
754
|
-
}
|
|
755
|
-
async doubleTap(x, y) {
|
|
756
|
-
await this.wdaBackend.doubleTap(Math.round(x), Math.round(y));
|
|
757
|
-
}
|
|
758
|
-
async tripleTap(x, y) {
|
|
759
|
-
await this.wdaBackend.tripleTap(Math.round(x), Math.round(y));
|
|
760
|
-
}
|
|
761
|
-
async longPress(x, y, duration = 1000) {
|
|
762
|
-
await this.wdaBackend.longPress(Math.round(x), Math.round(y), duration);
|
|
700
|
+
await this.tapPoint({
|
|
701
|
+
x,
|
|
702
|
+
y
|
|
703
|
+
});
|
|
763
704
|
}
|
|
764
705
|
async swipe(fromX, fromY, toX, toY, duration = 500) {
|
|
765
|
-
await this.
|
|
706
|
+
await this.swipeCoordinates(fromX, fromY, toX, toY, duration);
|
|
707
|
+
}
|
|
708
|
+
async swipeCoordinates(fromX, fromY, toX, toY, duration = 500) {
|
|
709
|
+
await this.swipePoint({
|
|
710
|
+
x: fromX,
|
|
711
|
+
y: fromY
|
|
712
|
+
}, {
|
|
713
|
+
x: toX,
|
|
714
|
+
y: toY
|
|
715
|
+
}, duration);
|
|
766
716
|
}
|
|
767
717
|
async typeText(text, options) {
|
|
768
718
|
if (!text) return;
|
|
@@ -791,7 +741,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
791
741
|
y: Math.round(height / 2)
|
|
792
742
|
};
|
|
793
743
|
const scrollDistance = Math.round(distance || height / 3);
|
|
794
|
-
await this.
|
|
744
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance);
|
|
795
745
|
}
|
|
796
746
|
async scrollDown(distance, startPoint) {
|
|
797
747
|
const { width, height } = await this.size();
|
|
@@ -803,7 +753,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
803
753
|
y: Math.round(height / 2)
|
|
804
754
|
};
|
|
805
755
|
const scrollDistance = Math.round(distance || height / 3);
|
|
806
|
-
await this.
|
|
756
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance);
|
|
807
757
|
}
|
|
808
758
|
async scrollLeft(distance, startPoint) {
|
|
809
759
|
const { width, height } = await this.size();
|
|
@@ -815,7 +765,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
815
765
|
y: Math.round(height / 2)
|
|
816
766
|
};
|
|
817
767
|
const scrollDistance = Math.round(distance || 0.7 * width);
|
|
818
|
-
await this.
|
|
768
|
+
await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y);
|
|
819
769
|
}
|
|
820
770
|
async scrollRight(distance, startPoint) {
|
|
821
771
|
const { width, height } = await this.size();
|
|
@@ -827,7 +777,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
827
777
|
y: Math.round(height / 2)
|
|
828
778
|
};
|
|
829
779
|
const scrollDistance = Math.round(distance || 0.7 * width);
|
|
830
|
-
await this.
|
|
780
|
+
await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y);
|
|
831
781
|
}
|
|
832
782
|
async scrollUntilTop(startPoint) {
|
|
833
783
|
debugDevice('Using screenshot-based scroll detection for better reliability');
|
|
@@ -923,16 +873,16 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
923
873
|
debugDevice(`Performing scroll: ${direction}, distance: ${scrollDistance}`);
|
|
924
874
|
switch(direction){
|
|
925
875
|
case 'up':
|
|
926
|
-
await this.
|
|
876
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance, 300);
|
|
927
877
|
break;
|
|
928
878
|
case 'down':
|
|
929
|
-
await this.
|
|
879
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance, 300);
|
|
930
880
|
break;
|
|
931
881
|
case 'left':
|
|
932
|
-
await this.
|
|
882
|
+
await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y, 300);
|
|
933
883
|
break;
|
|
934
884
|
case 'right':
|
|
935
|
-
await this.
|
|
885
|
+
await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y, 300);
|
|
936
886
|
break;
|
|
937
887
|
}
|
|
938
888
|
debugDevice('Waiting for scroll and inertia to complete...');
|
|
@@ -989,7 +939,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
989
939
|
const centerX = Math.round(windowSize.width / 2);
|
|
990
940
|
const startY = Math.round(0.9 * windowSize.height);
|
|
991
941
|
const endY = Math.round(0.5 * windowSize.height);
|
|
992
|
-
await this.
|
|
942
|
+
await this.swipeCoordinates(centerX, startY, centerX, endY, 300);
|
|
993
943
|
debugDevice('Dismissed keyboard with swipe up gesture from bottom of screen');
|
|
994
944
|
await (0, utils_namespaceObject.sleep)(500);
|
|
995
945
|
return true;
|
|
@@ -1066,6 +1016,45 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
1066
1016
|
_define_property(this, "interfaceType", 'ios');
|
|
1067
1017
|
_define_property(this, "uri", void 0);
|
|
1068
1018
|
_define_property(this, "options", void 0);
|
|
1019
|
+
_define_property(this, "inputPrimitives", {
|
|
1020
|
+
pointer: {
|
|
1021
|
+
tap: (point)=>this.tapPoint(point),
|
|
1022
|
+
doubleClick: (point)=>this.doubleTapPoint(point),
|
|
1023
|
+
longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
|
|
1024
|
+
dragAndDrop: (from, to)=>this.swipePoint(from, to, 1000)
|
|
1025
|
+
},
|
|
1026
|
+
keyboard: {
|
|
1027
|
+
keyboardPress: (keyName)=>this.pressKey(keyName),
|
|
1028
|
+
typeText: async (value, opts)=>{
|
|
1029
|
+
const target = opts?.target;
|
|
1030
|
+
if (target && opts?.replace !== false) await this.clearInput(target);
|
|
1031
|
+
else if (target) await this.tapPoint({
|
|
1032
|
+
x: target.center[0],
|
|
1033
|
+
y: target.center[1]
|
|
1034
|
+
});
|
|
1035
|
+
if (opts?.focusOnly) return;
|
|
1036
|
+
await this.typeText(value, opts);
|
|
1037
|
+
},
|
|
1038
|
+
clearInput: (target)=>this.clearInput(target),
|
|
1039
|
+
cursorMove: async (direction, times = 1)=>{
|
|
1040
|
+
const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
|
|
1041
|
+
for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
|
|
1042
|
+
}
|
|
1043
|
+
},
|
|
1044
|
+
touch: {
|
|
1045
|
+
swipe: async (start, end, opts)=>{
|
|
1046
|
+
const duration = opts?.duration ?? 300;
|
|
1047
|
+
const repeat = opts?.repeat ?? 1;
|
|
1048
|
+
for(let i = 0; i < repeat; i++)await this.swipePoint(start, end, duration);
|
|
1049
|
+
},
|
|
1050
|
+
pinch: async (center, opts)=>{
|
|
1051
|
+
await this.wdaBackend.pinch(Math.round(center.x), Math.round(center.y), opts.startDistance, opts.endDistance, opts.duration);
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
scroll: {
|
|
1055
|
+
scroll: (param)=>this.performActionScroll(param)
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1069
1058
|
this.deviceId = 'pending-connection';
|
|
1070
1059
|
this.options = options;
|
|
1071
1060
|
this.customActions = options?.customActions;
|