testdriverai 6.1.10 → 6.2.0

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.
Files changed (67) hide show
  1. package/.github/workflows/acceptance-tests.yml +0 -2
  2. package/.github/workflows/acceptance-v6.yml +0 -2
  3. package/.github/workflows/lint.yml +1 -4
  4. package/.github/workflows/publish-canary.yml +0 -2
  5. package/.github/workflows/publish-latest.yml +0 -1
  6. package/.prettierignore +0 -1
  7. package/.vscode/settings.json +1 -4
  8. package/agent/events.js +10 -1
  9. package/agent/index.js +76 -104
  10. package/agent/interface.js +6 -43
  11. package/agent/lib/censorship.js +10 -15
  12. package/agent/lib/commander.js +18 -31
  13. package/agent/lib/commands.js +63 -81
  14. package/agent/lib/debugger-server.js +5 -0
  15. package/agent/lib/generator.js +2 -2
  16. package/agent/lib/redraw.js +1 -0
  17. package/agent/lib/sandbox.js +2 -0
  18. package/agent/lib/sdk.js +1 -2
  19. package/agent/lib/source-mapper.js +1 -1
  20. package/agent/lib/system.js +6 -1
  21. package/docs/account/enterprise.mdx +12 -8
  22. package/docs/account/pricing.mdx +2 -2
  23. package/docs/account/projects.mdx +0 -5
  24. package/docs/cli/overview.mdx +6 -6
  25. package/docs/commands/assert.mdx +0 -1
  26. package/docs/commands/hover-text.mdx +1 -3
  27. package/docs/commands/match-image.mdx +4 -5
  28. package/docs/commands/press-keys.mdx +8 -6
  29. package/docs/commands/scroll-until-image.mdx +7 -8
  30. package/docs/commands/scroll-until-text.mdx +6 -7
  31. package/docs/commands/wait-for-image.mdx +4 -5
  32. package/docs/commands/wait-for-text.mdx +5 -6
  33. package/docs/docs.json +40 -42
  34. package/docs/getting-started/vscode.mdx +56 -67
  35. package/docs/guide/environment-variables.mdx +5 -5
  36. package/docs/overview/comparison.mdx +39 -22
  37. package/docs/overview/quickstart.mdx +32 -84
  38. package/docs/styles.css +1 -10
  39. package/interfaces/cli/lib/base.js +6 -27
  40. package/interfaces/cli/utils/factory.js +4 -17
  41. package/interfaces/logger.js +5 -4
  42. package/interfaces/readline.js +1 -1
  43. package/package.json +3 -3
  44. package/schema.json +2 -22
  45. package/testdriver/acceptance/hover-text.yaml +1 -2
  46. package/testdriver/acceptance/prompt.yaml +1 -4
  47. package/testdriver/acceptance/scroll-until-image.yaml +0 -5
  48. package/testdriver/{lifecycle/prerun.yaml → examples/web/lifecycle/provision.yaml} +0 -6
  49. package/testdriver/lifecycle/provision.yaml +20 -0
  50. package/.github/workflows/self-hosted.yml +0 -102
  51. package/docs/apps/tauri-apps.mdx +0 -361
  52. package/docs/getting-started/playwright.mdx +0 -342
  53. package/docs/getting-started/self-hosting.mdx +0 -370
  54. package/docs/guide/dashcam.mdx +0 -118
  55. package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
  56. package/docs/images/content/vscode/ide-full.png +0 -0
  57. package/docs/images/content/vscode/running.png +0 -0
  58. package/interfaces/cli/commands/generate.js +0 -3
  59. package/setup/aws/cloudformation.yaml +0 -463
  60. package/setup/aws/spawn-runner.sh +0 -190
  61. package/testdriver/edge-cases/js-exception.yaml +0 -8
  62. package/testdriver/edge-cases/js-promise.yaml +0 -19
  63. package/testdriver/edge-cases/lifecycle/postrun.yaml +0 -10
  64. package/testdriver/edge-cases/success-test.yaml +0 -9
  65. package/testdriver/examples/web/lifecycle/postrun.yaml +0 -7
  66. package/testdriver/examples/web/lifecycle/prerun.yaml +0 -17
  67. package/testdriver/lifecycle/postrun.yaml +0 -7
@@ -80,21 +80,21 @@ commands:
80
80
  // this will actually interpret the command and execute it
81
81
  switch (object.command) {
82
82
  case "type":
83
- emitter.emit(events.log.log, generator.jsonToManual(object));
84
83
  emitter.emit(events.log.narration, `typing ${object.text}`);
84
+ emitter.emit(events.log.log, generator.jsonToManual(object));
85
85
  response = await commands.type(object.text, object.delay);
86
86
  break;
87
87
  case "press-keys":
88
- emitter.emit(events.log.log, generator.jsonToManual(object));
89
88
  emitter.emit(
90
89
  events.log.narration,
91
- `pressing keys: ${Array.isArray(object.keys) ? object.keys.join(", ") : object.keys}`,
90
+ `pressing keys ${object.keys.join(",")}`,
92
91
  );
92
+ emitter.emit(events.log.log, generator.jsonToManual(object));
93
93
  response = await commands["press-keys"](object.keys);
94
94
  break;
95
95
  case "scroll":
96
- emitter.emit(events.log.log, generator.jsonToManual(object));
97
96
  emitter.emit(events.log.narration, `scrolling ${object.direction}`);
97
+ emitter.emit(events.log.log, generator.jsonToManual(object));
98
98
  response = await commands.scroll(
99
99
  object.direction,
100
100
  object.amount,
@@ -102,21 +102,21 @@ commands:
102
102
  );
103
103
  break;
104
104
  case "wait":
105
- emitter.emit(events.log.log, generator.jsonToManual(object));
106
105
  emitter.emit(
107
106
  events.log.narration,
108
107
  `waiting ${object.timeout} seconds`,
109
108
  );
109
+ emitter.emit(events.log.log, generator.jsonToManual(object));
110
110
  response = await commands.wait(object.timeout);
111
111
  break;
112
112
  case "click":
113
- emitter.emit(events.log.log, generator.jsonToManual(object));
114
113
  emitter.emit(events.log.narration, `${object.action}`);
114
+ emitter.emit(events.log.log, generator.jsonToManual(object));
115
115
  response = await commands["click"](object.x, object.y, object.action);
116
116
  break;
117
117
  case "hover":
118
- emitter.emit(events.log.log, generator.jsonToManual(object));
119
118
  emitter.emit(events.log.narration, `moving mouse`);
119
+ emitter.emit(events.log.log, generator.jsonToManual(object));
120
120
  response = await commands["hover"](object.x, object.y);
121
121
  break;
122
122
  case "drag":
@@ -124,25 +124,24 @@ commands:
124
124
  response = await commands["drag"](object.x, object.y);
125
125
  break;
126
126
  case "hover-text":
127
- emitter.emit(events.log.log, generator.jsonToManual(object));
128
127
  emitter.emit(
129
128
  events.log.narration,
130
129
  `searching for ${object.description}`,
131
130
  );
131
+ emitter.emit(events.log.log, generator.jsonToManual(object));
132
132
  response = await commands["hover-text"](
133
133
  object.text,
134
134
  object.description,
135
135
  object.action,
136
136
  object.method,
137
- object.timeout,
138
137
  );
139
138
  break;
140
139
  case "hover-image":
141
- emitter.emit(events.log.log, generator.jsonToManual(object));
142
140
  emitter.emit(
143
141
  events.log.narration,
144
142
  `searching for image of ${object.description}`,
145
143
  );
144
+ emitter.emit(events.log.log, generator.jsonToManual(object));
146
145
  response = await commands["hover-image"](
147
146
  object.description,
148
147
  object.action,
@@ -154,38 +153,32 @@ commands:
154
153
  events.log.narration,
155
154
  `${object.action} image ${object.path}`,
156
155
  );
157
- response = await commands["match-image"](
158
- object.path,
159
- object.action,
160
- object.invert,
161
- );
156
+ response = await commands["match-image"](object.path, object.action);
162
157
  break;
163
158
  case "wait-for-image":
164
- emitter.emit(events.log.log, generator.jsonToManual(object));
165
159
  emitter.emit(
166
160
  events.log.narration,
167
161
  `waiting for ${object.description}`,
168
162
  );
163
+ emitter.emit(events.log.log, generator.jsonToManual(object));
169
164
  response = await commands["wait-for-image"](
170
165
  object.description,
171
166
  object.timeout,
172
- object.invert,
173
167
  );
174
168
  break;
175
169
  case "wait-for-text":
176
- emitter.emit(events.log.log, generator.jsonToManual(object));
177
170
  emitter.emit(events.log.narration, `waiting for ${object.text}`);
171
+ emitter.emit(events.log.log, generator.jsonToManual(object));
178
172
  copy.text = "*****";
179
173
  response = await commands["wait-for-text"](
180
174
  object.text,
181
175
  object.timeout,
182
176
  object.method,
183
- object.invert,
184
177
  );
185
178
  break;
186
179
  case "scroll-until-text":
187
- emitter.emit(events.log.log, generator.jsonToManual(object));
188
180
  emitter.emit(events.log.narration, `scrolling until ${object.text}`);
181
+ emitter.emit(events.log.log, generator.jsonToManual(object));
189
182
  copy.text = "*****";
190
183
  response = await commands["scroll-until-text"](
191
184
  object.text,
@@ -193,26 +186,24 @@ commands:
193
186
  object.distance,
194
187
  object.textMatchMethod,
195
188
  object.method,
196
- object.invert,
197
189
  );
198
190
  break;
199
191
  case "scroll-until-image": {
200
192
  const needle = object.description || object.path;
201
- emitter.emit(events.log.log, generator.jsonToManual(object));
202
193
  emitter.emit(events.log.narration, `scrolling until ${needle}`);
194
+ emitter.emit(events.log.log, generator.jsonToManual(object));
203
195
  response = await commands["scroll-until-image"](
204
196
  object.description,
205
197
  object.direction,
206
198
  object.distance,
207
199
  object.method,
208
200
  object.path,
209
- object.invert,
210
201
  );
211
202
  break;
212
203
  }
213
204
  case "focus-application":
214
- emitter.emit(events.log.log, generator.jsonToManual(object));
215
205
  emitter.emit(events.log.narration, `focusing ${object.name}`);
206
+ emitter.emit(events.log.log, generator.jsonToManual(object));
216
207
  response = await commands["focus-application"](object.name);
217
208
  break;
218
209
  case "remember": {
@@ -223,16 +214,12 @@ commands:
223
214
  break;
224
215
  }
225
216
  case "assert":
226
- emitter.emit(events.log.log, generator.jsonToManual(object));
227
217
  emitter.emit(events.log.narration, `asserting ${object.expect}`);
228
- response = await commands.assert(
229
- object.expect,
230
- object.async,
231
- object.invert,
232
- );
233
-
218
+ emitter.emit(events.log.log, generator.jsonToManual(object));
219
+ response = await commands.assert(object.expect, object.async);
234
220
  break;
235
221
  case "exec":
222
+ emitter.emit(events.log.narration, `exec`);
236
223
  emitter.emit(
237
224
  events.log.log,
238
225
  generator.jsonToManual({
@@ -170,34 +170,20 @@ const createCommands = (
170
170
  return result;
171
171
  };
172
172
 
173
- const assert = async (
174
- assertion,
175
- shouldThrow = false,
176
- async = false,
177
- invert = false,
178
- ) => {
173
+ const assert = async (assertion, shouldThrow = false, async = false) => {
179
174
  if (async) {
180
175
  shouldThrow = true;
181
176
  }
182
177
 
183
178
  const handleAssertResponse = (response) => {
184
- emitter.emit(events.log.log, response);
185
-
186
- let valid = response.indexOf("The task passed") > -1;
187
-
188
- if (invert) {
189
- valid = !valid;
190
- }
179
+ emitter.emit(events.log.markdown.static, response);
191
180
 
192
- if (valid) {
181
+ if (response.indexOf("The task passed") > -1) {
193
182
  return true;
194
183
  } else {
195
184
  if (shouldThrow) {
196
185
  // Is fatal, othewise it just changes the assertion to be true
197
- throw new MatchError(
198
- `AI Assertion failed ${invert && "(Inverted)"}`,
199
- true,
200
- );
186
+ throw new MatchError(`AI Assertion failed`, true);
201
187
  } else {
202
188
  return false;
203
189
  }
@@ -241,17 +227,31 @@ const createCommands = (
241
227
  switch (direction) {
242
228
  case "up":
243
229
  if (method === "mouse") {
244
- await sandbox.send({ type: "scroll", amount, direction });
230
+ await sandbox.send({
231
+ os: "linux",
232
+ type: "scroll",
233
+ amount,
234
+ direction,
235
+ });
245
236
  } else {
246
- await sandbox.send({ type: "press", keys: ["pageup"] });
237
+ await sandbox.send({ os: "linux", type: "press", keys: ["pageup"] });
247
238
  }
248
239
  await redraw.wait(2500);
249
240
  break;
250
241
  case "down":
251
242
  if (method === "mouse") {
252
- await sandbox.send({ type: "scroll", amount, direction });
243
+ await sandbox.send({
244
+ os: "linux",
245
+ type: "scroll",
246
+ amount,
247
+ direction,
248
+ });
253
249
  } else {
254
- await sandbox.send({ type: "press", keys: ["pagedown"] });
250
+ await sandbox.send({
251
+ os: "linux",
252
+ type: "press",
253
+ keys: ["pagedown"],
254
+ });
255
255
  }
256
256
  await redraw.wait(2500);
257
257
  break;
@@ -298,7 +298,7 @@ const createCommands = (
298
298
  x = parseInt(x);
299
299
  y = parseInt(y);
300
300
 
301
- await sandbox.send({ type: "moveMouse", x, y });
301
+ await sandbox.send({ os: "linux", type: "moveMouse", x, y });
302
302
 
303
303
  emitter.emit(events.mouseMove, { x, y });
304
304
 
@@ -306,17 +306,21 @@ const createCommands = (
306
306
 
307
307
  if (action !== "hover") {
308
308
  if (action === "click" || action === "left-click") {
309
- await sandbox.send({ type: "leftClick" });
309
+ await sandbox.send({ os: "linux", type: "leftClick" });
310
310
  } else if (action === "right-click") {
311
- await sandbox.send({ type: "rightClick" });
311
+ await sandbox.send({ os: "linux", type: "rightClick" });
312
312
  } else if (action === "middle-click") {
313
- await sandbox.send({ type: "middleClick" });
313
+ await sandbox.send({ os: "linux", type: "middleClick" });
314
314
  } else if (action === "double-click") {
315
- await sandbox.send({ type: "doubleClick" });
315
+ await sandbox.send({ os: "linux", type: "doubleClick" });
316
316
  } else if (action === "drag-start") {
317
- await sandbox.send({ type: "mousePress", button: "left" });
317
+ await sandbox.send({ os: "linux", type: "mousePress", button: "left" });
318
318
  } else if (action === "drag-end") {
319
- await sandbox.send({ type: "mouseRelease", button: "left" });
319
+ await sandbox.send({
320
+ os: "linux",
321
+ type: "mouseRelease",
322
+ button: "left",
323
+ });
320
324
  }
321
325
 
322
326
  emitter.emit(events.mouseClick, { x, y, button, click, double });
@@ -333,7 +337,7 @@ const createCommands = (
333
337
  x = parseInt(x);
334
338
  y = parseInt(y);
335
339
 
336
- await sandbox.send({ type: "moveMouse", x, y });
340
+ await sandbox.send({ os: "linux", type: "moveMouse", x, y });
337
341
 
338
342
  await redraw.wait(2500);
339
343
 
@@ -353,12 +357,11 @@ const createCommands = (
353
357
  description = null,
354
358
  action = "click",
355
359
  method = "turbo",
356
- timeout = 5000, // we pass this to the subsequent wait-for-text block
357
360
  ) => {
358
361
  text = text ? text.toString() : null;
359
362
 
360
363
  // wait for the text to appear on screen
361
- await commands["wait-for-text"](text, timeout);
364
+ await commands["wait-for-text"](text, 5000);
362
365
 
363
366
  description = description ? description.toString() : null;
364
367
 
@@ -413,7 +416,7 @@ const createCommands = (
413
416
  return response.data;
414
417
  }
415
418
  },
416
- "match-image": async (relativePath, action = "click", invert = false) => {
419
+ "match-image": async (relativePath, action = "click") => {
417
420
  // Resolve the image path relative to the current file
418
421
  const resolvedPath = resolveRelativePath(relativePath);
419
422
 
@@ -421,10 +424,6 @@ const createCommands = (
421
424
 
422
425
  let result = await findImageOnScreen(resolvedPath, image);
423
426
 
424
- if (invert) {
425
- result = !result;
426
- }
427
-
428
427
  if (!result) {
429
428
  throw new CommandError(`Image not found: ${resolvedPath}`);
430
429
  } else {
@@ -438,12 +437,13 @@ const createCommands = (
438
437
  return true;
439
438
  },
440
439
  // type a string
440
+ os: "linux",
441
441
  type: async (string, delay = 250) => {
442
442
  await redraw.start();
443
443
 
444
444
  string = string.toString();
445
445
 
446
- await sandbox.send({ type: "write", text: string, delay });
446
+ await sandbox.send({ os: "linux", type: "write", text: string, delay });
447
447
  await redraw.wait(5000);
448
448
  return;
449
449
  },
@@ -453,7 +453,7 @@ const createCommands = (
453
453
  await redraw.start();
454
454
 
455
455
  // finally, press the keys
456
- await sandbox.send({ type: "press", keys: inputKeys });
456
+ await sandbox.send({ os: "linux", type: "press", keys: inputKeys });
457
457
 
458
458
  await redraw.wait(5000);
459
459
 
@@ -463,7 +463,7 @@ const createCommands = (
463
463
  wait: async (timeout = 3000) => {
464
464
  return await delay(timeout);
465
465
  },
466
- "wait-for-image": async (description, timeout = 10000, invert = false) => {
466
+ "wait-for-image": async (description, timeout = 10000) => {
467
467
  emitter.emit(
468
468
  events.log.narration,
469
469
  theme.dim(
@@ -481,7 +481,6 @@ const createCommands = (
481
481
  `An image matching the description "${description}" appears on screen.`,
482
482
  false,
483
483
  false,
484
- invert,
485
484
  );
486
485
 
487
486
  durationPassed = new Date().getTime() - startTime;
@@ -512,12 +511,7 @@ const createCommands = (
512
511
  );
513
512
  }
514
513
  },
515
- "wait-for-text": async (
516
- text,
517
- timeout = 5000,
518
- method = "turbo",
519
- invert = false,
520
- ) => {
514
+ "wait-for-text": async (text, timeout = 5000, method = "turbo") => {
521
515
  await redraw.start();
522
516
 
523
517
  emitter.emit(
@@ -547,12 +541,7 @@ const createCommands = (
547
541
  );
548
542
 
549
543
  passed = response.data;
550
-
551
- if (invert) {
552
- passed = !passed;
553
- }
554
544
  durationPassed = new Date().getTime() - startTime;
555
-
556
545
  if (!passed) {
557
546
  emitter.emit(
558
547
  events.log.narration,
@@ -580,7 +569,6 @@ const createCommands = (
580
569
  maxDistance = 10000,
581
570
  textMatchMethod = "turbo",
582
571
  method = "keyboard",
583
- invert = false,
584
572
  ) => {
585
573
  await redraw.start();
586
574
 
@@ -592,11 +580,15 @@ const createCommands = (
592
580
 
593
581
  if (method === "keyboard") {
594
582
  try {
595
- await sandbox.send({ type: "press", keys: ["f", "ctrl"] });
583
+ await sandbox.send({
584
+ os: "linux",
585
+ type: "press",
586
+ keys: ["f", "ctrl"],
587
+ });
596
588
  await delay(1000);
597
- await sandbox.send({ type: "write", text });
589
+ await sandbox.send({ os: "linux", type: "write", text });
598
590
  await redraw.wait(5000);
599
- await sandbox.send({ type: "press", keys: ["escape"] });
591
+ await sandbox.send({ os: "linux", type: "press", keys: ["escape"] });
600
592
  } catch {
601
593
  throw new MatchError(
602
594
  "Could not find element using browser text search",
@@ -624,11 +616,6 @@ const createCommands = (
624
616
  );
625
617
 
626
618
  passed = response.data;
627
-
628
- if (invert) {
629
- passed = !passed;
630
- }
631
-
632
619
  if (!passed) {
633
620
  emitter.emit(
634
621
  events.log.narration,
@@ -657,7 +644,6 @@ const createCommands = (
657
644
  maxDistance = 10000,
658
645
  method = "keyboard",
659
646
  path,
660
- invert = false,
661
647
  ) => {
662
648
  const needle = description || path;
663
649
 
@@ -687,7 +673,6 @@ const createCommands = (
687
673
  `An image matching the description "${description}" appears on screen.`,
688
674
  false,
689
675
  false,
690
- invert,
691
676
  );
692
677
  }
693
678
 
@@ -727,6 +712,7 @@ const createCommands = (
727
712
  await redraw.start();
728
713
 
729
714
  await sandbox.send({
715
+ os: "linux",
730
716
  type: "commands.focus-application",
731
717
  name,
732
718
  });
@@ -740,40 +726,41 @@ const createCommands = (
740
726
  });
741
727
  return result.data;
742
728
  },
743
- assert: async (assertion, async = false, invert = false) => {
744
- let response = await assert(assertion, true, async, invert);
745
-
746
- return response;
729
+ assert: async (assertion, async = false) => {
730
+ return await assert(assertion, true, async);
747
731
  },
748
- exec: async (language, code, timeout, silent = false) => {
732
+ exec: async (language = "pwsh", code, timeout, silent = false) => {
749
733
  emitter.emit(events.log.narration, theme.dim(`calling exec...`), true);
750
734
 
751
735
  emitter.emit(events.log.log, code);
752
736
 
753
737
  let plat = system.platform();
754
738
 
755
- if (language == "pwsh") {
739
+ if (language == "pwsh" || language == "sh") {
756
740
  let result = null;
757
741
 
758
742
  result = await sandbox.send({
743
+ os: "linux",
759
744
  type: "commands.run",
760
745
  command: code,
761
746
  timeout,
762
747
  });
763
748
 
749
+ console.log("Exec result:", result);
750
+
764
751
  if (result.out && result.out.returncode !== 0) {
765
752
  throw new MatchError(
766
753
  `Command failed with exit code ${result.out.returncode}: ${result.out.stderr}`,
767
754
  );
768
755
  } else {
769
- if (!silent && result.out?.stdout) {
770
- emitter.emit(events.log.log, theme.dim(`stdout:`), true);
756
+ if (!silent) {
757
+ emitter.emit(events.log.log, theme.dim(`Command stdout:`), true);
771
758
  emitter.emit(events.log.log, `${result.out.stdout}`, true);
772
- }
773
759
 
774
- if (!silent && result.out.stderr) {
775
- emitter.emit(events.log.log, theme.dim(`stderr:`), true);
776
- emitter.emit(events.log.log, `${result.out.stderr}`, true);
760
+ if (result.out.stderr) {
761
+ emitter.emit(events.log.log, theme.dim(`Command stderr:`), true);
762
+ emitter.emit(events.log.log, `${result.out.stderr}`, true);
763
+ }
777
764
  }
778
765
 
779
766
  return result.out?.stdout?.trim();
@@ -805,12 +792,7 @@ const createCommands = (
805
792
  try {
806
793
  await script.runInNewContext(context);
807
794
  } catch (e) {
808
- // Log the error to the emitter instead of console.error to maintain consistency
809
- emitter.emit(
810
- events.log.debug,
811
- `JavaScript execution error: ${e.message}`,
812
- );
813
- // Wait a tick to allow any promise rejections to be handled
795
+ console.error(e);
814
796
  throw new CommandError(`Error running script: ${e.message}`);
815
797
  }
816
798
 
@@ -65,6 +65,11 @@ function createDebuggerServer(config = {}) {
65
65
 
66
66
  ws.on("close", () => {
67
67
  clients.delete(ws);
68
+
69
+ // If no clients connected, we can optionally shut down
70
+ if (clients.size === 0) {
71
+ console.log("No clients connected, keeping server alive");
72
+ }
68
73
  });
69
74
 
70
75
  ws.on("error", (error) => {
@@ -1,6 +1,6 @@
1
1
  // parses markdown content to find code blocks, and then extracts yaml from those code blocks
2
2
  const yaml = require("js-yaml");
3
- const pkg = require("../../package.json");
3
+ const package = require("../../package.json");
4
4
  const session = require("./session");
5
5
  const theme = require("./theme");
6
6
  // do the actual parsing
@@ -56,7 +56,7 @@ const jsonToManual = function (json, colors = true) {
56
56
  const dumpToYML = async function (inputArray, sessionInstance = null) {
57
57
  // use yml dump to convert json to yml
58
58
  let yml = await yaml.dump({
59
- version: pkg.version,
59
+ version: package.version,
60
60
  session: sessionInstance ? sessionInstance.get() : session.get(),
61
61
  steps: inputArray,
62
62
  });
@@ -69,6 +69,7 @@ const createRedraw = (emitter, system, sandbox) => {
69
69
  async function updateNetwork() {
70
70
  if (sandbox && sandbox.instanceSocketConnected) {
71
71
  let network = await sandbox.send({
72
+ os: "linux",
72
73
  type: "system.network",
73
74
  });
74
75
  parseNetworkStats(
@@ -51,6 +51,7 @@ const createSandbox = (emitter, analytics) => {
51
51
  async auth(apiKey) {
52
52
  let reply = await this.send({
53
53
  type: "authenticate",
54
+ os: "linux",
54
55
  apiKey,
55
56
  });
56
57
 
@@ -64,6 +65,7 @@ const createSandbox = (emitter, analytics) => {
64
65
  async connect(sandboxId, persist = false) {
65
66
  let reply = await this.send({
66
67
  type: "connect",
68
+ os: "linux",
67
69
  persist,
68
70
  sandboxId,
69
71
  });
package/agent/lib/sdk.js CHANGED
@@ -95,7 +95,7 @@ const createSDK = (emitter, config, sessionInstance) => {
95
95
  return token;
96
96
  } catch (error) {
97
97
  outputError(error);
98
- throw error; // Re-throw the error so calling code can handle it properly
98
+ return;
99
99
  }
100
100
  }
101
101
  };
@@ -194,7 +194,6 @@ const createSDK = (emitter, config, sessionInstance) => {
194
194
  return value;
195
195
  } catch (error) {
196
196
  outputError(error);
197
- throw error; // Re-throw the error so calling code can handle it properly
198
197
  }
199
198
  };
200
199
 
@@ -263,7 +263,7 @@ class SourceMapper {
263
263
  let description = `${fileName}:${(sourcePosition.step.startLine || 0) + 1}`;
264
264
 
265
265
  if (sourcePosition.command) {
266
- description += `:${(sourcePosition.command.startLine || 0) + 1}`;
266
+ description += `:${(sourcePosition.command.startLine || 0) + 1} (${sourcePosition.command.command || "unknown command"})`;
267
267
  } else {
268
268
  description += ` (step ${sourcePosition.step.stepIndex + 1})`;
269
269
  }
@@ -7,7 +7,10 @@ const { events } = require("../events.js");
7
7
 
8
8
  const createSystem = (emitter, sandbox, config) => {
9
9
  const screenshot = async (options) => {
10
- let { base64 } = await sandbox.send({ type: "system.screenshot" });
10
+ let { base64 } = await sandbox.send({
11
+ os: "linux",
12
+ type: "system.screenshot",
13
+ });
11
14
 
12
15
  if (!base64) {
13
16
  console.error("Failed to take screenshot");
@@ -110,6 +113,7 @@ const createSystem = (emitter, sandbox, config) => {
110
113
  const activeWin = async () => {
111
114
  // Get Mouse Position from command line
112
115
  let result = await sandbox.send({
116
+ os: "linux",
113
117
  type: "system.get-active-window",
114
118
  });
115
119
 
@@ -119,6 +123,7 @@ const createSystem = (emitter, sandbox, config) => {
119
123
  const getMousePosition = async () => {
120
124
  // Get Mouse Position from command line
121
125
  let result = await sandbox.send({
126
+ os: "linux",
122
127
  type: "system.get-mouse-position",
123
128
  });
124
129