testdriverai 5.3.9 → 5.3.10

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/agent.js CHANGED
@@ -239,7 +239,13 @@ const dieOnFatal = async (error) => {
239
239
  // creates a new "thread" in which the AI is given an error
240
240
  // and responds. notice `actOnMarkdown` which will continue
241
241
  // the thread until there are no more codeblocks to execute
242
- const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
242
+ const haveAIResolveError = async (
243
+ error,
244
+ markdown,
245
+ depth = 0,
246
+ undo = true,
247
+ shouldSave,
248
+ ) => {
243
249
  if (error.fatal) {
244
250
  return await dieOnFatal(error);
245
251
  }
@@ -299,7 +305,7 @@ const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
299
305
  mdStream.end();
300
306
 
301
307
  if (response?.data) {
302
- return await actOnMarkdown(response.data, depth, true);
308
+ return await actOnMarkdown(response.data, depth, true, false, shouldSave);
303
309
  }
304
310
  };
305
311
 
@@ -350,7 +356,7 @@ const check = async () => {
350
356
  // command is transformed from a single yml entry generated by the AI into a JSON object
351
357
  // it is mapped via `commander` to the `commands` module so the yaml
352
358
  // parameters can be mapped to actual functions
353
- const runCommand = async (command, depth) => {
359
+ const runCommand = async (command, depth, shouldSave) => {
354
360
  let yml = await yaml.dump(command);
355
361
 
356
362
  logger.debug(`running command: \n\n${yml}`);
@@ -372,7 +378,7 @@ const runCommand = async (command, depth) => {
372
378
  }
373
379
 
374
380
  if (response && typeof response === "string") {
375
- return await actOnMarkdown(response, depth);
381
+ return await actOnMarkdown(response, depth, true, false);
376
382
  }
377
383
  } catch (error) {
378
384
  return await haveAIResolveError(
@@ -380,6 +386,7 @@ const runCommand = async (command, depth) => {
380
386
  yaml.dump({ commands: [yml] }),
381
387
  depth,
382
388
  true,
389
+ shouldSave,
383
390
  );
384
391
  }
385
392
  };
@@ -392,6 +399,7 @@ const executeCommands = async (
392
399
  depth,
393
400
  pushToHistory = false,
394
401
  dry = false,
402
+ shouldSave = false,
395
403
  ) => {
396
404
  if (commands?.length) {
397
405
  for (const command of commands) {
@@ -400,7 +408,11 @@ const executeCommands = async (
400
408
  }
401
409
 
402
410
  if (!dry) {
403
- await runCommand(command, depth);
411
+ await runCommand(command, depth, shouldSave);
412
+ }
413
+
414
+ if (shouldSave) {
415
+ await save({ silent: true });
404
416
  }
405
417
 
406
418
  let timeToComplete = (new Date().getTime() - lastCommand) / 1000;
@@ -419,6 +431,7 @@ const executeCodeBlocks = async (
419
431
  depth,
420
432
  pushToHistory = false,
421
433
  dry = false,
434
+ shouldSave = false,
422
435
  ) => {
423
436
  depth = depth + 1;
424
437
 
@@ -434,23 +447,33 @@ const executeCodeBlocks = async (
434
447
  e,
435
448
  yaml.dump(parser.getYAMLFromCodeBlock(codeblock)),
436
449
  depth,
450
+ shouldSave,
437
451
  );
438
452
  }
439
453
 
440
- await executeCommands(commands, depth, pushToHistory, dry);
454
+ await executeCommands(commands, depth, pushToHistory, dry, shouldSave);
441
455
  }
442
456
  };
443
457
 
444
458
  // this is the main function that interacts with the ai, runs commands, and checks the results
445
459
  // notice that depth is 0 here. when this function resolves, the task is considered complete
446
460
  // notice the call to `check()` which validates the prompt is complete
447
- const aiExecute = async (message, validateAndLoop = false, dry = false) => {
461
+ const aiExecute = async (
462
+ message,
463
+ validateAndLoop = false,
464
+ dry = false,
465
+ shouldSave = false,
466
+ ) => {
448
467
  executionHistory.push({ prompt: lastPrompt, commands: [] });
449
468
 
469
+ if (shouldSave) {
470
+ await save({ silent: true });
471
+ }
472
+
450
473
  logger.debug("kicking off exploratory loop");
451
474
 
452
475
  // kick everything off
453
- await actOnMarkdown(message, 0, true, dry);
476
+ await actOnMarkdown(message, 0, true, dry, shouldSave);
454
477
 
455
478
  if (validateAndLoop) {
456
479
  logger.debug("exploratory loop resolved, check your work");
@@ -461,7 +484,7 @@ const aiExecute = async (message, validateAndLoop = false, dry = false) => {
461
484
  try {
462
485
  checkCodeblocks = await parser.findCodeBlocks(response);
463
486
  } catch (error) {
464
- return await haveAIResolveError(error, response, 0);
487
+ return await haveAIResolveError(error, response, 0, true, true);
465
488
  }
466
489
 
467
490
  logger.debug(`found ${checkCodeblocks.length} codeblocks`);
@@ -560,6 +583,7 @@ const exploratoryLoop = async (
560
583
  currentTask,
561
584
  dry = false,
562
585
  validateAndLoop = false,
586
+ shouldSave = true,
563
587
  ) => {
564
588
  lastPrompt = currentTask;
565
589
  checkCount = 0;
@@ -594,7 +618,7 @@ const exploratoryLoop = async (
594
618
  mdStream.end();
595
619
 
596
620
  if (message) {
597
- await aiExecute(message.data, validateAndLoop, dry);
621
+ await aiExecute(message.data, validateAndLoop, dry, shouldSave);
598
622
  logger.debug("showing prompt from exploratoryLoop response check");
599
623
  }
600
624
 
@@ -714,6 +738,7 @@ const actOnMarkdown = async (
714
738
  depth,
715
739
  pushToHistory = false,
716
740
  dry = false,
741
+ shouldSave,
717
742
  ) => {
718
743
  logger.debug("%j", {
719
744
  message: "actOnMarkdown called",
@@ -725,7 +750,7 @@ const actOnMarkdown = async (
725
750
  codeblocks = await parser.findCodeBlocks(content);
726
751
  } catch (error) {
727
752
  pushToHistory = false;
728
- return await haveAIResolveError(error, content, depth);
753
+ return await haveAIResolveError(error, content, depth, false, shouldSave);
729
754
  }
730
755
 
731
756
  if (codeblocks.length) {
@@ -734,6 +759,7 @@ const actOnMarkdown = async (
734
759
  depth,
735
760
  pushToHistory,
736
761
  dry,
762
+ shouldSave,
737
763
  );
738
764
  return executions;
739
765
  } else {
@@ -864,7 +890,7 @@ const firstPrompt = async () => {
864
890
  logger.error(result.error.result.stdout);
865
891
  }
866
892
  } else {
867
- await exploratoryLoop(input, false, true);
893
+ await exploratoryLoop(input, false, true, true);
868
894
  }
869
895
 
870
896
  setTerminalWindowTransparency(false);
@@ -1104,7 +1130,7 @@ ${yaml.dump(step)}
1104
1130
  logger.debug("load calling actOnMarkdown");
1105
1131
 
1106
1132
  lastPrompt = step.prompt;
1107
- await actOnMarkdown(markdown, 0, true);
1133
+ await actOnMarkdown(markdown, 0, true, false, shouldSave);
1108
1134
 
1109
1135
  if (shouldSave) {
1110
1136
  await save({ silent: true });
@@ -89,7 +89,7 @@ jobs:
89
89
  with:
90
90
  key: ${{ secrets.TESTDRIVER_API_KEY }}
91
91
  prompt: |
92
- 1. /run testdriver/onboarding.yaml
92
+ 1. /run testdriver/onboarding.yaml --save
93
93
  create-pr: true
94
94
  pr-title: "Auto-Healed Test Updates"
95
95
  pr-base: main
@@ -12,7 +12,7 @@ The TestDriver.ai VSCode extension is available for download on our GitHub relea
12
12
  <Card
13
13
  title="Download the VSCode Extension"
14
14
  icon="download"
15
- href="https://github.com/testdriverai/vscode/releases"
15
+ href="https://github.com/testdriverai/vscode/releases/latest/download/testdriver.vsix"
16
16
  >
17
17
  Get the latest version of the TestDriver.ai VSCode extension from our GitHub releases page.
18
18
  </Card>
@@ -1,65 +1,65 @@
1
- const fs = require('fs');
2
- const { execSync } = require('child_process');
3
- const dotenv = require('dotenv');
4
- const prompts = require('prompts');
1
+ const fs = require("fs");
2
+ const { execSync } = require("child_process");
3
+ const dotenv = require("dotenv");
4
+ const prompts = require("prompts");
5
5
 
6
6
  module.exports = async () => {
7
-
8
- // 1. Check for GitHub CLI
9
- try {
10
- execSync('gh --version', { stdio: 'ignore' });
11
- } catch (err) {
12
- console.log(err)
13
- console.error('āŒ GitHub CLI (gh) is not installed.\n');
14
- console.log('šŸ‘‰ Install it from https://cli.github.com/');
15
- console.log(' macOS: brew install gh');
16
- console.log(' Windows: winget install GitHub.cli');
17
- console.log(' Ubuntu: sudo apt install gh\n');
18
- process.exit(1);
19
- }
20
-
21
- // 2. Load and parse .env file
22
- const envPath = '.env';
23
- if (!fs.existsSync(envPath)) {
24
- console.error('āŒ .env file not found.');
25
- process.exit(1);
26
- }
27
-
28
- const env = dotenv.parse(fs.readFileSync(envPath));
29
- const tdSecrets = Object.entries(env).filter(([key]) => key.startsWith('TD_'));
30
-
31
- if (tdSecrets.length === 0) {
32
- console.log('ā„¹ļø No secrets found in .env that start with TD_');
33
- process.exit(0);
34
- }
7
+ // 1. Check for GitHub CLI
8
+ try {
9
+ execSync("gh --version", { stdio: "ignore" });
10
+ } catch (err) {
11
+ console.log(err);
12
+ console.error("āŒ GitHub CLI (gh) is not installed.\n");
13
+ console.log("šŸ‘‰ Install it from https://cli.github.com/");
14
+ console.log(" macOS: brew install gh");
15
+ console.log(" Windows: winget install GitHub.cli");
16
+ console.log(" Ubuntu: sudo apt install gh\n");
17
+ process.exit(1);
18
+ }
35
19
 
36
- // 3. Prompt user for confirmation
37
- (async () => {
38
- console.log('\nšŸ” The following TD_ secrets will be uploaded:');
39
- tdSecrets.forEach(([key]) => console.log(`- ${key}`));
20
+ // 2. Load and parse .env file
21
+ const envPath = ".env";
22
+ if (!fs.existsSync(envPath)) {
23
+ console.error("āŒ .env file not found.");
24
+ process.exit(1);
25
+ }
40
26
 
41
- const response = await prompts({
42
- type: 'confirm',
43
- name: 'confirm',
44
- message: '\nAre you sure you want to upload these secrets to the current GitHub repo?',
45
- initial: false,
46
- });
27
+ const env = dotenv.parse(fs.readFileSync(envPath));
28
+ const tdSecrets = Object.entries(env).filter(([key]) =>
29
+ key.startsWith("TD_"),
30
+ );
47
31
 
48
- if (!response.confirm) {
49
- console.log('āŒ Upload cancelled.');
32
+ if (tdSecrets.length === 0) {
33
+ console.log("ā„¹ļø No secrets found in .env that start with TD_");
50
34
  process.exit(0);
51
35
  }
52
36
 
53
- // 4. Upload secrets using GitHub CLI
54
- for (const [key, value] of tdSecrets) {
55
- try {
56
- const cmd = `gh secret set ${key} --body "${value}"`;
57
- execSync(cmd, { stdio: 'inherit' });
58
- } catch (err) {
59
- console.error(`āŒ Failed to upload ${key}: ${err.message}`);
60
- }
61
- }
37
+ // 3. Prompt user for confirmation
38
+ (async () => {
39
+ console.log("\nšŸ” The following TD_ secrets will be uploaded:");
40
+ tdSecrets.forEach(([key]) => console.log(`- ${key}`));
62
41
 
63
- })();
42
+ const response = await prompts({
43
+ type: "confirm",
44
+ name: "confirm",
45
+ message:
46
+ "\nAre you sure you want to upload these secrets to the current GitHub repo?",
47
+ initial: false,
48
+ });
64
49
 
65
- }
50
+ if (!response.confirm) {
51
+ console.log("āŒ Upload cancelled.");
52
+ process.exit(0);
53
+ }
54
+
55
+ // 4. Upload secrets using GitHub CLI
56
+ for (const [key, value] of tdSecrets) {
57
+ try {
58
+ const cmd = `gh secret set ${key} --body "${value}"`;
59
+ execSync(cmd, { stdio: "inherit" });
60
+ } catch (err) {
61
+ console.error(`āŒ Failed to upload ${key}`);
62
+ }
63
+ }
64
+ })();
65
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "5.3.9",
3
+ "version": "5.3.10",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {