testdriverai 5.7.43 → 5.7.44
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 +44 -44
- package/index.js +0 -2
- package/lib/commander.js +199 -203
- package/lib/commands.js +63 -35
- package/lib/config.js +1 -3
- package/lib/events.js +1 -1
- package/lib/focus-application.js +14 -8
- package/lib/generator.js +3 -4
- package/lib/init.js +10 -10
- package/lib/logger.js +226 -5
- package/lib/network.js +0 -3
- package/lib/outputs.js +1 -1
- package/lib/parser.js +22 -23
- package/lib/redraw.js +47 -27
- package/lib/resources/prerun.yaml +2 -2
- package/lib/sandbox.js +20 -20
- package/lib/sdk.js +4 -4
- package/lib/session.js +0 -2
- package/lib/system.js +1 -1
- package/lib/theme.js +13 -0
- package/lib/upload-secrets.js +1 -1
- package/package.json +1 -1
- package/testdriver/type-repeated.yaml +21 -0
package/agent.js
CHANGED
|
@@ -25,7 +25,6 @@ const http = require("http");
|
|
|
25
25
|
|
|
26
26
|
// third party modules
|
|
27
27
|
const path = require("path");
|
|
28
|
-
const chalk = require("chalk");
|
|
29
28
|
const yaml = require("js-yaml");
|
|
30
29
|
const sanitizeFilename = require("sanitize-filename");
|
|
31
30
|
|
|
@@ -44,6 +43,7 @@ const init = require("./lib/init.js");
|
|
|
44
43
|
const config = require("./lib/config.js");
|
|
45
44
|
const sandbox = require("./lib/sandbox.js");
|
|
46
45
|
const uploadSecrets = require("./lib/upload-secrets.js");
|
|
46
|
+
const theme = require("./lib/theme.js");
|
|
47
47
|
|
|
48
48
|
const { showTerminal, hideTerminal } = require("./lib/focus-application.js");
|
|
49
49
|
const isValidVersion = require("./lib/valid-version.js");
|
|
@@ -210,7 +210,7 @@ const exit = async (failed = true, shouldSave = false) => {
|
|
|
210
210
|
};
|
|
211
211
|
|
|
212
212
|
const dieOnFatal = async (error) => {
|
|
213
|
-
logger.error(
|
|
213
|
+
logger.error(theme.red("Fatal Error") + `\n${error.message}`);
|
|
214
214
|
await summarize(error.message);
|
|
215
215
|
return await exit(true);
|
|
216
216
|
};
|
|
@@ -234,7 +234,7 @@ const haveAIResolveError = async (
|
|
|
234
234
|
let safeKey = JSON.stringify(eMessage);
|
|
235
235
|
errorCounts[safeKey] = errorCounts[safeKey] ? errorCounts[safeKey] + 1 : 1;
|
|
236
236
|
|
|
237
|
-
logger.error(
|
|
237
|
+
logger.error(theme.red("Error detected"));
|
|
238
238
|
|
|
239
239
|
log.prettyMarkdown(eMessage);
|
|
240
240
|
|
|
@@ -243,7 +243,7 @@ const haveAIResolveError = async (
|
|
|
243
243
|
|
|
244
244
|
// if we get the same error 3 times in `run` mode, we exit
|
|
245
245
|
if (errorCounts[safeKey] > errorLimit - 1) {
|
|
246
|
-
logger.info(
|
|
246
|
+
logger.info(theme.red("Error loop detected. Exiting."));
|
|
247
247
|
logger.info("%s", eMessage);
|
|
248
248
|
await summarize(eMessage);
|
|
249
249
|
return await exit(true);
|
|
@@ -263,7 +263,7 @@ const haveAIResolveError = async (
|
|
|
263
263
|
speak("thinking...");
|
|
264
264
|
notify("thinking...");
|
|
265
265
|
server.broadcast("status", `thinking...`);
|
|
266
|
-
logger.info(
|
|
266
|
+
logger.info(theme.dim("thinking..."), true);
|
|
267
267
|
logger.info("");
|
|
268
268
|
|
|
269
269
|
const mdStream = log.createMarkdownStreamLogger();
|
|
@@ -295,13 +295,13 @@ const check = async () => {
|
|
|
295
295
|
checkCount++;
|
|
296
296
|
|
|
297
297
|
if (checkCount >= checkLimit) {
|
|
298
|
-
logger.info(
|
|
298
|
+
logger.info(theme.red("Exploratory loop detected. Exiting."));
|
|
299
299
|
await summarize("Check loop detected.");
|
|
300
300
|
return await exit(true);
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
logger.info("");
|
|
304
|
-
logger.info(
|
|
304
|
+
logger.info(theme.dim("checking..."), "testdriver");
|
|
305
305
|
server.broadcast("status", `checking...`);
|
|
306
306
|
logger.info("");
|
|
307
307
|
|
|
@@ -470,14 +470,14 @@ const aiExecute = async (
|
|
|
470
470
|
if (checkCodeblocks.length > 0) {
|
|
471
471
|
logger.debug("check thinks more needs to be done");
|
|
472
472
|
|
|
473
|
-
logger.info(
|
|
473
|
+
logger.info(theme.dim("not done yet!"), "testdriver");
|
|
474
474
|
logger.info("");
|
|
475
475
|
|
|
476
476
|
return await aiExecute(response, validateAndLoop);
|
|
477
477
|
} else {
|
|
478
478
|
logger.debug("seems complete, returning");
|
|
479
479
|
|
|
480
|
-
logger.info(
|
|
480
|
+
logger.info(theme.green("success!"), "testdriver");
|
|
481
481
|
logger.info("");
|
|
482
482
|
|
|
483
483
|
return response;
|
|
@@ -547,7 +547,7 @@ const assert = async (expect) => {
|
|
|
547
547
|
speak("thinking...");
|
|
548
548
|
notify("thinking...");
|
|
549
549
|
server.broadcast("status", `thinking...`);
|
|
550
|
-
logger.info(
|
|
550
|
+
logger.info(theme.dim("thinking..."), true);
|
|
551
551
|
logger.info("");
|
|
552
552
|
|
|
553
553
|
let response = `\`\`\`yaml
|
|
@@ -579,7 +579,7 @@ const exploratoryLoop = async (
|
|
|
579
579
|
speak("thinking...");
|
|
580
580
|
notify("thinking...");
|
|
581
581
|
server.broadcast("status", `thinking...`);
|
|
582
|
-
logger.info(
|
|
582
|
+
logger.info(theme.dim("thinking..."), true);
|
|
583
583
|
logger.info("");
|
|
584
584
|
|
|
585
585
|
lastScreenshot = await system.captureScreenBase64();
|
|
@@ -615,7 +615,7 @@ const generate = async (type, count, baseYaml, skipYaml = false) => {
|
|
|
615
615
|
speak("thinking...");
|
|
616
616
|
notify("thinking...");
|
|
617
617
|
server.broadcast("status", `thinking...`);
|
|
618
|
-
logger.info(
|
|
618
|
+
logger.info(theme.dim("thinking..."), true);
|
|
619
619
|
logger.info("");
|
|
620
620
|
|
|
621
621
|
if (baseYaml && !skipYaml) {
|
|
@@ -681,7 +681,7 @@ const generate = async (type, count, baseYaml, skipYaml = false) => {
|
|
|
681
681
|
};
|
|
682
682
|
|
|
683
683
|
const popFromHistory = async (fullStep) => {
|
|
684
|
-
logger.info(
|
|
684
|
+
logger.info(theme.dim("undoing..."), true);
|
|
685
685
|
|
|
686
686
|
if (executionHistory.length) {
|
|
687
687
|
if (fullStep) {
|
|
@@ -756,7 +756,7 @@ const ensureMacScreenPerms = async () => {
|
|
|
756
756
|
if (!config.TD_OVERLAY_ID && !config.TD_VM && process.platform === "darwin") {
|
|
757
757
|
const macScreenPerms = require("mac-screen-capture-permissions");
|
|
758
758
|
if (!macScreenPerms.hasScreenCapturePermission()) {
|
|
759
|
-
logger.info(
|
|
759
|
+
logger.info(theme.red("Screen capture permissions not enabled."));
|
|
760
760
|
logger.info(
|
|
761
761
|
"You must enable screen capture permissions for this terminal application within System Settings.",
|
|
762
762
|
);
|
|
@@ -963,12 +963,12 @@ let summarize = async (error = null) => {
|
|
|
963
963
|
|
|
964
964
|
logger.info("");
|
|
965
965
|
|
|
966
|
-
logger.info(
|
|
966
|
+
logger.info(theme.dim("reviewing test..."), true);
|
|
967
967
|
|
|
968
968
|
// let text = prompts.summarize(tasks, error);
|
|
969
969
|
let image = await system.captureScreenBase64();
|
|
970
970
|
|
|
971
|
-
logger.info(
|
|
971
|
+
logger.info(theme.dim("summarizing..."), true);
|
|
972
972
|
|
|
973
973
|
const mdStream = log.createMarkdownStreamLogger();
|
|
974
974
|
let reply = await sdk.req(
|
|
@@ -1020,7 +1020,7 @@ ${regression}
|
|
|
1020
1020
|
\`\`\``);
|
|
1021
1021
|
|
|
1022
1022
|
if (!silent) {
|
|
1023
|
-
logger.info(
|
|
1023
|
+
logger.info(theme.dim(`saved as ${filepath}`));
|
|
1024
1024
|
}
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
@@ -1068,7 +1068,7 @@ let run = async (
|
|
|
1068
1068
|
setTerminalWindowTransparency(true);
|
|
1069
1069
|
emitter.emit(events.interactive, false);
|
|
1070
1070
|
|
|
1071
|
-
logger.info(
|
|
1071
|
+
logger.info(theme.cyan(`running ${file}...`));
|
|
1072
1072
|
|
|
1073
1073
|
let ymlObj = await loadYML(file);
|
|
1074
1074
|
|
|
@@ -1076,10 +1076,10 @@ let run = async (
|
|
|
1076
1076
|
let valid = isValidVersion(ymlObj.version);
|
|
1077
1077
|
if (!valid) {
|
|
1078
1078
|
console.log("");
|
|
1079
|
-
logger.warn(
|
|
1080
|
-
logger.warn(
|
|
1079
|
+
logger.warn(theme.red(`Version mismatch detected!`));
|
|
1080
|
+
logger.warn(theme.red(`Running a test created with v${ymlObj.version}.`));
|
|
1081
1081
|
logger.warn(
|
|
1082
|
-
|
|
1082
|
+
theme.red(`The current testdriverai version is v${package.version}.`),
|
|
1083
1083
|
);
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
@@ -1088,7 +1088,7 @@ let run = async (
|
|
|
1088
1088
|
|
|
1089
1089
|
for (const step of ymlObj.steps) {
|
|
1090
1090
|
logger.info(``, null);
|
|
1091
|
-
logger.info(
|
|
1091
|
+
logger.info(theme.yellow(`> ${step.prompt || "no prompt"}`), null);
|
|
1092
1092
|
|
|
1093
1093
|
if (pushToHistory) {
|
|
1094
1094
|
executionHistory.push({
|
|
@@ -1098,10 +1098,10 @@ let run = async (
|
|
|
1098
1098
|
}
|
|
1099
1099
|
|
|
1100
1100
|
if (!step.commands && !step.prompt) {
|
|
1101
|
-
logger.info(
|
|
1101
|
+
logger.info(theme.red("No commands or prompt found"));
|
|
1102
1102
|
await exit(true);
|
|
1103
1103
|
} else if (!step.commands) {
|
|
1104
|
-
logger.info(
|
|
1104
|
+
logger.info(theme.yellow("No commands found, running exploratory"));
|
|
1105
1105
|
await exploratoryLoop(step.prompt, false, true, false);
|
|
1106
1106
|
} else {
|
|
1107
1107
|
let markdown = `\`\`\`yaml
|
|
@@ -1208,10 +1208,10 @@ const start = async () => {
|
|
|
1208
1208
|
thisFile = a.file;
|
|
1209
1209
|
const thisCommand = a.command;
|
|
1210
1210
|
|
|
1211
|
-
logger.info(
|
|
1211
|
+
logger.info(theme.green(`Howdy! I'm TestDriver v${package.version}`));
|
|
1212
1212
|
logger.info(`This is beta software!`);
|
|
1213
1213
|
logger.info("");
|
|
1214
|
-
logger.info(
|
|
1214
|
+
logger.info(theme.yellow(`Join our Discord for help`));
|
|
1215
1215
|
logger.info(`https://discord.com/invite/cWDFW8DzPm`);
|
|
1216
1216
|
logger.info("");
|
|
1217
1217
|
|
|
@@ -1220,21 +1220,21 @@ const start = async () => {
|
|
|
1220
1220
|
if (!fs.existsSync(testdriverFolder)) {
|
|
1221
1221
|
fs.mkdirSync(testdriverFolder);
|
|
1222
1222
|
// log
|
|
1223
|
-
logger.info(
|
|
1224
|
-
console.log(
|
|
1223
|
+
logger.info(theme.dim(`Created testdriver directory`));
|
|
1224
|
+
console.log(theme.dim(`Created testdriver directory: ${testdriverFolder}`));
|
|
1225
1225
|
}
|
|
1226
1226
|
|
|
1227
1227
|
// if the directory for thisFile doesn't exist, create it
|
|
1228
1228
|
const dir = path.dirname(thisFile);
|
|
1229
1229
|
if (!fs.existsSync(dir)) {
|
|
1230
1230
|
fs.mkdirSync(dir, { recursive: true });
|
|
1231
|
-
logger.info(
|
|
1231
|
+
logger.info(theme.dim(`Created directory ${dir}`));
|
|
1232
1232
|
}
|
|
1233
1233
|
|
|
1234
1234
|
// if thisFile doesn't exist, create it
|
|
1235
1235
|
if (!fs.existsSync(thisFile)) {
|
|
1236
1236
|
fs.writeFileSync(thisFile, "");
|
|
1237
|
-
logger.info(
|
|
1237
|
+
logger.info(theme.dim(`Created ${thisFile}`));
|
|
1238
1238
|
}
|
|
1239
1239
|
|
|
1240
1240
|
if (config.TD_API_KEY) {
|
|
@@ -1246,20 +1246,20 @@ const start = async () => {
|
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
1248
|
if (thisCommand !== "init" && thisCommand !== "upload-secrets") {
|
|
1249
|
-
logger.info(
|
|
1249
|
+
logger.info(theme.dim(`Working on ${thisFile}`));
|
|
1250
1250
|
console.log("");
|
|
1251
1251
|
|
|
1252
1252
|
loadYML(thisFile);
|
|
1253
1253
|
|
|
1254
1254
|
if (!config.TD_VM) {
|
|
1255
1255
|
logger.info(
|
|
1256
|
-
|
|
1257
|
-
|
|
1256
|
+
theme.red("Warning! ") +
|
|
1257
|
+
theme.dim(
|
|
1258
1258
|
"Local mode sends screenshots of the desktop to our API. Set `TD_VM` to run in a secure VM.",
|
|
1259
1259
|
),
|
|
1260
1260
|
);
|
|
1261
1261
|
logger.info(
|
|
1262
|
-
|
|
1262
|
+
theme.dim("Read More: https://docs.testdriver.ai/security/agent"),
|
|
1263
1263
|
);
|
|
1264
1264
|
logger.info("");
|
|
1265
1265
|
}
|
|
@@ -1285,39 +1285,39 @@ const start = async () => {
|
|
|
1285
1285
|
const makeSandbox = async () => {
|
|
1286
1286
|
if (config.TD_VM) {
|
|
1287
1287
|
try {
|
|
1288
|
-
logger.info(
|
|
1288
|
+
logger.info(theme.gray(`- creating sandbox...`));
|
|
1289
1289
|
server.broadcast("status", `Creating new sandbox...`);
|
|
1290
1290
|
await sandbox.boot();
|
|
1291
|
-
logger.info(
|
|
1291
|
+
logger.info(theme.gray(`- authenticating...`));
|
|
1292
1292
|
server.broadcast("status", `Authenticating...`);
|
|
1293
1293
|
await sandbox.send({
|
|
1294
1294
|
type: "authenticate",
|
|
1295
1295
|
apiKey: config.TD_API_KEY,
|
|
1296
1296
|
secret: config.TD_SECRET,
|
|
1297
1297
|
});
|
|
1298
|
-
logger.info(
|
|
1298
|
+
logger.info(theme.gray(`- configuring...`));
|
|
1299
1299
|
server.broadcast("status", `Configuring...`);
|
|
1300
1300
|
await sandbox.send({
|
|
1301
1301
|
type: "create",
|
|
1302
1302
|
resolution: config.TD_VM_RESOLUTION,
|
|
1303
1303
|
});
|
|
1304
|
-
logger.info(
|
|
1304
|
+
logger.info(theme.gray(`- starting stream...`));
|
|
1305
1305
|
server.broadcast("status", `Starting stream...`);
|
|
1306
1306
|
await sandbox.send({ type: "stream.start" });
|
|
1307
1307
|
let { url } = await sandbox.send({ type: "stream.getUrl" });
|
|
1308
|
-
logger.info(
|
|
1308
|
+
logger.info(theme.gray(`- rendering...`));
|
|
1309
1309
|
server.broadcast("status", `Rendering...`);
|
|
1310
1310
|
await sandbox.send({ type: "ready" });
|
|
1311
1311
|
emitter.emit(events.vm.show, { url });
|
|
1312
|
-
logger.info(
|
|
1312
|
+
logger.info(theme.gray(`- booting...`));
|
|
1313
1313
|
server.broadcast("status", `Starting...`);
|
|
1314
1314
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
1315
|
-
logger.info(
|
|
1316
|
-
logger.info(
|
|
1317
|
-
logger.info(
|
|
1315
|
+
logger.info(theme.green(``));
|
|
1316
|
+
logger.info(theme.green(`sandbox runner ready!`));
|
|
1317
|
+
logger.info(theme.green(``));
|
|
1318
1318
|
} catch (e) {
|
|
1319
1319
|
logger.error(e);
|
|
1320
|
-
logger.error(
|
|
1320
|
+
logger.error(theme.red(`sandbox runner failed to start`));
|
|
1321
1321
|
process.exit(1);
|
|
1322
1322
|
}
|
|
1323
1323
|
}
|
package/index.js
CHANGED
|
@@ -12,7 +12,6 @@ if (process.argv[2] === "--help" || process.argv[2] === "-h") {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
if (process.argv[2] === "--renderer") {
|
|
15
|
-
|
|
16
15
|
const {
|
|
17
16
|
// connectToOverlay,
|
|
18
17
|
createOverlayProcess,
|
|
@@ -41,7 +40,6 @@ if (process.argv[2] === "--renderer") {
|
|
|
41
40
|
})();
|
|
42
41
|
} else {
|
|
43
42
|
(async () => {
|
|
44
|
-
|
|
45
43
|
if (!config.TD_OVERLAY) {
|
|
46
44
|
let agent = require("./agent.js");
|
|
47
45
|
await agent.start();
|