testdriverai 4.0.33 → 4.0.35

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/index.js CHANGED
@@ -100,14 +100,49 @@ console.log('')
100
100
  // individual run ID for this session
101
101
  let runID = new Date().getTime();
102
102
 
103
+ function fileCompleter(line) {
104
+ line = line.slice(5); // remove /run
105
+ const lastSepIndex = line.lastIndexOf(path.sep);
106
+ let dir;
107
+ let partial;
108
+ if (lastSepIndex === -1) {
109
+ dir = '.';
110
+ partial = line;
111
+ }
112
+ else{
113
+ dir = line.slice(0, lastSepIndex + 1);
114
+ partial = line.slice(lastSepIndex + 1);
115
+ }
116
+ try{
117
+ const dirPath = path.resolve(process.cwd(), dir);
118
+
119
+ let files = fs.readdirSync(dirPath);
120
+ files = files.map(file => {
121
+ const fullFilePath = path.join(dirPath, file);
122
+ const fileStats = fs.statSync(fullFilePath);
123
+ return file + (fileStats.isDirectory() ? path.sep : ''); // add path.sep for dir
124
+ });
125
+ const matches = files.filter(file => file.startsWith(partial));
126
+
127
+ return [matches.length ? matches : files, partial];
128
+ }
129
+ catch(err){
130
+ return [[], partial];
131
+ }
132
+ }
133
+
103
134
  function completer(line) {
104
135
  let completions = '/summarize /save /run /quit /explore /assert /undo /manual'.split(' ')
105
-
136
+ if(line.startsWith('/run ')){
137
+ return fileCompleter(line);
138
+ }
139
+ else{
106
140
  completions.concat(tasks)
107
141
 
108
142
  var hits = completions.filter(function(c) { return c.indexOf(line) == 0 })
109
143
  // show all completions if none found
110
- return [hits.length ? hits : completions, line]
144
+ return [hits.length ? hits : completions, line]
145
+ }
111
146
  }
112
147
 
113
148
  if (!fs.existsSync(commandHistoryFile)) {
@@ -170,7 +205,7 @@ const haveAIResolveError = async (error, markdown, depth = 0, undo = false) => {
170
205
 
171
206
  let image;
172
207
  if (error.attachScreenshot) {
173
- image = await system.captureScreenBase64();
208
+ image = await system.captureScreenBase64(.5);
174
209
  } else {
175
210
  image = null;
176
211
  }
@@ -196,7 +231,7 @@ const check = async () => {
196
231
 
197
232
  console.log('')
198
233
  log.log('info', chalk.dim('checking...'), 'testdriver')
199
- let image = await system.captureScreenBase64();
234
+ let image = await system.captureScreenBase64(.5);
200
235
  let mousePosition = await system.getMousePosition();
201
236
  let activeWindow = await system.activeWin();
202
237
  return await sdk.req('check', {tasks, image, mousePosition, activeWindow});
@@ -382,7 +417,7 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
382
417
 
383
418
  log.log('info', '');
384
419
 
385
- let image = await system.captureScreenBase64();
420
+ let image = await system.captureScreenBase64(.5);
386
421
  let message = await sdk.req('input', {
387
422
  input: currentTask,
388
423
  mousePosition: await system.getMousePosition(),
@@ -409,7 +444,7 @@ const generate = async (type) => {
409
444
 
410
445
  log.log('info', '');
411
446
 
412
- let image = await system.captureScreenBase64();
447
+ let image = await system.captureScreenBase64(.5);
413
448
  let message = await sdk.req('generate', {
414
449
  type,
415
450
  image});
@@ -420,9 +455,8 @@ const generate = async (type) => {
420
455
 
421
456
  // for each testPrompt
422
457
  for (const testPrompt of testPrompts) {
423
- // write a file called testprompt.headings[0].replace(' ', '-').toLowerCase().md
424
458
  // with the contents of the testPrompt
425
- let fileName = testPrompt.headings[0].trim().replace(/ /g, '-').toLowerCase() + '.md';
459
+ let fileName = sanitizeFilename(testPrompt.headings[0]).trim().replace(/ /g, '-').toLowerCase() + '.md';
426
460
  let path1 = path.join(process.cwd(), 'testdriver', '.generate', fileName);
427
461
  let contents = testPrompt.listsOrdered[0].map((item, index) => `${index + 1}. /explore ${item}`).join('\n');
428
462
  fs.writeFileSync(path1, contents);
@@ -634,7 +668,7 @@ let summarize = async (error = null) => {
634
668
  log.log('info', chalk.dim('reviewing test...'), true);
635
669
 
636
670
  // let text = prompts.summarize(tasks, error);
637
- let image = await system.captureScreenBase64();
671
+ let image = await system.captureScreenBase64(.5);
638
672
 
639
673
  log.log('info', chalk.dim('summarizing...'), true);
640
674
 
package/lib/commands.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // the actual commands to interact with the system
2
2
  const sdk = require('./sdk');
3
3
  const chalk = require('chalk');
4
- const {captureScreenBase64, captureScreenPNG, platform, getDisplayMultiple, activeWin} = require('./system');
4
+ const {captureScreenBase64, captureScreenPNG, platform, activeWin} = require('./system');
5
5
  const {log} = require('./logger');
6
6
  const keymap = require('./keymap');
7
7
  const { focusApplication } = require('./focus-application');
@@ -31,7 +31,6 @@ class AiError extends Error {
31
31
  const commandOrControl = process.platform === 'darwin' ? 'command' : 'control';
32
32
 
33
33
  const findImageOnScreen = async (relativePath, haystack, restrictToWindow) => {
34
- let displayMultiple = await getDisplayMultiple();
35
34
 
36
35
  // move the file from filePath to `testdriver/screenshots`
37
36
  let rootpath = path.join(cwd(), `testdriver`, `screenshots`, platform());
@@ -94,10 +93,10 @@ const findImageOnScreen = async (relativePath, haystack, restrictToWindow) => {
94
93
 
95
94
  results = results.filter((el) => {
96
95
 
97
- return el.centerX * displayMultiple > activeWindow.bounds.x
98
- && el.centerX * displayMultiple < activeWindow.bounds.x + activeWindow.bounds.width
99
- && el.centerY * displayMultiple > activeWindow.bounds.y
100
- && el.centerY * displayMultiple < activeWindow.bounds.y + activeWindow.bounds.height;
96
+ return el.centerX > activeWindow.bounds.x
97
+ && el.centerX < activeWindow.bounds.x + activeWindow.bounds.width
98
+ && el.centerY > activeWindow.bounds.y
99
+ && el.centerY < activeWindow.bounds.y + activeWindow.bounds.height;
101
100
 
102
101
  });
103
102
  }
@@ -250,7 +249,7 @@ let commands = {
250
249
  button,
251
250
  clickType,
252
251
  description,
253
- displayMultiple: await getDisplayMultiple()
252
+ displayMultiple: 1
254
253
  });
255
254
 
256
255
  if (!response.data) {
@@ -275,7 +274,7 @@ let commands = {
275
274
  intent: action,
276
275
  button,
277
276
  clickType,
278
- displayMultiple: await getDisplayMultiple()
277
+ displayMultiple: 1
279
278
  });
280
279
 
281
280
  if (!response?.data) {
@@ -293,16 +292,14 @@ let commands = {
293
292
 
294
293
  let result = await findImageOnScreen(relativePath, image)
295
294
 
296
- let displayMultiple = await getDisplayMultiple();
297
-
298
295
  if (!result) {
299
296
  throw new AiError(`Image not found: ${relativePath}`)
300
297
  } else {
301
298
 
302
299
  if (action === 'click') {
303
- await click(result.centerX * displayMultiple, result.centerY * displayMultiple, button, clickType);
300
+ await click(result.centerX, result.centerY, button, clickType);
304
301
  } else if (action === 'hover') {
305
- await hover(result.centerX * displayMultiple, result.centerY * displayMultiple);
302
+ await hover(result.centerX, result.centerY);
306
303
  }
307
304
  }
308
305
 
package/lib/sdk.js CHANGED
@@ -1,7 +1,11 @@
1
1
 
2
2
  // custom "sdk" for calling our API
3
- // const root = "https://replayable-dev-ian-mac-m1-16.ngrok.io";
4
- const root = "https://replayable-api-production.herokuapp.com";
3
+ let root = "https://replayable-api-production.herokuapp.com";
4
+
5
+ if (process.env['DEV']) {
6
+ root = "https://replayable-dev-ian-mac-m1-16.ngrok.io";
7
+ }
8
+
5
9
  const chalk = require('chalk');
6
10
  const axios = require('axios');
7
11
  const session = require('./session')
package/lib/system.js CHANGED
@@ -8,7 +8,6 @@ const activeWindow = require('active-win');
8
8
  const robot = require('robotjs');
9
9
  const sharp = require('sharp')
10
10
 
11
- let displayMultiple = 0;
12
11
  let primaryDisplay = null;
13
12
 
14
13
  // get the primary display
@@ -27,54 +26,34 @@ const getSystemInformationOsInfo = async() => {
27
26
  return await si.osInfo();
28
27
  }
29
28
 
30
- // this hepls us understand how to scale things for retina screens
31
- const calculateDisplayMultiple = async () => {
32
- let primaryDisplay = await getPrimaryDisplay();
33
- displayMultiple = primaryDisplay.currentResX / primaryDisplay.resolutionX;
34
- };
35
-
36
- const getDisplayMultiple = async () => {
37
-
38
- if (!displayMultiple) {
39
- await calculateDisplayMultiple();
40
- }
41
-
42
- return displayMultiple;
43
- };
44
-
45
29
  const tmpFilename = () => {
46
30
  return path.join(os.tmpdir(), `${new Date().getTime() + Math.random()}.png`);
47
31
  }
48
32
 
49
- // our handy screenshot function
50
- const captureScreenBase64 = async () => {
51
-
33
+ const captureAndResize = async(scale = 1) => {
52
34
  let primaryDisplay = await getPrimaryDisplay();
53
35
 
54
36
  let step1 = tmpFilename();
55
37
  let step2 = tmpFilename();
56
38
 
57
- await screenshot({ filename: step1, format: 'png' });
39
+ let step1Screenshot = await screenshot({ filename: step1, format: 'png' });
58
40
 
59
- // // resize to 1:1 px ratio
41
+ // resize to 1:1 px ratio
60
42
  await sharp(step1)
61
- .resize(primaryDisplay.currentResX, primaryDisplay.currentResY)
43
+ .resize(Math.floor(primaryDisplay.currentResX * scale), Math.floor(primaryDisplay.currentResY * scale))
62
44
  .toFile(step2);
63
45
 
64
- // let image = fs.readFileSync(step1, "base64");
65
- let image = fs.readFileSync(step2, "base64");
66
-
67
- return image;
46
+ return step2;
47
+ }
68
48
 
49
+ // our handy screenshot function
50
+ const captureScreenBase64 = async (scale = 1) => {
51
+ let step2 = await captureAndResize(scale);
52
+ return fs.readFileSync(step2, "base64");
69
53
  };
70
54
 
71
- const captureScreenPNG = async () => {
72
-
73
- let step1 = tmpFilename();
74
- await screenshot({ filename: step1, format: 'png' });
75
-
76
- return step1;
77
-
55
+ const captureScreenPNG = async (scale = 1) => {
56
+ return await captureAndResize(scale);
78
57
  }
79
58
 
80
59
  const platform = () => {
@@ -103,8 +82,6 @@ const getMousePosition = async () => {
103
82
  module.exports = {
104
83
  captureScreenBase64,
105
84
  captureScreenPNG,
106
- getDisplayMultiple,
107
- calculateDisplayMultiple,
108
85
  getMousePosition,
109
86
  primaryDisplay,
110
87
  activeWin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "4.0.33",
3
+ "version": "4.0.35",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {