@midscene/android 1.5.4-beta-20260310030546.0 → 1.5.4
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/cli.mjs +28 -1
- package/dist/es/index.mjs +26 -0
- package/dist/es/mcp-server.mjs +27 -1
- package/dist/lib/cli.js +28 -1
- package/dist/lib/index.js +26 -0
- package/dist/lib/mcp-server.js +27 -1
- package/package.json +4 -4
package/dist/es/cli.mjs
CHANGED
|
@@ -706,6 +706,12 @@ class AndroidDevice {
|
|
|
706
706
|
]).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.')),
|
|
707
707
|
locate: getMidsceneLocationSchema().describe('The input field to be filled').optional()
|
|
708
708
|
}),
|
|
709
|
+
sample: {
|
|
710
|
+
value: 'test@example.com',
|
|
711
|
+
locate: {
|
|
712
|
+
prompt: 'the email input field'
|
|
713
|
+
}
|
|
714
|
+
},
|
|
709
715
|
call: async (param)=>{
|
|
710
716
|
const element = param.locate;
|
|
711
717
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -773,6 +779,11 @@ class AndroidDevice {
|
|
|
773
779
|
duration: z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
774
780
|
locate: getMidsceneLocationSchema().describe('The element to be long pressed')
|
|
775
781
|
}),
|
|
782
|
+
sample: {
|
|
783
|
+
locate: {
|
|
784
|
+
prompt: 'the message bubble'
|
|
785
|
+
}
|
|
786
|
+
},
|
|
776
787
|
call: async (param)=>{
|
|
777
788
|
const element = param.locate;
|
|
778
789
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -792,6 +803,12 @@ class AndroidDevice {
|
|
|
792
803
|
duration: z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
793
804
|
locate: getMidsceneLocationSchema().optional().describe('The element to start the pull from (optional)')
|
|
794
805
|
}),
|
|
806
|
+
sample: {
|
|
807
|
+
direction: 'down',
|
|
808
|
+
locate: {
|
|
809
|
+
prompt: 'the center of the content list area'
|
|
810
|
+
}
|
|
811
|
+
},
|
|
795
812
|
call: async (param)=>{
|
|
796
813
|
const element = param.locate;
|
|
797
814
|
const startPoint = element ? {
|
|
@@ -961,6 +978,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
961
978
|
}
|
|
962
979
|
async getScreenSize() {
|
|
963
980
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
981
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
964
982
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
965
983
|
const adb = await this.getAdb();
|
|
966
984
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -1094,6 +1112,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1094
1112
|
}
|
|
1095
1113
|
async getDisplayOrientation() {
|
|
1096
1114
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1115
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1097
1116
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1098
1117
|
const adb = await this.getAdb();
|
|
1099
1118
|
let orientation = 0;
|
|
@@ -1138,6 +1157,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1138
1157
|
}
|
|
1139
1158
|
async getAdjustScale() {
|
|
1140
1159
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1160
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1141
1161
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1142
1162
|
const physical = await this.getOrientedPhysicalSize();
|
|
1143
1163
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1723,6 +1743,9 @@ const createPlatformActions = (device)=>({
|
|
|
1723
1743
|
description: 'Execute ADB shell command on Android device',
|
|
1724
1744
|
interfaceAlias: 'runAdbShell',
|
|
1725
1745
|
paramSchema: runAdbShellParamSchema,
|
|
1746
|
+
sample: {
|
|
1747
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1748
|
+
},
|
|
1726
1749
|
call: async (param)=>{
|
|
1727
1750
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1728
1751
|
const adb = await device.getAdb();
|
|
@@ -1734,6 +1757,9 @@ const createPlatformActions = (device)=>({
|
|
|
1734
1757
|
description: 'Launch an Android app or URL',
|
|
1735
1758
|
interfaceAlias: 'launch',
|
|
1736
1759
|
paramSchema: launchParamSchema,
|
|
1760
|
+
sample: {
|
|
1761
|
+
uri: 'com.example.app'
|
|
1762
|
+
},
|
|
1737
1763
|
call: async (param)=>{
|
|
1738
1764
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1739
1765
|
await device.launch(param.uri);
|
|
@@ -1881,7 +1907,8 @@ class AndroidMidsceneTools extends BaseMidsceneTools {
|
|
|
1881
1907
|
}
|
|
1882
1908
|
const tools = new AndroidMidsceneTools();
|
|
1883
1909
|
runToolsCLI(tools, 'midscene-android', {
|
|
1884
|
-
stripPrefix: 'android_'
|
|
1910
|
+
stripPrefix: 'android_',
|
|
1911
|
+
version: "1.5.4"
|
|
1885
1912
|
}).catch((e)=>{
|
|
1886
1913
|
if (!(e instanceof CLIError)) console.error(e);
|
|
1887
1914
|
process.exit(e instanceof CLIError ? e.exitCode : 1);
|
package/dist/es/index.mjs
CHANGED
|
@@ -609,6 +609,12 @@ class AndroidDevice {
|
|
|
609
609
|
]).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.')),
|
|
610
610
|
locate: getMidsceneLocationSchema().describe('The input field to be filled').optional()
|
|
611
611
|
}),
|
|
612
|
+
sample: {
|
|
613
|
+
value: 'test@example.com',
|
|
614
|
+
locate: {
|
|
615
|
+
prompt: 'the email input field'
|
|
616
|
+
}
|
|
617
|
+
},
|
|
612
618
|
call: async (param)=>{
|
|
613
619
|
const element = param.locate;
|
|
614
620
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -676,6 +682,11 @@ class AndroidDevice {
|
|
|
676
682
|
duration: z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
677
683
|
locate: getMidsceneLocationSchema().describe('The element to be long pressed')
|
|
678
684
|
}),
|
|
685
|
+
sample: {
|
|
686
|
+
locate: {
|
|
687
|
+
prompt: 'the message bubble'
|
|
688
|
+
}
|
|
689
|
+
},
|
|
679
690
|
call: async (param)=>{
|
|
680
691
|
const element = param.locate;
|
|
681
692
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -695,6 +706,12 @@ class AndroidDevice {
|
|
|
695
706
|
duration: z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
696
707
|
locate: getMidsceneLocationSchema().optional().describe('The element to start the pull from (optional)')
|
|
697
708
|
}),
|
|
709
|
+
sample: {
|
|
710
|
+
direction: 'down',
|
|
711
|
+
locate: {
|
|
712
|
+
prompt: 'the center of the content list area'
|
|
713
|
+
}
|
|
714
|
+
},
|
|
698
715
|
call: async (param)=>{
|
|
699
716
|
const element = param.locate;
|
|
700
717
|
const startPoint = element ? {
|
|
@@ -864,6 +881,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
864
881
|
}
|
|
865
882
|
async getScreenSize() {
|
|
866
883
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
884
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
867
885
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
868
886
|
const adb = await this.getAdb();
|
|
869
887
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -997,6 +1015,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
997
1015
|
}
|
|
998
1016
|
async getDisplayOrientation() {
|
|
999
1017
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1018
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1000
1019
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1001
1020
|
const adb = await this.getAdb();
|
|
1002
1021
|
let orientation = 0;
|
|
@@ -1041,6 +1060,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1041
1060
|
}
|
|
1042
1061
|
async getAdjustScale() {
|
|
1043
1062
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1063
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1044
1064
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1045
1065
|
const physical = await this.getOrientedPhysicalSize();
|
|
1046
1066
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1626,6 +1646,9 @@ const createPlatformActions = (device)=>({
|
|
|
1626
1646
|
description: 'Execute ADB shell command on Android device',
|
|
1627
1647
|
interfaceAlias: 'runAdbShell',
|
|
1628
1648
|
paramSchema: runAdbShellParamSchema,
|
|
1649
|
+
sample: {
|
|
1650
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1651
|
+
},
|
|
1629
1652
|
call: async (param)=>{
|
|
1630
1653
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1631
1654
|
const adb = await device.getAdb();
|
|
@@ -1637,6 +1660,9 @@ const createPlatformActions = (device)=>({
|
|
|
1637
1660
|
description: 'Launch an Android app or URL',
|
|
1638
1661
|
interfaceAlias: 'launch',
|
|
1639
1662
|
paramSchema: launchParamSchema,
|
|
1663
|
+
sample: {
|
|
1664
|
+
uri: 'com.example.app'
|
|
1665
|
+
},
|
|
1640
1666
|
call: async (param)=>{
|
|
1641
1667
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1642
1668
|
await device.launch(param.uri);
|
package/dist/es/mcp-server.mjs
CHANGED
|
@@ -705,6 +705,12 @@ class AndroidDevice {
|
|
|
705
705
|
]).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.')),
|
|
706
706
|
locate: getMidsceneLocationSchema().describe('The input field to be filled').optional()
|
|
707
707
|
}),
|
|
708
|
+
sample: {
|
|
709
|
+
value: 'test@example.com',
|
|
710
|
+
locate: {
|
|
711
|
+
prompt: 'the email input field'
|
|
712
|
+
}
|
|
713
|
+
},
|
|
708
714
|
call: async (param)=>{
|
|
709
715
|
const element = param.locate;
|
|
710
716
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -772,6 +778,11 @@ class AndroidDevice {
|
|
|
772
778
|
duration: z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
773
779
|
locate: getMidsceneLocationSchema().describe('The element to be long pressed')
|
|
774
780
|
}),
|
|
781
|
+
sample: {
|
|
782
|
+
locate: {
|
|
783
|
+
prompt: 'the message bubble'
|
|
784
|
+
}
|
|
785
|
+
},
|
|
775
786
|
call: async (param)=>{
|
|
776
787
|
const element = param.locate;
|
|
777
788
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -791,6 +802,12 @@ class AndroidDevice {
|
|
|
791
802
|
duration: z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
792
803
|
locate: getMidsceneLocationSchema().optional().describe('The element to start the pull from (optional)')
|
|
793
804
|
}),
|
|
805
|
+
sample: {
|
|
806
|
+
direction: 'down',
|
|
807
|
+
locate: {
|
|
808
|
+
prompt: 'the center of the content list area'
|
|
809
|
+
}
|
|
810
|
+
},
|
|
794
811
|
call: async (param)=>{
|
|
795
812
|
const element = param.locate;
|
|
796
813
|
const startPoint = element ? {
|
|
@@ -960,6 +977,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
960
977
|
}
|
|
961
978
|
async getScreenSize() {
|
|
962
979
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
980
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
963
981
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
964
982
|
const adb = await this.getAdb();
|
|
965
983
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -1093,6 +1111,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1093
1111
|
}
|
|
1094
1112
|
async getDisplayOrientation() {
|
|
1095
1113
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1114
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1096
1115
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1097
1116
|
const adb = await this.getAdb();
|
|
1098
1117
|
let orientation = 0;
|
|
@@ -1137,6 +1156,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1137
1156
|
}
|
|
1138
1157
|
async getAdjustScale() {
|
|
1139
1158
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1159
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1140
1160
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1141
1161
|
const physical = await this.getOrientedPhysicalSize();
|
|
1142
1162
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1722,6 +1742,9 @@ const createPlatformActions = (device)=>({
|
|
|
1722
1742
|
description: 'Execute ADB shell command on Android device',
|
|
1723
1743
|
interfaceAlias: 'runAdbShell',
|
|
1724
1744
|
paramSchema: runAdbShellParamSchema,
|
|
1745
|
+
sample: {
|
|
1746
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1747
|
+
},
|
|
1725
1748
|
call: async (param)=>{
|
|
1726
1749
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1727
1750
|
const adb = await device.getAdb();
|
|
@@ -1733,6 +1756,9 @@ const createPlatformActions = (device)=>({
|
|
|
1733
1756
|
description: 'Launch an Android app or URL',
|
|
1734
1757
|
interfaceAlias: 'launch',
|
|
1735
1758
|
paramSchema: launchParamSchema,
|
|
1759
|
+
sample: {
|
|
1760
|
+
uri: 'com.example.app'
|
|
1761
|
+
},
|
|
1736
1762
|
call: async (param)=>{
|
|
1737
1763
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1738
1764
|
await device.launch(param.uri);
|
|
@@ -1885,7 +1911,7 @@ class AndroidMCPServer extends BaseMCPServer {
|
|
|
1885
1911
|
constructor(toolsManager){
|
|
1886
1912
|
super({
|
|
1887
1913
|
name: '@midscene/android-mcp',
|
|
1888
|
-
version:
|
|
1914
|
+
version: "1.5.4",
|
|
1889
1915
|
description: 'Control the Android device using natural language commands'
|
|
1890
1916
|
}, toolsManager);
|
|
1891
1917
|
}
|
package/dist/lib/cli.js
CHANGED
|
@@ -721,6 +721,12 @@ var __webpack_exports__ = {};
|
|
|
721
721
|
]).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.')),
|
|
722
722
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
723
723
|
}),
|
|
724
|
+
sample: {
|
|
725
|
+
value: 'test@example.com',
|
|
726
|
+
locate: {
|
|
727
|
+
prompt: 'the email input field'
|
|
728
|
+
}
|
|
729
|
+
},
|
|
724
730
|
call: async (param)=>{
|
|
725
731
|
const element = param.locate;
|
|
726
732
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -788,6 +794,11 @@ var __webpack_exports__ = {};
|
|
|
788
794
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
789
795
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The element to be long pressed')
|
|
790
796
|
}),
|
|
797
|
+
sample: {
|
|
798
|
+
locate: {
|
|
799
|
+
prompt: 'the message bubble'
|
|
800
|
+
}
|
|
801
|
+
},
|
|
791
802
|
call: async (param)=>{
|
|
792
803
|
const element = param.locate;
|
|
793
804
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -807,6 +818,12 @@ var __webpack_exports__ = {};
|
|
|
807
818
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
808
819
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().optional().describe('The element to start the pull from (optional)')
|
|
809
820
|
}),
|
|
821
|
+
sample: {
|
|
822
|
+
direction: 'down',
|
|
823
|
+
locate: {
|
|
824
|
+
prompt: 'the center of the content list area'
|
|
825
|
+
}
|
|
826
|
+
},
|
|
810
827
|
call: async (param)=>{
|
|
811
828
|
const element = param.locate;
|
|
812
829
|
const startPoint = element ? {
|
|
@@ -976,6 +993,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
976
993
|
}
|
|
977
994
|
async getScreenSize() {
|
|
978
995
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
996
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
979
997
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
980
998
|
const adb = await this.getAdb();
|
|
981
999
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -1109,6 +1127,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1109
1127
|
}
|
|
1110
1128
|
async getDisplayOrientation() {
|
|
1111
1129
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1130
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1112
1131
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1113
1132
|
const adb = await this.getAdb();
|
|
1114
1133
|
let orientation = 0;
|
|
@@ -1153,6 +1172,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1153
1172
|
}
|
|
1154
1173
|
async getAdjustScale() {
|
|
1155
1174
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1175
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1156
1176
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1157
1177
|
const physical = await this.getOrientedPhysicalSize();
|
|
1158
1178
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1738,6 +1758,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1738
1758
|
description: 'Execute ADB shell command on Android device',
|
|
1739
1759
|
interfaceAlias: 'runAdbShell',
|
|
1740
1760
|
paramSchema: runAdbShellParamSchema,
|
|
1761
|
+
sample: {
|
|
1762
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1763
|
+
},
|
|
1741
1764
|
call: async (param)=>{
|
|
1742
1765
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1743
1766
|
const adb = await device.getAdb();
|
|
@@ -1749,6 +1772,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1749
1772
|
description: 'Launch an Android app or URL',
|
|
1750
1773
|
interfaceAlias: 'launch',
|
|
1751
1774
|
paramSchema: launchParamSchema,
|
|
1775
|
+
sample: {
|
|
1776
|
+
uri: 'com.example.app'
|
|
1777
|
+
},
|
|
1752
1778
|
call: async (param)=>{
|
|
1753
1779
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1754
1780
|
await device.launch(param.uri);
|
|
@@ -1896,7 +1922,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1896
1922
|
}
|
|
1897
1923
|
const tools = new AndroidMidsceneTools();
|
|
1898
1924
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-android', {
|
|
1899
|
-
stripPrefix: 'android_'
|
|
1925
|
+
stripPrefix: 'android_',
|
|
1926
|
+
version: "1.5.4"
|
|
1900
1927
|
}).catch((e)=>{
|
|
1901
1928
|
if (!(e instanceof cli_namespaceObject.CLIError)) console.error(e);
|
|
1902
1929
|
process.exit(e instanceof cli_namespaceObject.CLIError ? e.exitCode : 1);
|
package/dist/lib/index.js
CHANGED
|
@@ -642,6 +642,12 @@ var __webpack_exports__ = {};
|
|
|
642
642
|
]).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.')),
|
|
643
643
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
644
644
|
}),
|
|
645
|
+
sample: {
|
|
646
|
+
value: 'test@example.com',
|
|
647
|
+
locate: {
|
|
648
|
+
prompt: 'the email input field'
|
|
649
|
+
}
|
|
650
|
+
},
|
|
645
651
|
call: async (param)=>{
|
|
646
652
|
const element = param.locate;
|
|
647
653
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -709,6 +715,11 @@ var __webpack_exports__ = {};
|
|
|
709
715
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
710
716
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The element to be long pressed')
|
|
711
717
|
}),
|
|
718
|
+
sample: {
|
|
719
|
+
locate: {
|
|
720
|
+
prompt: 'the message bubble'
|
|
721
|
+
}
|
|
722
|
+
},
|
|
712
723
|
call: async (param)=>{
|
|
713
724
|
const element = param.locate;
|
|
714
725
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -728,6 +739,12 @@ var __webpack_exports__ = {};
|
|
|
728
739
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
729
740
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().optional().describe('The element to start the pull from (optional)')
|
|
730
741
|
}),
|
|
742
|
+
sample: {
|
|
743
|
+
direction: 'down',
|
|
744
|
+
locate: {
|
|
745
|
+
prompt: 'the center of the content list area'
|
|
746
|
+
}
|
|
747
|
+
},
|
|
731
748
|
call: async (param)=>{
|
|
732
749
|
const element = param.locate;
|
|
733
750
|
const startPoint = element ? {
|
|
@@ -897,6 +914,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
897
914
|
}
|
|
898
915
|
async getScreenSize() {
|
|
899
916
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
917
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
900
918
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
901
919
|
const adb = await this.getAdb();
|
|
902
920
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -1030,6 +1048,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1030
1048
|
}
|
|
1031
1049
|
async getDisplayOrientation() {
|
|
1032
1050
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1051
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1033
1052
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1034
1053
|
const adb = await this.getAdb();
|
|
1035
1054
|
let orientation = 0;
|
|
@@ -1074,6 +1093,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1074
1093
|
}
|
|
1075
1094
|
async getAdjustScale() {
|
|
1076
1095
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1096
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1077
1097
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1078
1098
|
const physical = await this.getOrientedPhysicalSize();
|
|
1079
1099
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1659,6 +1679,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1659
1679
|
description: 'Execute ADB shell command on Android device',
|
|
1660
1680
|
interfaceAlias: 'runAdbShell',
|
|
1661
1681
|
paramSchema: runAdbShellParamSchema,
|
|
1682
|
+
sample: {
|
|
1683
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1684
|
+
},
|
|
1662
1685
|
call: async (param)=>{
|
|
1663
1686
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1664
1687
|
const adb = await device.getAdb();
|
|
@@ -1670,6 +1693,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1670
1693
|
description: 'Launch an Android app or URL',
|
|
1671
1694
|
interfaceAlias: 'launch',
|
|
1672
1695
|
paramSchema: launchParamSchema,
|
|
1696
|
+
sample: {
|
|
1697
|
+
uri: 'com.example.app'
|
|
1698
|
+
},
|
|
1673
1699
|
call: async (param)=>{
|
|
1674
1700
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1675
1701
|
await device.launch(param.uri);
|
package/dist/lib/mcp-server.js
CHANGED
|
@@ -736,6 +736,12 @@ var __webpack_exports__ = {};
|
|
|
736
736
|
]).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.')),
|
|
737
737
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
738
738
|
}),
|
|
739
|
+
sample: {
|
|
740
|
+
value: 'test@example.com',
|
|
741
|
+
locate: {
|
|
742
|
+
prompt: 'the email input field'
|
|
743
|
+
}
|
|
744
|
+
},
|
|
739
745
|
call: async (param)=>{
|
|
740
746
|
const element = param.locate;
|
|
741
747
|
if ('typeOnly' !== param.mode) await this.clearInput(element);
|
|
@@ -803,6 +809,11 @@ var __webpack_exports__ = {};
|
|
|
803
809
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the long press in milliseconds'),
|
|
804
810
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The element to be long pressed')
|
|
805
811
|
}),
|
|
812
|
+
sample: {
|
|
813
|
+
locate: {
|
|
814
|
+
prompt: 'the message bubble'
|
|
815
|
+
}
|
|
816
|
+
},
|
|
806
817
|
call: async (param)=>{
|
|
807
818
|
const element = param.locate;
|
|
808
819
|
if (!element) throw new Error('LongPress requires an element to be located');
|
|
@@ -822,6 +833,12 @@ var __webpack_exports__ = {};
|
|
|
822
833
|
duration: core_namespaceObject.z.number().optional().describe('The duration of the pull (in milliseconds)'),
|
|
823
834
|
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().optional().describe('The element to start the pull from (optional)')
|
|
824
835
|
}),
|
|
836
|
+
sample: {
|
|
837
|
+
direction: 'down',
|
|
838
|
+
locate: {
|
|
839
|
+
prompt: 'the center of the content list area'
|
|
840
|
+
}
|
|
841
|
+
},
|
|
825
842
|
call: async (param)=>{
|
|
826
843
|
const element = param.locate;
|
|
827
844
|
const startPoint = element ? {
|
|
@@ -991,6 +1008,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
991
1008
|
}
|
|
992
1009
|
async getScreenSize() {
|
|
993
1010
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1011
|
+
debugDevice(`getScreenSize: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedSize=${!!this.cachedScreenSize}`);
|
|
994
1012
|
if (shouldCache && this.cachedScreenSize) return this.cachedScreenSize;
|
|
995
1013
|
const adb = await this.getAdb();
|
|
996
1014
|
if ('number' == typeof this.options?.displayId) try {
|
|
@@ -1124,6 +1142,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1124
1142
|
}
|
|
1125
1143
|
async getDisplayOrientation() {
|
|
1126
1144
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1145
|
+
debugDevice(`getDisplayOrientation: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedOrientation=${null !== this.cachedOrientation}`);
|
|
1127
1146
|
if (shouldCache && null !== this.cachedOrientation) return this.cachedOrientation;
|
|
1128
1147
|
const adb = await this.getAdb();
|
|
1129
1148
|
let orientation = 0;
|
|
@@ -1168,6 +1187,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1168
1187
|
}
|
|
1169
1188
|
async getAdjustScale() {
|
|
1170
1189
|
const shouldCache = !(this.options?.alwaysRefreshScreenInfo ?? false);
|
|
1190
|
+
debugDevice(`getAdjustScale: alwaysRefreshScreenInfo=${this.options?.alwaysRefreshScreenInfo}, shouldCache=${shouldCache}, hasCachedScale=${!!this.cachedAdjustScale}`);
|
|
1171
1191
|
if (shouldCache && this.cachedAdjustScale) return this.cachedAdjustScale;
|
|
1172
1192
|
const physical = await this.getOrientedPhysicalSize();
|
|
1173
1193
|
const { width: logicalW, height: logicalH } = await this.size();
|
|
@@ -1753,6 +1773,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1753
1773
|
description: 'Execute ADB shell command on Android device',
|
|
1754
1774
|
interfaceAlias: 'runAdbShell',
|
|
1755
1775
|
paramSchema: runAdbShellParamSchema,
|
|
1776
|
+
sample: {
|
|
1777
|
+
command: 'dumpsys window displays | grep -E "mCurrentFocus"'
|
|
1778
|
+
},
|
|
1756
1779
|
call: async (param)=>{
|
|
1757
1780
|
if (!param.command || '' === param.command.trim()) throw new Error('RunAdbShell requires a non-empty command parameter');
|
|
1758
1781
|
const adb = await device.getAdb();
|
|
@@ -1764,6 +1787,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1764
1787
|
description: 'Launch an Android app or URL',
|
|
1765
1788
|
interfaceAlias: 'launch',
|
|
1766
1789
|
paramSchema: launchParamSchema,
|
|
1790
|
+
sample: {
|
|
1791
|
+
uri: 'com.example.app'
|
|
1792
|
+
},
|
|
1767
1793
|
call: async (param)=>{
|
|
1768
1794
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Launch requires a non-empty uri parameter');
|
|
1769
1795
|
await device.launch(param.uri);
|
|
@@ -1916,7 +1942,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1916
1942
|
constructor(toolsManager){
|
|
1917
1943
|
super({
|
|
1918
1944
|
name: '@midscene/android-mcp',
|
|
1919
|
-
version:
|
|
1945
|
+
version: "1.5.4",
|
|
1920
1946
|
description: 'Control the Android device using natural language commands'
|
|
1921
1947
|
}, toolsManager);
|
|
1922
1948
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/android",
|
|
3
|
-
"version": "1.5.4
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Android automation library for Midscene",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Android UI automation",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@yume-chan/stream-extra": "^1.0.0",
|
|
42
42
|
"appium-adb": "12.12.1",
|
|
43
43
|
"sharp": "^0.34.3",
|
|
44
|
-
"@midscene/core": "1.5.4
|
|
45
|
-
"@midscene/shared": "1.5.4
|
|
44
|
+
"@midscene/core": "1.5.4",
|
|
45
|
+
"@midscene/shared": "1.5.4"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
48
|
"@ffmpeg-installer/ffmpeg": "^1.1.0"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"tsx": "^4.19.2",
|
|
57
57
|
"vitest": "3.0.5",
|
|
58
58
|
"zod": "3.24.3",
|
|
59
|
-
"@midscene/playground": "1.5.4
|
|
59
|
+
"@midscene/playground": "1.5.4"
|
|
60
60
|
},
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"scripts": {
|