testdriverai 4.2.10 → 4.2.12
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 +129 -132
- package/index.js +2 -1
- package/lib/commander.js +18 -18
- package/lib/commands.js +34 -37
- package/lib/config.js +2 -1
- package/lib/focus-application.js +4 -3
- package/lib/history.js +4 -4
- package/lib/init.js +22 -21
- package/lib/logger.js +42 -66
- package/lib/overlay.js +3 -2
- package/lib/redraw.js +7 -7
- package/lib/sdk.js +5 -5
- package/lib/subimage/index.js +3 -2
- package/lib/system.js +3 -1
- package/package.json +1 -1
package/agent.js
CHANGED
|
@@ -49,6 +49,8 @@ const session = require("./lib/session.js");
|
|
|
49
49
|
const notify = require("./lib/notify.js");
|
|
50
50
|
const { emitter, events } = require("./lib/events.js");
|
|
51
51
|
|
|
52
|
+
const logger = log.logger;
|
|
53
|
+
|
|
52
54
|
let lastPrompt = "";
|
|
53
55
|
let terminalApp = "";
|
|
54
56
|
let commandHistory = [];
|
|
@@ -84,7 +86,7 @@ let getArgs = () => {
|
|
|
84
86
|
args[file] == "--help" ||
|
|
85
87
|
args[file] == "-h"
|
|
86
88
|
) {
|
|
87
|
-
|
|
89
|
+
logger.info("Command: testdriverai [init, run, edit] [yaml filepath]");
|
|
88
90
|
process.exit(0);
|
|
89
91
|
}
|
|
90
92
|
|
|
@@ -123,13 +125,13 @@ let a = getArgs();
|
|
|
123
125
|
const thisFile = a.file;
|
|
124
126
|
const thisCommand = a.command;
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
logger.info(chalk.green(`Howdy! I'm TestDriver v${package.version}`));
|
|
129
|
+
logger.info(chalk.dim(`Working on ${thisFile}`));
|
|
130
|
+
logger.info("");
|
|
131
|
+
logger.info(chalk.yellow(`This is beta software!`));
|
|
132
|
+
logger.info(`Join our Discord for help`);
|
|
133
|
+
logger.info(`https://discord.com/invite/cWDFW8DzPm`);
|
|
134
|
+
logger.info("");
|
|
133
135
|
|
|
134
136
|
// individual run ID for this session
|
|
135
137
|
// let runID = new Date().getTime();
|
|
@@ -159,7 +161,7 @@ function fileCompleter(line) {
|
|
|
159
161
|
|
|
160
162
|
return [matches.length ? matches : files, partial];
|
|
161
163
|
} catch (e) {
|
|
162
|
-
|
|
164
|
+
logger.info("%s", e);
|
|
163
165
|
return [[], partial];
|
|
164
166
|
}
|
|
165
167
|
}
|
|
@@ -219,8 +221,7 @@ const exit = async (failed = true, shouldSave = false) => {
|
|
|
219
221
|
};
|
|
220
222
|
|
|
221
223
|
const dieOnFatal = async (error) => {
|
|
222
|
-
|
|
223
|
-
log.log("info", chalk.red("Fatal Error") + `\n${error.message}`);
|
|
224
|
+
logger.error(chalk.red("Fatal Error") + `\n${error.message}`);
|
|
224
225
|
await summarize(error.message);
|
|
225
226
|
return await exit(true);
|
|
226
227
|
};
|
|
@@ -238,19 +239,17 @@ const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
|
|
|
238
239
|
let safeKey = JSON.stringify(eMessage);
|
|
239
240
|
errorCounts[safeKey] = errorCounts[safeKey] ? errorCounts[safeKey] + 1 : 1;
|
|
240
241
|
|
|
241
|
-
|
|
242
|
+
logger.error(eMessage);
|
|
242
243
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.log(error.stack);
|
|
246
|
-
}
|
|
244
|
+
logger.debug("%j", error);
|
|
245
|
+
logger.debug("%s", error.stack);
|
|
247
246
|
|
|
248
247
|
log.prettyMarkdown(eMessage);
|
|
249
248
|
|
|
250
249
|
// if we get the same error 3 times in `run` mode, we exit
|
|
251
250
|
if (errorCounts[safeKey] > errorLimit - 1) {
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
logger.info(chalk.red("Error loop detected. Exiting."));
|
|
252
|
+
logger.info("%s", eMessage);
|
|
254
253
|
await summarize(eMessage);
|
|
255
254
|
return await exit(true);
|
|
256
255
|
}
|
|
@@ -268,8 +267,8 @@ const haveAIResolveError = async (error, markdown, depth = 0, undo = true) => {
|
|
|
268
267
|
|
|
269
268
|
speak("thinking...");
|
|
270
269
|
notify("thinking...");
|
|
271
|
-
|
|
272
|
-
|
|
270
|
+
logger.info(chalk.dim("thinking..."), true);
|
|
271
|
+
logger.info("");
|
|
273
272
|
|
|
274
273
|
const mdStream = log.createMarkdownStreamLogger();
|
|
275
274
|
|
|
@@ -300,14 +299,14 @@ const check = async () => {
|
|
|
300
299
|
checkCount++;
|
|
301
300
|
|
|
302
301
|
if (checkCount >= checkLimit) {
|
|
303
|
-
|
|
302
|
+
logger.info(chalk.red("Exploratory loop detected. Exiting."));
|
|
304
303
|
await summarize("Check loop detected.");
|
|
305
304
|
return await exit(true);
|
|
306
305
|
}
|
|
307
306
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
logger.info("");
|
|
308
|
+
logger.info(chalk.dim("checking..."), "testdriver");
|
|
309
|
+
logger.info("");
|
|
311
310
|
|
|
312
311
|
let thisScreenshot = await system.captureScreenBase64(1, false, true);
|
|
313
312
|
let images = [lastScreenshot, thisScreenshot];
|
|
@@ -342,7 +341,7 @@ const check = async () => {
|
|
|
342
341
|
const runCommand = async (command, depth) => {
|
|
343
342
|
let yml = await yaml.dump(command);
|
|
344
343
|
|
|
345
|
-
|
|
344
|
+
logger.debug(`running command: \n\n${yml}`);
|
|
346
345
|
|
|
347
346
|
try {
|
|
348
347
|
let response;
|
|
@@ -378,6 +377,7 @@ let csv = [["command,time"]];
|
|
|
378
377
|
|
|
379
378
|
const executeCommands = async (commands, depth, pushToHistory = false) => {
|
|
380
379
|
if (commands?.length) {
|
|
380
|
+
|
|
381
381
|
for (const command of commands) {
|
|
382
382
|
if (pushToHistory) {
|
|
383
383
|
executionHistory[executionHistory.length - 1]?.commands.push(command);
|
|
@@ -386,7 +386,7 @@ const executeCommands = async (commands, depth, pushToHistory = false) => {
|
|
|
386
386
|
await runCommand(command, depth);
|
|
387
387
|
|
|
388
388
|
let timeToComplete = (new Date().getTime() - lastCommand) / 1000;
|
|
389
|
-
//
|
|
389
|
+
// logger.info(timeToComplete, 'seconds')
|
|
390
390
|
|
|
391
391
|
csv.push([command.command, timeToComplete]);
|
|
392
392
|
lastCommand = new Date().getTime();
|
|
@@ -399,7 +399,7 @@ const executeCommands = async (commands, depth, pushToHistory = false) => {
|
|
|
399
399
|
const executeCodeBlocks = async (codeblocks, depth, pushToHistory = false) => {
|
|
400
400
|
depth = depth + 1;
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
logger.debug("%j", { message: "execute code blocks", depth });
|
|
403
403
|
|
|
404
404
|
for (const codeblock of codeblocks) {
|
|
405
405
|
let commands;
|
|
@@ -424,13 +424,13 @@ const executeCodeBlocks = async (codeblocks, depth, pushToHistory = false) => {
|
|
|
424
424
|
const aiExecute = async (message, validateAndLoop = false) => {
|
|
425
425
|
executionHistory.push({ prompt: lastPrompt, commands: [] });
|
|
426
426
|
|
|
427
|
-
|
|
427
|
+
logger.debug("kicking off exploratory loop");
|
|
428
428
|
|
|
429
429
|
// kick everything off
|
|
430
430
|
await actOnMarkdown(message, 0, true);
|
|
431
431
|
|
|
432
432
|
if (validateAndLoop) {
|
|
433
|
-
|
|
433
|
+
logger.debug("exploratory loop resolved, check your work");
|
|
434
434
|
|
|
435
435
|
let response = await check();
|
|
436
436
|
|
|
@@ -441,18 +441,58 @@ const aiExecute = async (message, validateAndLoop = false) => {
|
|
|
441
441
|
return await haveAIResolveError(error, response, 0);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
|
|
444
|
+
logger.debug(`found ${checkCodeblocks.length} codeblocks`);
|
|
445
445
|
|
|
446
446
|
if (checkCodeblocks.length > 0) {
|
|
447
|
-
|
|
447
|
+
logger.debug("check thinks more needs to be done");
|
|
448
448
|
return await aiExecute(response, validateAndLoop);
|
|
449
449
|
} else {
|
|
450
|
-
|
|
450
|
+
logger.debug("seems complete, returning");
|
|
451
451
|
return response;
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
};
|
|
455
455
|
|
|
456
|
+
const loadYML = async (file) => {
|
|
457
|
+
|
|
458
|
+
let yml;
|
|
459
|
+
|
|
460
|
+
//wrap this in try/catch so if the file doesn't exist output an error message to the user
|
|
461
|
+
try {
|
|
462
|
+
yml = fs.readFileSync(file, "utf-8");
|
|
463
|
+
} catch (e) {
|
|
464
|
+
logger.error(e);
|
|
465
|
+
logger.error(`File not found: ${file}`);
|
|
466
|
+
logger.error(`Current directory: ${process.cwd()}`);
|
|
467
|
+
|
|
468
|
+
await summarize("File not found");
|
|
469
|
+
await exit(true);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
let interpolationVars = JSON.parse(process.env["TD_INTERPOLATION_VARS"] || '{}');
|
|
473
|
+
|
|
474
|
+
// Inject environment variables into any ${VAR} strings
|
|
475
|
+
yml = parser.interpolate(yml, process.env);
|
|
476
|
+
|
|
477
|
+
// Inject any vars from the TD_INTERPOLATION_VARS variable (typically from the action)
|
|
478
|
+
yml = parser.interpolate(yml, interpolationVars);
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
let ymlObj = null;
|
|
482
|
+
try {
|
|
483
|
+
ymlObj = await yaml.load(yml);
|
|
484
|
+
} catch (e) {
|
|
485
|
+
logger.error("%s", e);
|
|
486
|
+
logger.error(`Invalid YAML: ${file}`);
|
|
487
|
+
|
|
488
|
+
await summarize("Invalid YAML");
|
|
489
|
+
await exit(true);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return ymlObj;
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
|
|
456
496
|
const assert = async (expect) => {
|
|
457
497
|
analytics.track("assert");
|
|
458
498
|
|
|
@@ -469,8 +509,8 @@ const assert = async (expect) => {
|
|
|
469
509
|
|
|
470
510
|
speak("thinking...");
|
|
471
511
|
notify("thinking...");
|
|
472
|
-
|
|
473
|
-
|
|
512
|
+
logger.info(chalk.dim("thinking..."), true);
|
|
513
|
+
logger.info("");
|
|
474
514
|
|
|
475
515
|
let response = `\`\`\`yml
|
|
476
516
|
commands:
|
|
@@ -489,14 +529,14 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
|
|
|
489
529
|
lastPrompt = currentTask;
|
|
490
530
|
checkCount = 0;
|
|
491
531
|
|
|
492
|
-
|
|
532
|
+
logger.debug("humanInput called");
|
|
493
533
|
|
|
494
534
|
tasks.push(currentTask);
|
|
495
535
|
|
|
496
536
|
speak("thinking...");
|
|
497
537
|
notify("thinking...");
|
|
498
|
-
|
|
499
|
-
|
|
538
|
+
logger.info(chalk.dim("thinking..."), true);
|
|
539
|
+
logger.info("");
|
|
500
540
|
|
|
501
541
|
lastScreenshot = await system.captureScreenBase64();
|
|
502
542
|
|
|
@@ -519,19 +559,19 @@ const humanInput = async (currentTask, validateAndLoop = false) => {
|
|
|
519
559
|
|
|
520
560
|
await aiExecute(message.data, validateAndLoop);
|
|
521
561
|
|
|
522
|
-
|
|
562
|
+
logger.debug("showing prompt from humanInput response check");
|
|
523
563
|
|
|
524
564
|
await save({ silent: true });
|
|
525
565
|
};
|
|
526
566
|
|
|
527
567
|
const generate = async (type, count) => {
|
|
528
|
-
|
|
568
|
+
logger.debug("generate called, %s", type);
|
|
529
569
|
|
|
530
570
|
speak("thinking...");
|
|
531
571
|
notify("thinking...");
|
|
532
572
|
|
|
533
|
-
|
|
534
|
-
|
|
573
|
+
logger.info(chalk.dim("thinking..."), true);
|
|
574
|
+
logger.info("");
|
|
535
575
|
|
|
536
576
|
let image = await system.captureScreenBase64();
|
|
537
577
|
const mdStream = log.createMarkdownStreamLogger();
|
|
@@ -583,7 +623,7 @@ const generate = async (type, count) => {
|
|
|
583
623
|
};
|
|
584
624
|
|
|
585
625
|
const popFromHistory = async (fullStep) => {
|
|
586
|
-
|
|
626
|
+
logger.info(chalk.dim("undoing..."), true);
|
|
587
627
|
|
|
588
628
|
if (executionHistory.length) {
|
|
589
629
|
if (fullStep) {
|
|
@@ -620,7 +660,7 @@ ${yml}
|
|
|
620
660
|
|
|
621
661
|
// this function is responsible for starting the recursive process of executing codeblocks
|
|
622
662
|
const actOnMarkdown = async (content, depth, pushToHistory = false) => {
|
|
623
|
-
|
|
663
|
+
logger.debug("%j", {
|
|
624
664
|
message: "actOnMarkdown called",
|
|
625
665
|
depth,
|
|
626
666
|
});
|
|
@@ -692,7 +732,7 @@ const firstPrompt = async () => {
|
|
|
692
732
|
|
|
693
733
|
analytics.track("input", { input });
|
|
694
734
|
|
|
695
|
-
|
|
735
|
+
logger.info(""); // adds a nice break between submissions
|
|
696
736
|
|
|
697
737
|
let commands = input.split(" ");
|
|
698
738
|
|
|
@@ -732,8 +772,8 @@ const firstPrompt = async () => {
|
|
|
732
772
|
|
|
733
773
|
if (!object?.steps) {
|
|
734
774
|
analytics.track("load invalid yaml");
|
|
735
|
-
|
|
736
|
-
|
|
775
|
+
logger.error("Invalid YAML. No steps found.");
|
|
776
|
+
logger.info("Invalid YAML: " + thisFile);
|
|
737
777
|
return await exit(true);
|
|
738
778
|
}
|
|
739
779
|
|
|
@@ -748,7 +788,7 @@ const firstPrompt = async () => {
|
|
|
748
788
|
${yml}
|
|
749
789
|
\`\`\``;
|
|
750
790
|
|
|
751
|
-
|
|
791
|
+
logger.info(`Loaded test script ${thisFile}\n`);
|
|
752
792
|
|
|
753
793
|
log.prettyMarkdown(`
|
|
754
794
|
|
|
@@ -770,7 +810,7 @@ let setTerminalWindowTransparency = async (hide) => {
|
|
|
770
810
|
.end();
|
|
771
811
|
} catch (e) {
|
|
772
812
|
// Suppress error
|
|
773
|
-
|
|
813
|
+
logger.error("Caught exception: %s", e);
|
|
774
814
|
}
|
|
775
815
|
} else {
|
|
776
816
|
try {
|
|
@@ -780,7 +820,7 @@ let setTerminalWindowTransparency = async (hide) => {
|
|
|
780
820
|
.end();
|
|
781
821
|
} catch (e) {
|
|
782
822
|
// Suppress error
|
|
783
|
-
|
|
823
|
+
logger.error("Caught exception:", e);
|
|
784
824
|
}
|
|
785
825
|
}
|
|
786
826
|
|
|
@@ -800,23 +840,23 @@ let setTerminalWindowTransparency = async (hide) => {
|
|
|
800
840
|
}
|
|
801
841
|
} catch (e) {
|
|
802
842
|
// Suppress error
|
|
803
|
-
|
|
843
|
+
logger.error("Caught exception: %s", e);
|
|
804
844
|
}
|
|
805
845
|
};
|
|
806
846
|
|
|
807
847
|
// this function is responsible for summarizing the test script that has already executed
|
|
808
|
-
// it is what is saved to the `/tmp/oiResult.log
|
|
848
|
+
// it is what is saved to the `/tmp/oiResult.log` file and output to the action as a summary
|
|
809
849
|
let summarize = async (error = null) => {
|
|
810
850
|
analytics.track("summarize");
|
|
811
851
|
|
|
812
|
-
|
|
852
|
+
logger.info("");
|
|
813
853
|
|
|
814
|
-
|
|
854
|
+
logger.info(chalk.dim("reviewing test..."), true);
|
|
815
855
|
|
|
816
856
|
// let text = prompts.summarize(tasks, error);
|
|
817
857
|
let image = await system.captureScreenBase64();
|
|
818
858
|
|
|
819
|
-
|
|
859
|
+
logger.info(chalk.dim("summarizing..."), true);
|
|
820
860
|
|
|
821
861
|
const mdStream = log.createMarkdownStreamLogger();
|
|
822
862
|
let reply = await sdk.req(
|
|
@@ -834,11 +874,11 @@ let summarize = async (error = null) => {
|
|
|
834
874
|
);
|
|
835
875
|
mdStream.end();
|
|
836
876
|
|
|
837
|
-
let resultFile = "/tmp/oiResult.log
|
|
877
|
+
let resultFile = "/tmp/oiResult.log";
|
|
838
878
|
if (process.platform === "win32") {
|
|
839
|
-
resultFile = "/Windows/Temp/oiResult.log
|
|
879
|
+
resultFile = "/Windows/Temp/oiResult.log";
|
|
840
880
|
}
|
|
841
|
-
// write reply to /tmp/oiResult.log
|
|
881
|
+
// write reply to /tmp/oiResult.log
|
|
842
882
|
fs.writeFileSync(resultFile, reply.data);
|
|
843
883
|
};
|
|
844
884
|
|
|
@@ -848,21 +888,21 @@ let save = async ({ filepath = thisFile, silent = false } = {}) => {
|
|
|
848
888
|
analytics.track("save", { silent });
|
|
849
889
|
|
|
850
890
|
if (!silent) {
|
|
851
|
-
|
|
852
|
-
|
|
891
|
+
logger.info(chalk.dim("saving..."), true);
|
|
892
|
+
logger.info("");
|
|
853
893
|
}
|
|
854
894
|
|
|
855
895
|
if (!executionHistory.length) {
|
|
856
896
|
return;
|
|
857
897
|
}
|
|
858
898
|
|
|
859
|
-
// write reply to /tmp/oiResult.log
|
|
899
|
+
// write reply to /tmp/oiResult.log
|
|
860
900
|
let regression = await generator.dumpToYML(executionHistory);
|
|
861
901
|
try {
|
|
862
902
|
fs.writeFileSync(filepath, regression);
|
|
863
903
|
} catch (e) {
|
|
864
|
-
|
|
865
|
-
|
|
904
|
+
logger.error(e.message);
|
|
905
|
+
logger.error("%s", e);
|
|
866
906
|
}
|
|
867
907
|
|
|
868
908
|
if (!silent) {
|
|
@@ -872,11 +912,11 @@ let save = async ({ filepath = thisFile, silent = false } = {}) => {
|
|
|
872
912
|
${regression}
|
|
873
913
|
\`\`\``);
|
|
874
914
|
|
|
875
|
-
//
|
|
915
|
+
// logger.info(csv.join('\n'))
|
|
876
916
|
|
|
877
917
|
const fileName = filepath.split("/").pop();
|
|
878
918
|
if (!silent) {
|
|
879
|
-
|
|
919
|
+
logger.info(chalk.dim(`saved as ${fileName}`));
|
|
880
920
|
}
|
|
881
921
|
}
|
|
882
922
|
};
|
|
@@ -891,50 +931,14 @@ let run = async (file, shouldSave = false, shouldExit = true) => {
|
|
|
891
931
|
setTerminalWindowTransparency(true);
|
|
892
932
|
emitter.emit(events.interactive, false);
|
|
893
933
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
executionHistory = [];
|
|
897
|
-
let yml;
|
|
934
|
+
logger.info(chalk.cyan(`running ${file}...`));
|
|
898
935
|
|
|
899
|
-
|
|
900
|
-
try {
|
|
901
|
-
yml = fs.readFileSync(file, "utf-8");
|
|
902
|
-
} catch (e) {
|
|
903
|
-
console.log(e);
|
|
904
|
-
log.log("error", "File not found. Please try again.");
|
|
905
|
-
console.log(`File not found: ${file}`);
|
|
906
|
-
console.log(`Current directory: ${process.cwd()}`);
|
|
907
|
-
|
|
908
|
-
await summarize("File not found");
|
|
909
|
-
await exit(true);
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
let interpolationVars = JSON.parse(process.env["TD_INTERPOLATION_VARS"] || '{}');
|
|
913
|
-
|
|
914
|
-
// Inject environment variables into any ${VAR} strings
|
|
915
|
-
yml = parser.interpolate(yml, process.env);
|
|
916
|
-
|
|
917
|
-
// Inject any vars from the TD_INTERPOLATION_VARS variable (typically from the action)
|
|
918
|
-
yml = parser.interpolate(yml, interpolationVars);
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
let ymlObj = null;
|
|
922
|
-
try {
|
|
923
|
-
ymlObj = await yaml.load(yml);
|
|
924
|
-
} catch (e) {
|
|
925
|
-
console.log(e);
|
|
926
|
-
log.log("error", "Invalid YAML. Please try again.");
|
|
927
|
-
console.log(`Invalid YAML: ${file}`);
|
|
928
|
-
|
|
929
|
-
await summarize("Invalid YAML");
|
|
930
|
-
await exit(true);
|
|
931
|
-
}
|
|
936
|
+
let ymlObj = await loadYML(file);
|
|
932
937
|
|
|
933
938
|
if (ymlObj.version) {
|
|
934
939
|
let valid = isValidVersion(ymlObj.version);
|
|
935
940
|
if (!valid) {
|
|
936
|
-
|
|
937
|
-
console.log(
|
|
941
|
+
logger.error(
|
|
938
942
|
`Version mismatch: ${file}. Trying to run a test with v${ymlObj.version} test when this package is v${package.version}.`,
|
|
939
943
|
);
|
|
940
944
|
|
|
@@ -946,8 +950,8 @@ let run = async (file, shouldSave = false, shouldExit = true) => {
|
|
|
946
950
|
executionHistory = [];
|
|
947
951
|
|
|
948
952
|
for (const step of ymlObj.steps) {
|
|
949
|
-
|
|
950
|
-
|
|
953
|
+
logger.info(``, null);
|
|
954
|
+
logger.info(chalk.yellow(`${step.prompt || "no prompt"}`), null);
|
|
951
955
|
|
|
952
956
|
executionHistory.push({
|
|
953
957
|
prompt: step.prompt,
|
|
@@ -958,8 +962,8 @@ let run = async (file, shouldSave = false, shouldExit = true) => {
|
|
|
958
962
|
${yaml.dump(step)}
|
|
959
963
|
\`\`\``;
|
|
960
964
|
|
|
961
|
-
|
|
962
|
-
|
|
965
|
+
logger.debug(markdown);
|
|
966
|
+
logger.debug("load calling actOnMarkdown");
|
|
963
967
|
|
|
964
968
|
lastPrompt = step.prompt;
|
|
965
969
|
await actOnMarkdown(markdown, 0, true);
|
|
@@ -995,7 +999,7 @@ const setTerminalApp = async (win) => {
|
|
|
995
999
|
const iffy = async (condition, then, otherwise, depth) => {
|
|
996
1000
|
analytics.track("if", { condition });
|
|
997
1001
|
|
|
998
|
-
|
|
1002
|
+
logger.info(generator.jsonToManual({ command: "if", condition }));
|
|
999
1003
|
|
|
1000
1004
|
let response = await commands.assert(condition);
|
|
1001
1005
|
|
|
@@ -1011,11 +1015,11 @@ const iffy = async (condition, then, otherwise, depth) => {
|
|
|
1011
1015
|
const embed = async (file, depth) => {
|
|
1012
1016
|
analytics.track("embed", { file });
|
|
1013
1017
|
|
|
1014
|
-
|
|
1018
|
+
logger.info(generator.jsonToManual({ command: "embed", file }));
|
|
1015
1019
|
|
|
1016
1020
|
depth = depth + 1;
|
|
1017
1021
|
|
|
1018
|
-
|
|
1022
|
+
logger.info(`${file} (start)`);
|
|
1019
1023
|
|
|
1020
1024
|
// get the current wowrking directory where this file is being executed
|
|
1021
1025
|
let cwd = process.cwd();
|
|
@@ -1030,28 +1034,23 @@ const embed = async (file, depth) => {
|
|
|
1030
1034
|
throw `Embedded file not found: ${file}`;
|
|
1031
1035
|
}
|
|
1032
1036
|
|
|
1033
|
-
|
|
1034
|
-
let contents = fs.readFileSync(file, "utf8");
|
|
1037
|
+
let ymlObj = await loadYML(file);
|
|
1035
1038
|
|
|
1036
|
-
|
|
1037
|
-
let steps = yaml.load(contents).steps;
|
|
1038
|
-
// for each step, execute the commands
|
|
1039
|
-
|
|
1040
|
-
for (const step of steps) {
|
|
1039
|
+
for (const step of ymlObj.steps) {
|
|
1041
1040
|
await executeCommands(step.commands, depth);
|
|
1042
1041
|
}
|
|
1043
1042
|
|
|
1044
|
-
|
|
1043
|
+
logger.info(`${file} (end)`);
|
|
1045
1044
|
};
|
|
1046
1045
|
|
|
1047
1046
|
const start = async () => {
|
|
1048
|
-
//
|
|
1047
|
+
// logger.info(await system.getPrimaryDisplay());
|
|
1049
1048
|
|
|
1050
1049
|
// @todo add-auth
|
|
1051
1050
|
// if (!process.env.DASHCAM_API_KEY) {
|
|
1052
|
-
// log
|
|
1053
|
-
// log
|
|
1054
|
-
// log
|
|
1051
|
+
// log('info', chalk.red(`You must supply an API key`), 'system')
|
|
1052
|
+
// log('info', `Supply your API key with the \`DASHCAM_API_KEY\` environment variable.`, 'system');
|
|
1053
|
+
// log('info', 'You can get a key in the Dashcam Discord server: https://discord.com/invite/cWDFW8DzPm', 'system')
|
|
1055
1054
|
// process.exit();
|
|
1056
1055
|
// }
|
|
1057
1056
|
|
|
@@ -1062,13 +1061,11 @@ const start = async () => {
|
|
|
1062
1061
|
process.platform === "darwin" &&
|
|
1063
1062
|
!macScreenPerms.hasScreenCapturePermission()
|
|
1064
1063
|
) {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
"info",
|
|
1064
|
+
logger.info(chalk.red("Screen capture permissions not enabled."));
|
|
1065
|
+
logger.info(
|
|
1068
1066
|
"You must enable screen capture permissions for the application calling `testdriverai`.",
|
|
1069
1067
|
);
|
|
1070
|
-
|
|
1071
|
-
"info",
|
|
1068
|
+
logger.info(
|
|
1072
1069
|
"Read More: https://docs.testdriver.ai/faq/screen-recording-permissions-mac-only",
|
|
1073
1070
|
);
|
|
1074
1071
|
analytics.track("noMacPermissions");
|
|
@@ -1078,14 +1075,14 @@ const start = async () => {
|
|
|
1078
1075
|
if (thisCommand !== "run") {
|
|
1079
1076
|
speak("Howdy! I am TestDriver version " + package.version);
|
|
1080
1077
|
|
|
1081
|
-
|
|
1078
|
+
logger.info(
|
|
1082
1079
|
chalk.red("Warning!") +
|
|
1083
1080
|
chalk.dim(" TestDriver sends screenshots of the desktop to our API."),
|
|
1084
1081
|
);
|
|
1085
|
-
|
|
1082
|
+
logger.info(
|
|
1086
1083
|
chalk.dim("https://docs.testdriver.ai/security-and-privacy/agent"),
|
|
1087
1084
|
);
|
|
1088
|
-
|
|
1085
|
+
logger.info("");
|
|
1089
1086
|
}
|
|
1090
1087
|
|
|
1091
1088
|
analytics.track("command", { command: thisCommand, file: thisFile });
|
|
@@ -1103,14 +1100,14 @@ const start = async () => {
|
|
|
1103
1100
|
|
|
1104
1101
|
process.on("uncaughtException", async (err) => {
|
|
1105
1102
|
analytics.track("uncaughtException", { err });
|
|
1106
|
-
|
|
1103
|
+
logger.error("Uncaught Exception: %s", err);
|
|
1107
1104
|
// You might want to exit the process after handling the error
|
|
1108
1105
|
await exit(true);
|
|
1109
1106
|
});
|
|
1110
1107
|
|
|
1111
1108
|
process.on("unhandledRejection", async (reason, promise) => {
|
|
1112
1109
|
analytics.track("unhandledRejection", { reason, promise });
|
|
1113
|
-
|
|
1110
|
+
logger.error("Unhandled Rejection at: %s, reason: %s", promise, reason);
|
|
1114
1111
|
// Optionally, you might want to exit the process
|
|
1115
1112
|
await exit(true);
|
|
1116
1113
|
});
|
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const config = require("./lib/config.js");
|
|
3
3
|
const system = require("./lib/system.js");
|
|
4
4
|
const { emitter, events } = require("./lib/events.js");
|
|
5
|
+
const { logger } = require("./lib/logger.js");
|
|
5
6
|
|
|
6
7
|
(async () => {
|
|
7
8
|
|
|
@@ -40,7 +41,7 @@ const { emitter, events } = require("./lib/events.js");
|
|
|
40
41
|
agent.start();
|
|
41
42
|
})
|
|
42
43
|
.catch((err) => {
|
|
43
|
-
|
|
44
|
+
logger.error("%s", err);
|
|
44
45
|
process.exit(1);
|
|
45
46
|
});
|
|
46
47
|
}
|