@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/bin.js
CHANGED
|
@@ -675,16 +675,6 @@ function _define_property(obj, key, value) {
|
|
|
675
675
|
return obj;
|
|
676
676
|
}
|
|
677
677
|
const debugDevice = (0, logger_namespaceObject.getDebug)('ios:device');
|
|
678
|
-
const iosInputParamSchema = core_namespaceObject.z.object({
|
|
679
|
-
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.'),
|
|
680
|
-
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.'),
|
|
681
|
-
mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
|
|
682
|
-
'replace',
|
|
683
|
-
'clear',
|
|
684
|
-
'typeOnly'
|
|
685
|
-
]).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.')),
|
|
686
|
-
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
687
|
-
});
|
|
688
678
|
const WDA_HTTP_METHODS = [
|
|
689
679
|
'GET',
|
|
690
680
|
'POST',
|
|
@@ -693,96 +683,39 @@ const WDA_HTTP_METHODS = [
|
|
|
693
683
|
];
|
|
694
684
|
const DEFAULT_WDA_MJPEG_PORT = 9100;
|
|
695
685
|
class IOSDevice {
|
|
686
|
+
async tapPoint(point) {
|
|
687
|
+
debugDevice(`tap at coordinates (${point.x}, ${point.y})`);
|
|
688
|
+
await this.wdaBackend.tap(Math.round(point.x), Math.round(point.y));
|
|
689
|
+
}
|
|
690
|
+
async doubleTapPoint(point) {
|
|
691
|
+
await this.wdaBackend.doubleTap(Math.round(point.x), Math.round(point.y));
|
|
692
|
+
}
|
|
693
|
+
async longPressPoint(point, duration = 1000) {
|
|
694
|
+
await this.wdaBackend.longPress(Math.round(point.x), Math.round(point.y), duration);
|
|
695
|
+
}
|
|
696
|
+
async swipePoint(start, end, duration = 500) {
|
|
697
|
+
await this.wdaBackend.swipe(Math.round(start.x), Math.round(start.y), Math.round(end.x), Math.round(end.y), duration);
|
|
698
|
+
}
|
|
699
|
+
async clearInputAt(point) {
|
|
700
|
+
if (point) {
|
|
701
|
+
await this.tapPoint(point);
|
|
702
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
703
|
+
}
|
|
704
|
+
debugDevice('Attempting to clear input with WebDriver Clear API');
|
|
705
|
+
const cleared = await this.wdaBackend.clearActiveElement();
|
|
706
|
+
cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
|
|
707
|
+
}
|
|
696
708
|
actionSpace() {
|
|
709
|
+
const mobileActionContext = {
|
|
710
|
+
input: this.inputPrimitives,
|
|
711
|
+
size: ()=>this.size(),
|
|
712
|
+
sleep: async (timeMs)=>{
|
|
713
|
+
await (0, core_utils_namespaceObject.sleep)(timeMs);
|
|
714
|
+
},
|
|
715
|
+
getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard
|
|
716
|
+
};
|
|
697
717
|
const defaultActions = [
|
|
698
|
-
(0, device_namespaceObject.
|
|
699
|
-
const element = param.locate;
|
|
700
|
-
external_node_assert_default()(element, 'Element not found, cannot tap');
|
|
701
|
-
await this.mouseClick(element.center[0], element.center[1]);
|
|
702
|
-
}),
|
|
703
|
-
(0, device_namespaceObject.defineActionDoubleClick)(async (param)=>{
|
|
704
|
-
const element = param.locate;
|
|
705
|
-
external_node_assert_default()(element, 'Element not found, cannot double click');
|
|
706
|
-
await this.doubleTap(element.center[0], element.center[1]);
|
|
707
|
-
}),
|
|
708
|
-
(0, device_namespaceObject.defineAction)({
|
|
709
|
-
name: 'Input',
|
|
710
|
-
description: 'Input text into the input field',
|
|
711
|
-
interfaceAlias: 'aiInput',
|
|
712
|
-
paramSchema: iosInputParamSchema,
|
|
713
|
-
sample: {
|
|
714
|
-
value: 'test@example.com',
|
|
715
|
-
locate: {
|
|
716
|
-
prompt: 'the email input field'
|
|
717
|
-
}
|
|
718
|
-
},
|
|
719
|
-
call: async (param)=>{
|
|
720
|
-
const element = param.locate;
|
|
721
|
-
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
722
|
-
if ('clear' === param.mode) return;
|
|
723
|
-
if (!param || !param.value) return;
|
|
724
|
-
const autoDismissKeyboard = param.autoDismissKeyboard ?? this.options?.autoDismissKeyboard;
|
|
725
|
-
await this.typeText(param.value, {
|
|
726
|
-
autoDismissKeyboard
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
}),
|
|
730
|
-
(0, device_namespaceObject.defineActionScroll)(async (param)=>{
|
|
731
|
-
const element = param.locate;
|
|
732
|
-
const startingPoint = element ? {
|
|
733
|
-
left: element.center[0],
|
|
734
|
-
top: element.center[1]
|
|
735
|
-
} : void 0;
|
|
736
|
-
const scrollToEventName = param?.scrollType;
|
|
737
|
-
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
738
|
-
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
739
|
-
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
740
|
-
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
741
|
-
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
742
|
-
else {
|
|
743
|
-
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
744
|
-
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
745
|
-
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
746
|
-
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
747
|
-
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
748
|
-
await (0, core_utils_namespaceObject.sleep)(500);
|
|
749
|
-
}
|
|
750
|
-
}),
|
|
751
|
-
(0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
|
|
752
|
-
const from = param.from;
|
|
753
|
-
const to = param.to;
|
|
754
|
-
external_node_assert_default()(from, 'missing "from" param for drag and drop');
|
|
755
|
-
external_node_assert_default()(to, 'missing "to" param for drag and drop');
|
|
756
|
-
await this.swipe(from.center[0], from.center[1], to.center[0], to.center[1], 1000);
|
|
757
|
-
}),
|
|
758
|
-
(0, device_namespaceObject.defineActionSwipe)(async (param)=>{
|
|
759
|
-
const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
|
|
760
|
-
for(let i = 0; i < repeatCount; i++)await this.swipe(startPoint.x, startPoint.y, endPoint.x, endPoint.y, duration);
|
|
761
|
-
}),
|
|
762
|
-
(0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
|
|
763
|
-
await this.pressKey(param.keyName);
|
|
764
|
-
}),
|
|
765
|
-
(0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
|
|
766
|
-
const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
|
|
767
|
-
const times = param.times ?? 1;
|
|
768
|
-
for(let i = 0; i < times; i++){
|
|
769
|
-
await this.pressKey(arrowKey);
|
|
770
|
-
await (0, core_utils_namespaceObject.sleep)(100);
|
|
771
|
-
}
|
|
772
|
-
}),
|
|
773
|
-
(0, device_namespaceObject.defineActionLongPress)(async (param)=>{
|
|
774
|
-
const element = param.locate;
|
|
775
|
-
external_node_assert_default()(element, 'LongPress requires an element to be located');
|
|
776
|
-
const [x, y] = element.center;
|
|
777
|
-
await this.longPress(x, y, param?.duration);
|
|
778
|
-
}),
|
|
779
|
-
(0, device_namespaceObject.defineActionPinch)(async (param)=>{
|
|
780
|
-
const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
|
|
781
|
-
await this.wdaBackend.pinch(centerX, centerY, startDistance, endDistance, duration);
|
|
782
|
-
}),
|
|
783
|
-
(0, device_namespaceObject.defineActionClearInput)(async (param)=>{
|
|
784
|
-
await this.clearInput(param.locate);
|
|
785
|
-
})
|
|
718
|
+
...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext)
|
|
786
719
|
];
|
|
787
720
|
const platformSpecificActions = Object.values(createPlatformActions(this));
|
|
788
721
|
const customActions = this.customActions || [];
|
|
@@ -792,6 +725,27 @@ class IOSDevice {
|
|
|
792
725
|
...customActions
|
|
793
726
|
];
|
|
794
727
|
}
|
|
728
|
+
async performActionScroll(param) {
|
|
729
|
+
const element = param.locate;
|
|
730
|
+
const startingPoint = element ? {
|
|
731
|
+
left: element.center[0],
|
|
732
|
+
top: element.center[1]
|
|
733
|
+
} : void 0;
|
|
734
|
+
const scrollToEventName = param?.scrollType;
|
|
735
|
+
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
736
|
+
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
737
|
+
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
738
|
+
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
739
|
+
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
740
|
+
else {
|
|
741
|
+
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
742
|
+
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
743
|
+
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
744
|
+
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
745
|
+
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
746
|
+
await (0, core_utils_namespaceObject.sleep)(500);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
795
749
|
describe() {
|
|
796
750
|
return this.description || `Device ID: ${this.deviceId}`;
|
|
797
751
|
}
|
|
@@ -903,35 +857,31 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
903
857
|
}
|
|
904
858
|
}
|
|
905
859
|
async clearInput(element) {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
debugDevice('Attempting to clear input with WebDriver Clear API');
|
|
911
|
-
const cleared = await this.wdaBackend.clearActiveElement();
|
|
912
|
-
cleared ? debugDevice('Successfully cleared input with WebDriver Clear API') : debugDevice('WebDriver Clear API returned false (no active element or clear failed)');
|
|
860
|
+
await this.clearInputAt(element ? {
|
|
861
|
+
x: element.center[0],
|
|
862
|
+
y: element.center[1]
|
|
863
|
+
} : void 0);
|
|
913
864
|
}
|
|
914
865
|
async url() {
|
|
915
866
|
return '';
|
|
916
867
|
}
|
|
917
868
|
async tap(x, y) {
|
|
918
|
-
await this.
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
await this.tap(x, y);
|
|
923
|
-
}
|
|
924
|
-
async doubleTap(x, y) {
|
|
925
|
-
await this.wdaBackend.doubleTap(Math.round(x), Math.round(y));
|
|
926
|
-
}
|
|
927
|
-
async tripleTap(x, y) {
|
|
928
|
-
await this.wdaBackend.tripleTap(Math.round(x), Math.round(y));
|
|
929
|
-
}
|
|
930
|
-
async longPress(x, y, duration = 1000) {
|
|
931
|
-
await this.wdaBackend.longPress(Math.round(x), Math.round(y), duration);
|
|
869
|
+
await this.tapPoint({
|
|
870
|
+
x,
|
|
871
|
+
y
|
|
872
|
+
});
|
|
932
873
|
}
|
|
933
874
|
async swipe(fromX, fromY, toX, toY, duration = 500) {
|
|
934
|
-
await this.
|
|
875
|
+
await this.swipeCoordinates(fromX, fromY, toX, toY, duration);
|
|
876
|
+
}
|
|
877
|
+
async swipeCoordinates(fromX, fromY, toX, toY, duration = 500) {
|
|
878
|
+
await this.swipePoint({
|
|
879
|
+
x: fromX,
|
|
880
|
+
y: fromY
|
|
881
|
+
}, {
|
|
882
|
+
x: toX,
|
|
883
|
+
y: toY
|
|
884
|
+
}, duration);
|
|
935
885
|
}
|
|
936
886
|
async typeText(text, options) {
|
|
937
887
|
if (!text) return;
|
|
@@ -960,7 +910,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
960
910
|
y: Math.round(height / 2)
|
|
961
911
|
};
|
|
962
912
|
const scrollDistance = Math.round(distance || height / 3);
|
|
963
|
-
await this.
|
|
913
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance);
|
|
964
914
|
}
|
|
965
915
|
async scrollDown(distance, startPoint) {
|
|
966
916
|
const { width, height } = await this.size();
|
|
@@ -972,7 +922,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
972
922
|
y: Math.round(height / 2)
|
|
973
923
|
};
|
|
974
924
|
const scrollDistance = Math.round(distance || height / 3);
|
|
975
|
-
await this.
|
|
925
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance);
|
|
976
926
|
}
|
|
977
927
|
async scrollLeft(distance, startPoint) {
|
|
978
928
|
const { width, height } = await this.size();
|
|
@@ -984,7 +934,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
984
934
|
y: Math.round(height / 2)
|
|
985
935
|
};
|
|
986
936
|
const scrollDistance = Math.round(distance || 0.7 * width);
|
|
987
|
-
await this.
|
|
937
|
+
await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y);
|
|
988
938
|
}
|
|
989
939
|
async scrollRight(distance, startPoint) {
|
|
990
940
|
const { width, height } = await this.size();
|
|
@@ -996,7 +946,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
996
946
|
y: Math.round(height / 2)
|
|
997
947
|
};
|
|
998
948
|
const scrollDistance = Math.round(distance || 0.7 * width);
|
|
999
|
-
await this.
|
|
949
|
+
await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y);
|
|
1000
950
|
}
|
|
1001
951
|
async scrollUntilTop(startPoint) {
|
|
1002
952
|
debugDevice('Using screenshot-based scroll detection for better reliability');
|
|
@@ -1092,16 +1042,16 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
1092
1042
|
debugDevice(`Performing scroll: ${direction}, distance: ${scrollDistance}`);
|
|
1093
1043
|
switch(direction){
|
|
1094
1044
|
case 'up':
|
|
1095
|
-
await this.
|
|
1045
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y + scrollDistance, 300);
|
|
1096
1046
|
break;
|
|
1097
1047
|
case 'down':
|
|
1098
|
-
await this.
|
|
1048
|
+
await this.swipeCoordinates(start.x, start.y, start.x, start.y - scrollDistance, 300);
|
|
1099
1049
|
break;
|
|
1100
1050
|
case 'left':
|
|
1101
|
-
await this.
|
|
1051
|
+
await this.swipeCoordinates(start.x, start.y, start.x + scrollDistance, start.y, 300);
|
|
1102
1052
|
break;
|
|
1103
1053
|
case 'right':
|
|
1104
|
-
await this.
|
|
1054
|
+
await this.swipeCoordinates(start.x, start.y, start.x - scrollDistance, start.y, 300);
|
|
1105
1055
|
break;
|
|
1106
1056
|
}
|
|
1107
1057
|
debugDevice('Waiting for scroll and inertia to complete...');
|
|
@@ -1158,7 +1108,7 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
1158
1108
|
const centerX = Math.round(windowSize.width / 2);
|
|
1159
1109
|
const startY = Math.round(0.9 * windowSize.height);
|
|
1160
1110
|
const endY = Math.round(0.5 * windowSize.height);
|
|
1161
|
-
await this.
|
|
1111
|
+
await this.swipeCoordinates(centerX, startY, centerX, endY, 300);
|
|
1162
1112
|
debugDevice('Dismissed keyboard with swipe up gesture from bottom of screen');
|
|
1163
1113
|
await (0, core_utils_namespaceObject.sleep)(500);
|
|
1164
1114
|
return true;
|
|
@@ -1235,6 +1185,45 @@ ScreenSize: ${size.width}x${size.height} (DPR: ${size.scale})
|
|
|
1235
1185
|
_define_property(this, "interfaceType", 'ios');
|
|
1236
1186
|
_define_property(this, "uri", void 0);
|
|
1237
1187
|
_define_property(this, "options", void 0);
|
|
1188
|
+
_define_property(this, "inputPrimitives", {
|
|
1189
|
+
pointer: {
|
|
1190
|
+
tap: (point)=>this.tapPoint(point),
|
|
1191
|
+
doubleClick: (point)=>this.doubleTapPoint(point),
|
|
1192
|
+
longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
|
|
1193
|
+
dragAndDrop: (from, to)=>this.swipePoint(from, to, 1000)
|
|
1194
|
+
},
|
|
1195
|
+
keyboard: {
|
|
1196
|
+
keyboardPress: (keyName)=>this.pressKey(keyName),
|
|
1197
|
+
typeText: async (value, opts)=>{
|
|
1198
|
+
const target = opts?.target;
|
|
1199
|
+
if (target && opts?.replace !== false) await this.clearInput(target);
|
|
1200
|
+
else if (target) await this.tapPoint({
|
|
1201
|
+
x: target.center[0],
|
|
1202
|
+
y: target.center[1]
|
|
1203
|
+
});
|
|
1204
|
+
if (opts?.focusOnly) return;
|
|
1205
|
+
await this.typeText(value, opts);
|
|
1206
|
+
},
|
|
1207
|
+
clearInput: (target)=>this.clearInput(target),
|
|
1208
|
+
cursorMove: async (direction, times = 1)=>{
|
|
1209
|
+
const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
|
|
1210
|
+
for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
|
|
1211
|
+
}
|
|
1212
|
+
},
|
|
1213
|
+
touch: {
|
|
1214
|
+
swipe: async (start, end, opts)=>{
|
|
1215
|
+
const duration = opts?.duration ?? 300;
|
|
1216
|
+
const repeat = opts?.repeat ?? 1;
|
|
1217
|
+
for(let i = 0; i < repeat; i++)await this.swipePoint(start, end, duration);
|
|
1218
|
+
},
|
|
1219
|
+
pinch: async (center, opts)=>{
|
|
1220
|
+
await this.wdaBackend.pinch(Math.round(center.x), Math.round(center.y), opts.startDistance, opts.endDistance, opts.duration);
|
|
1221
|
+
}
|
|
1222
|
+
},
|
|
1223
|
+
scroll: {
|
|
1224
|
+
scroll: (param)=>this.performActionScroll(param)
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1238
1227
|
this.deviceId = 'pending-connection';
|
|
1239
1228
|
this.options = options;
|
|
1240
1229
|
this.customActions = options?.customActions;
|