testdriverai 5.4.0 → 5.4.2
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 +64 -42
- package/lib/system.js +11 -2
- package/package.json +1 -1
- package/schema.json +19 -19
- package/testdriver/testdriver_2025-04-17T16-04-30-454Z.yaml +0 -13
package/agent.js
CHANGED
|
@@ -53,6 +53,7 @@ const { emitter, events } = require("./lib/events.js");
|
|
|
53
53
|
|
|
54
54
|
const logger = log.logger;
|
|
55
55
|
|
|
56
|
+
let thisFile;
|
|
56
57
|
let lastPrompt = "";
|
|
57
58
|
let terminalApp = "";
|
|
58
59
|
let commandHistory = [];
|
|
@@ -110,12 +111,6 @@ let getArgs = () => {
|
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
if (!args[file]) {
|
|
113
|
-
// make testdriver directory if it doesn't exist
|
|
114
|
-
let testdriverFolder = path.join(workingDir, "testdriver");
|
|
115
|
-
if (!fs.existsSync(testdriverFolder)) {
|
|
116
|
-
fs.mkdirSync(testdriverFolder);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
114
|
args[file] = "testdriver/testdriver.yaml";
|
|
120
115
|
}
|
|
121
116
|
|
|
@@ -130,21 +125,6 @@ let getArgs = () => {
|
|
|
130
125
|
return { command: args[command], file: args[file] };
|
|
131
126
|
};
|
|
132
127
|
|
|
133
|
-
let a = getArgs();
|
|
134
|
-
|
|
135
|
-
let thisFile = a.file;
|
|
136
|
-
const thisCommand = a.command;
|
|
137
|
-
|
|
138
|
-
logger.info(chalk.green(`Howdy! I'm TestDriver v${package.version}`));
|
|
139
|
-
logger.info(`This is beta software!`);
|
|
140
|
-
logger.info("");
|
|
141
|
-
logger.info(chalk.yellow(`Join our Discord for help`));
|
|
142
|
-
logger.info(`https://discord.com/invite/cWDFW8DzPm`);
|
|
143
|
-
logger.info("");
|
|
144
|
-
|
|
145
|
-
// individual run ID for this session
|
|
146
|
-
// let runID = new Date().getTime();
|
|
147
|
-
|
|
148
128
|
function fileCompleter(line) {
|
|
149
129
|
line = line.slice(5); // remove /run
|
|
150
130
|
const lastSepIndex = line.lastIndexOf(path.sep);
|
|
@@ -407,14 +387,13 @@ const executeCommands = async (
|
|
|
407
387
|
executionHistory[executionHistory.length - 1]?.commands.push(command);
|
|
408
388
|
}
|
|
409
389
|
|
|
410
|
-
if (!dry) {
|
|
411
|
-
await runCommand(command, depth, shouldSave);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
390
|
if (shouldSave) {
|
|
415
391
|
await save({ silent: true });
|
|
416
392
|
}
|
|
417
393
|
|
|
394
|
+
if (!dry) {
|
|
395
|
+
await runCommand(command, depth, shouldSave);
|
|
396
|
+
}
|
|
418
397
|
let timeToComplete = (new Date().getTime() - lastCommand) / 1000;
|
|
419
398
|
// logger.info(timeToComplete, 'seconds')
|
|
420
399
|
|
|
@@ -526,6 +505,10 @@ const loadYML = async (file) => {
|
|
|
526
505
|
process.env["TD_INTERPOLATION_VARS"] || "{}",
|
|
527
506
|
);
|
|
528
507
|
|
|
508
|
+
if (!yml) {
|
|
509
|
+
return {};
|
|
510
|
+
}
|
|
511
|
+
|
|
529
512
|
yml = await parser.validateYAML(yml);
|
|
530
513
|
|
|
531
514
|
// Inject environment variables into any ${VAR} strings
|
|
@@ -781,10 +764,10 @@ const ensureMacScreenPerms = async () => {
|
|
|
781
764
|
|
|
782
765
|
logger.info(chalk.red("Screen capture permissions not enabled."));
|
|
783
766
|
logger.info(
|
|
784
|
-
"You must enable screen capture permissions for
|
|
767
|
+
"You must enable screen capture permissions for this terminal application within System Settings.",
|
|
785
768
|
);
|
|
786
769
|
logger.info(
|
|
787
|
-
"
|
|
770
|
+
"Navigate to System Settings > Privacy & Security > Screen Recording and enable screen recording permissions for the terminal you are using to run this command.",
|
|
788
771
|
);
|
|
789
772
|
analytics.track("noMacPermissions");
|
|
790
773
|
return exit();
|
|
@@ -797,6 +780,7 @@ const ensureMacScreenPerms = async () => {
|
|
|
797
780
|
// simple function to backfill the chat history with a prompt and
|
|
798
781
|
// then call `promptUser()` to get the user input
|
|
799
782
|
const firstPrompt = async () => {
|
|
783
|
+
|
|
800
784
|
// readline is what allows us to get user input
|
|
801
785
|
rl = readline.createInterface({
|
|
802
786
|
terminal: true,
|
|
@@ -807,8 +791,6 @@ const firstPrompt = async () => {
|
|
|
807
791
|
completer,
|
|
808
792
|
});
|
|
809
793
|
|
|
810
|
-
analytics.track("first prompt");
|
|
811
|
-
|
|
812
794
|
rl.on("SIGINT", async () => {
|
|
813
795
|
analytics.track("sigint");
|
|
814
796
|
await exit(false);
|
|
@@ -902,6 +884,7 @@ const firstPrompt = async () => {
|
|
|
902
884
|
}
|
|
903
885
|
|
|
904
886
|
setTerminalWindowTransparency(false);
|
|
887
|
+
|
|
905
888
|
promptUser();
|
|
906
889
|
};
|
|
907
890
|
|
|
@@ -924,18 +907,17 @@ const firstPrompt = async () => {
|
|
|
924
907
|
|
|
925
908
|
let yml = fs.readFileSync(thisFile, "utf-8");
|
|
926
909
|
|
|
927
|
-
|
|
928
|
-
${yml}
|
|
929
|
-
\`\`\``;
|
|
910
|
+
if (yml) {
|
|
930
911
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
912
|
+
let markdown = `\`\`\`yaml
|
|
913
|
+
${yml}\`\`\``;
|
|
914
|
+
|
|
915
|
+
logger.info(`Loaded test script ${thisFile}\n`);
|
|
916
|
+
log.prettyMarkdown(markdown);
|
|
917
|
+
logger.info("New commands will be appended.")
|
|
918
|
+
console.log('')
|
|
936
919
|
|
|
937
|
-
|
|
938
|
-
`);
|
|
920
|
+
}
|
|
939
921
|
}
|
|
940
922
|
|
|
941
923
|
promptUser();
|
|
@@ -1156,7 +1138,7 @@ ${yaml.dump(step)}
|
|
|
1156
1138
|
|
|
1157
1139
|
const promptUser = () => {
|
|
1158
1140
|
emitter.emit(events.interactive, true);
|
|
1159
|
-
rl.prompt(
|
|
1141
|
+
process.nextTick(() => rl.prompt());
|
|
1160
1142
|
};
|
|
1161
1143
|
|
|
1162
1144
|
const setTerminalApp = async (win) => {
|
|
@@ -1235,6 +1217,45 @@ const start = async () => {
|
|
|
1235
1217
|
// process.exit();
|
|
1236
1218
|
// }
|
|
1237
1219
|
|
|
1220
|
+
let a = getArgs();
|
|
1221
|
+
|
|
1222
|
+
// make testdriver directory if it doesn't exist
|
|
1223
|
+
let testdriverFolder = path.join(workingDir, "testdriver");
|
|
1224
|
+
if (!fs.existsSync(testdriverFolder)) {
|
|
1225
|
+
|
|
1226
|
+
console.log('does not exist')
|
|
1227
|
+
|
|
1228
|
+
fs.mkdirSync(testdriverFolder);
|
|
1229
|
+
// log
|
|
1230
|
+
logger.info(chalk.dim(`Created testdriver directory`));
|
|
1231
|
+
console.log(
|
|
1232
|
+
chalk.dim(`Created testdriver directory: ${testdriverFolder}`),
|
|
1233
|
+
);
|
|
1234
|
+
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// if testdriver.yaml doesn't exist, make it
|
|
1238
|
+
let testdriverFile = path.join(testdriverFolder, "testdriver.yaml");
|
|
1239
|
+
if (!fs.existsSync(testdriverFile)) {
|
|
1240
|
+
fs.writeFileSync(testdriverFile, "");
|
|
1241
|
+
logger.info(chalk.dim(`Created testdriver.yaml`));
|
|
1242
|
+
console.log(chalk.dim(`Created testdriver.yaml: ${testdriverFile}`));
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
thisFile = a.file;
|
|
1246
|
+
const thisCommand = a.command;
|
|
1247
|
+
|
|
1248
|
+
logger.info(chalk.green(`Howdy! I'm TestDriver v${package.version}`));
|
|
1249
|
+
logger.info(`This is beta software!`);
|
|
1250
|
+
logger.info("");
|
|
1251
|
+
logger.info(chalk.yellow(`Join our Discord for help`));
|
|
1252
|
+
logger.info(`https://discord.com/invite/cWDFW8DzPm`);
|
|
1253
|
+
logger.info("");
|
|
1254
|
+
|
|
1255
|
+
// individual run ID for this session
|
|
1256
|
+
// let runID = new Date().getTime();
|
|
1257
|
+
|
|
1258
|
+
|
|
1238
1259
|
// await sdk.auth();
|
|
1239
1260
|
if (thisCommand !== "run") {
|
|
1240
1261
|
speak("Howdy! I am TestDriver version " + package.version);
|
|
@@ -1242,6 +1263,7 @@ const start = async () => {
|
|
|
1242
1263
|
|
|
1243
1264
|
if (thisCommand !== "init" && thisCommand !== "upload-secrets") {
|
|
1244
1265
|
logger.info(chalk.dim(`Working on ${thisFile}`));
|
|
1266
|
+
console.log("");
|
|
1245
1267
|
|
|
1246
1268
|
loadYML(thisFile)
|
|
1247
1269
|
|
|
@@ -1249,11 +1271,11 @@ const start = async () => {
|
|
|
1249
1271
|
logger.info(
|
|
1250
1272
|
chalk.red("Warning! ") +
|
|
1251
1273
|
chalk.dim(
|
|
1252
|
-
"Local mode sends screenshots of the desktop to our API. Set `TD_VM
|
|
1274
|
+
"Local mode sends screenshots of the desktop to our API. Set `TD_VM` to run in a secure VM.",
|
|
1253
1275
|
),
|
|
1254
1276
|
);
|
|
1255
1277
|
logger.info(
|
|
1256
|
-
chalk.dim("https://docs.testdriver.ai/security-and-privacy/agent"),
|
|
1278
|
+
chalk.dim("Read More: https://docs.testdriver.ai/security-and-privacy/agent"),
|
|
1257
1279
|
);
|
|
1258
1280
|
logger.info("");
|
|
1259
1281
|
}
|
package/lib/system.js
CHANGED
|
@@ -162,7 +162,9 @@ const initializeActiveWindow = async () => {
|
|
|
162
162
|
// For some reason, the import fails in certain situations
|
|
163
163
|
const activeWindow = await import("get-windows")
|
|
164
164
|
.then(({ activeWindow }) => activeWindow)
|
|
165
|
-
.catch(() =>
|
|
165
|
+
.catch(() => {
|
|
166
|
+
return null;
|
|
167
|
+
});
|
|
166
168
|
activeWindowFn = activeWindow;
|
|
167
169
|
}
|
|
168
170
|
return activeWindowFn;
|
|
@@ -174,7 +176,14 @@ const activeWin = async () => {
|
|
|
174
176
|
return "error getting active window, proceed normally";
|
|
175
177
|
} else {
|
|
176
178
|
const activeWindow = await initializeActiveWindow();
|
|
177
|
-
|
|
179
|
+
let windows;
|
|
180
|
+
try {
|
|
181
|
+
windows = await activeWindow?.();
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.error("Error getting active window", e);
|
|
184
|
+
return "error getting active window, proceed normally";
|
|
185
|
+
}
|
|
186
|
+
return windows;
|
|
178
187
|
}
|
|
179
188
|
};
|
|
180
189
|
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -70,26 +70,26 @@
|
|
|
70
70
|
"keys": {
|
|
71
71
|
"type": "array",
|
|
72
72
|
"items": {
|
|
73
|
-
"type": "string"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
"type": "string",
|
|
74
|
+
"enum": [
|
|
75
|
+
[
|
|
76
|
+
"backspace", "delete", "enter", "tab", "escape", "up", "down", "right", "left",
|
|
77
|
+
"home", "end", "pageup", "pagedown", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
|
78
|
+
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19",
|
|
79
|
+
"f20", "f21", "f22", "f23", "f24", "capslock", "command", "alt", "right_alt",
|
|
80
|
+
"control", "left_control", "right_control", "shift", "right_shift", "space",
|
|
81
|
+
"printscreen", "insert", "menu", "audio_mute", "audio_vol_down", "audio_vol_up",
|
|
82
|
+
"audio_play", "audio_stop", "audio_pause", "audio_prev", "audio_next",
|
|
83
|
+
"audio_rewind", "audio_forward", "audio_repeat", "audio_random", "numpad_lock",
|
|
84
|
+
"numpad_0", "numpad_1", "numpad_2", "numpad_3", "numpad_4", "numpad_5",
|
|
85
|
+
"numpad_6", "numpad_7", "numpad_8", "numpad_9", "numpad_+", "numpad_-",
|
|
86
|
+
"numpad_*", "numpad_/", "numpad_.", "lights_mon_up", "lights_mon_down",
|
|
87
|
+
"lights_kbd_toggle", "lights_kbd_up", "lights_kbd_down", "a", "b", "c", "d", "e",
|
|
88
|
+
"f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
|
|
89
|
+
"v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
|
|
90
|
+
]
|
|
91
91
|
]
|
|
92
|
-
|
|
92
|
+
}
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
95
|
"required": [
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
version: 5.1.1
|
|
2
|
-
session: 67f00511acbd9ccac373edf7
|
|
3
|
-
steps:
|
|
4
|
-
- prompt: launch chrome
|
|
5
|
-
commands:
|
|
6
|
-
- command: exec
|
|
7
|
-
lang: shell
|
|
8
|
-
linux: |
|
|
9
|
-
jumpapp google-chrome --disable-fre --no-default-browser-check --no-first-run "${TD_WEBSITE}" &
|
|
10
|
-
exit
|
|
11
|
-
- command: wait-for-text
|
|
12
|
-
text: "Google Chrome"
|
|
13
|
-
timeout: 30000
|