@rehearsal-labs/retest 0.2.0 → 0.3.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 (218) hide show
  1. package/README.md +6 -5
  2. package/dist/api/source-location.d.ts.map +1 -1
  3. package/dist/api/source-location.js +3 -1
  4. package/dist/browser/builds.d.ts +35 -6
  5. package/dist/browser/builds.d.ts.map +1 -1
  6. package/dist/browser/builds.js +115 -16
  7. package/dist/browser/cdp/transport.d.ts.map +1 -1
  8. package/dist/browser/cdp/transport.js +4 -4
  9. package/dist/browser/chromium-process.d.ts +23 -0
  10. package/dist/browser/chromium-process.d.ts.map +1 -1
  11. package/dist/browser/chromium-process.js +78 -13
  12. package/dist/browser/electron.d.ts +1 -1
  13. package/dist/browser/electron.d.ts.map +1 -1
  14. package/dist/browser/electron.js +6 -3
  15. package/dist/browser/executables.d.ts +16 -1
  16. package/dist/browser/executables.d.ts.map +1 -1
  17. package/dist/browser/executables.js +50 -18
  18. package/dist/browser/firefox/accessible-names.d.ts +5 -4
  19. package/dist/browser/firefox/accessible-names.d.ts.map +1 -1
  20. package/dist/browser/firefox/accessible-names.js +11 -6
  21. package/dist/browser/firefox/bridge.js +3 -2
  22. package/dist/browser/firefox/executable.d.ts +14 -14
  23. package/dist/browser/firefox/executable.d.ts.map +1 -1
  24. package/dist/browser/firefox/executable.js +29 -21
  25. package/dist/browser/firefox/launch.js +1 -1
  26. package/dist/browser/firefox/navigation.d.ts +5 -2
  27. package/dist/browser/firefox/navigation.d.ts.map +1 -1
  28. package/dist/browser/firefox/navigation.js +48 -14
  29. package/dist/browser/firefox/orphans.d.ts.map +1 -1
  30. package/dist/browser/firefox/orphans.js +34 -2
  31. package/dist/browser/firefox/page.d.ts.map +1 -1
  32. package/dist/browser/firefox/page.js +113 -19
  33. package/dist/browser/firefox/process.d.ts +20 -1
  34. package/dist/browser/firefox/process.d.ts.map +1 -1
  35. package/dist/browser/firefox/process.js +124 -22
  36. package/dist/browser/firefox/profile.d.ts +5 -0
  37. package/dist/browser/firefox/profile.d.ts.map +1 -1
  38. package/dist/browser/firefox/profile.js +17 -1
  39. package/dist/browser/firefox/storage.d.ts.map +1 -1
  40. package/dist/browser/firefox/storage.js +4 -2
  41. package/dist/browser/firefox/subscriptions.d.ts +26 -0
  42. package/dist/browser/firefox/subscriptions.d.ts.map +1 -0
  43. package/dist/browser/firefox/subscriptions.js +10 -0
  44. package/dist/browser/launch.d.ts +6 -0
  45. package/dist/browser/launch.d.ts.map +1 -1
  46. package/dist/browser/launch.js +14 -1
  47. package/dist/cli/commands/doctor.js +3 -3
  48. package/dist/cli/commands/inspect.js +3 -2
  49. package/dist/cli/commands/install.d.ts.map +1 -1
  50. package/dist/cli/commands/install.js +26 -13
  51. package/dist/cli/commands/licences.d.ts +22 -0
  52. package/dist/cli/commands/licences.d.ts.map +1 -1
  53. package/dist/cli/commands/licences.js +62 -20
  54. package/dist/cli/commands/run.js +2 -2
  55. package/dist/cli/doctor/checks.js +4 -1
  56. package/dist/cli/inspect/diagnostics.js +3 -3
  57. package/dist/cli/inspect/test-timeline.js +10 -10
  58. package/dist/cli/install/doctor-rows.d.ts.map +1 -1
  59. package/dist/cli/install/doctor-rows.js +5 -4
  60. package/dist/cli/install/file-changes.d.ts +44 -0
  61. package/dist/cli/install/file-changes.d.ts.map +1 -0
  62. package/dist/cli/install/file-changes.js +81 -0
  63. package/dist/cli/install/install-archive.d.ts +3 -1
  64. package/dist/cli/install/install-archive.d.ts.map +1 -1
  65. package/dist/cli/install/install-archive.js +80 -33
  66. package/dist/cli/install/lock.d.ts.map +1 -1
  67. package/dist/cli/install/lock.js +108 -21
  68. package/dist/cli/install/media-doctor.d.ts.map +1 -1
  69. package/dist/cli/install/media-doctor.js +2 -1
  70. package/dist/cli/install/media-install.d.ts.map +1 -1
  71. package/dist/cli/install/media-install.js +38 -19
  72. package/dist/cli/install/media-pins.d.ts +7 -1
  73. package/dist/cli/install/media-pins.d.ts.map +1 -1
  74. package/dist/cli/install/media-pins.js +23 -12
  75. package/dist/cli/install/media-record.d.ts.map +1 -1
  76. package/dist/cli/install/media-record.js +10 -9
  77. package/dist/cli/install/media-report.d.ts +3 -1
  78. package/dist/cli/install/media-report.d.ts.map +1 -1
  79. package/dist/cli/install/media-report.js +7 -5
  80. package/dist/cli/install/media-tools.d.ts.map +1 -1
  81. package/dist/cli/install/media-tools.js +6 -4
  82. package/dist/cli/install/process-start.d.ts +3 -2
  83. package/dist/cli/install/process-start.d.ts.map +1 -1
  84. package/dist/cli/install/process-start.js +4 -0
  85. package/dist/cli/install/report.d.ts.map +1 -1
  86. package/dist/cli/install/report.js +11 -7
  87. package/dist/cli/install/supervisor-install.d.ts +33 -0
  88. package/dist/cli/install/supervisor-install.d.ts.map +1 -0
  89. package/dist/cli/install/supervisor-install.js +158 -0
  90. package/dist/cli/install/supervisor-locate.d.ts +47 -0
  91. package/dist/cli/install/supervisor-locate.d.ts.map +1 -0
  92. package/dist/cli/install/supervisor-locate.js +113 -0
  93. package/dist/cli/install/supervisor-pins.d.ts +21 -0
  94. package/dist/cli/install/supervisor-pins.d.ts.map +1 -0
  95. package/dist/cli/install/supervisor-pins.js +28 -0
  96. package/dist/cli/install/supervisor-record.d.ts +31 -0
  97. package/dist/cli/install/supervisor-record.d.ts.map +1 -0
  98. package/dist/cli/install/supervisor-record.js +104 -0
  99. package/dist/cli/install/supervisor-report.d.ts +11 -0
  100. package/dist/cli/install/supervisor-report.d.ts.map +1 -0
  101. package/dist/cli/install/supervisor-report.js +33 -0
  102. package/dist/cli/install/supervisor-tools.d.ts +43 -0
  103. package/dist/cli/install/supervisor-tools.d.ts.map +1 -0
  104. package/dist/cli/install/supervisor-tools.js +114 -0
  105. package/dist/cli/install/unpack.d.ts +23 -3
  106. package/dist/cli/install/unpack.d.ts.map +1 -1
  107. package/dist/cli/install/unpack.js +124 -10
  108. package/dist/cli/install/zip-member.d.ts +15 -0
  109. package/dist/cli/install/zip-member.d.ts.map +1 -0
  110. package/dist/cli/install/zip-member.js +77 -0
  111. package/dist/cli/interrupt.d.ts +1 -1
  112. package/dist/cli/interrupt.d.ts.map +1 -1
  113. package/dist/cli/interrupt.js +15 -10
  114. package/dist/cli/terminal.d.ts +9 -1
  115. package/dist/cli/terminal.d.ts.map +1 -1
  116. package/dist/cli/terminal.js +14 -0
  117. package/dist/config/define.d.ts +2 -2
  118. package/dist/config/define.js +2 -2
  119. package/dist/diagnostics/firefox-collector.d.ts +11 -10
  120. package/dist/diagnostics/firefox-collector.d.ts.map +1 -1
  121. package/dist/diagnostics/firefox-collector.js +16 -11
  122. package/dist/media/client.d.ts +2 -1
  123. package/dist/media/client.d.ts.map +1 -1
  124. package/dist/media/client.js +16 -5
  125. package/dist/media/host.d.ts +32 -0
  126. package/dist/media/host.d.ts.map +1 -0
  127. package/dist/media/host.js +50 -0
  128. package/dist/media/locate.d.ts.map +1 -1
  129. package/dist/media/locate.js +4 -3
  130. package/dist/native/processes.d.ts.map +1 -1
  131. package/dist/native/processes.js +7 -3
  132. package/dist/protocol/files.d.ts +1 -1
  133. package/dist/protocol/files.d.ts.map +1 -1
  134. package/dist/protocol/files.js +10 -5
  135. package/dist/reporters/commands.d.ts +12 -3
  136. package/dist/reporters/commands.d.ts.map +1 -1
  137. package/dist/reporters/commands.js +29 -11
  138. package/dist/reporters/human-card.js +1 -1
  139. package/dist/reporters/human.d.ts +3 -1
  140. package/dist/reporters/human.d.ts.map +1 -1
  141. package/dist/reporters/human.js +8 -8
  142. package/dist/reporters/style.d.ts +21 -2
  143. package/dist/reporters/style.d.ts.map +1 -1
  144. package/dist/reporters/style.js +11 -2
  145. package/dist/runner/app-server.d.ts +27 -7
  146. package/dist/runner/app-server.d.ts.map +1 -1
  147. package/dist/runner/app-server.js +74 -24
  148. package/dist/runner/child.js +6 -2
  149. package/dist/runner/media-leftovers.d.ts +7 -3
  150. package/dist/runner/media-leftovers.d.ts.map +1 -1
  151. package/dist/runner/media-leftovers.js +27 -6
  152. package/dist/runner/resources.d.ts +8 -0
  153. package/dist/runner/resources.d.ts.map +1 -1
  154. package/dist/runner/resources.js +12 -1
  155. package/dist/runner/run-session.d.ts.map +1 -1
  156. package/dist/runner/run-session.js +9 -4
  157. package/dist/runner/run.d.ts.map +1 -1
  158. package/dist/runner/run.js +2 -1
  159. package/dist/runner/target-drivers.d.ts +5 -2
  160. package/dist/runner/target-drivers.d.ts.map +1 -1
  161. package/dist/runner/target-drivers.js +10 -1
  162. package/dist/runner/test-file-process.d.ts +8 -0
  163. package/dist/runner/test-file-process.d.ts.map +1 -1
  164. package/dist/runner/test-file-process.js +26 -3
  165. package/dist/runner/test-pages.d.ts.map +1 -1
  166. package/dist/runner/test-pages.js +5 -2
  167. package/dist/shared/environment.d.ts +17 -0
  168. package/dist/shared/environment.d.ts.map +1 -0
  169. package/dist/shared/environment.js +27 -0
  170. package/dist/shared/metadata-process-worker.js +15 -7
  171. package/dist/shared/metadata-process.d.ts +5 -0
  172. package/dist/shared/metadata-process.d.ts.map +1 -1
  173. package/dist/shared/metadata-process.js +36 -6
  174. package/dist/shared/posix-path.d.ts +12 -0
  175. package/dist/shared/posix-path.d.ts.map +1 -1
  176. package/dist/shared/posix-path.js +16 -0
  177. package/dist/shared/private-file.d.ts +38 -0
  178. package/dist/shared/private-file.d.ts.map +1 -0
  179. package/dist/shared/private-file.js +132 -0
  180. package/dist/shared/process-ownership.d.ts +52 -2
  181. package/dist/shared/process-ownership.d.ts.map +1 -1
  182. package/dist/shared/process-ownership.js +104 -11
  183. package/dist/shared/process-supervisor.d.ts +309 -0
  184. package/dist/shared/process-supervisor.d.ts.map +1 -0
  185. package/dist/shared/process-supervisor.js +737 -0
  186. package/dist/shared/process-system.d.ts +113 -0
  187. package/dist/shared/process-system.d.ts.map +1 -0
  188. package/dist/shared/process-system.js +254 -0
  189. package/dist/shared/regular-file.d.ts +2 -2
  190. package/dist/shared/regular-file.d.ts.map +1 -1
  191. package/dist/shared/regular-file.js +19 -2
  192. package/dist/store/artifacts.d.ts +5 -4
  193. package/dist/store/artifacts.d.ts.map +1 -1
  194. package/dist/store/artifacts.js +18 -5
  195. package/dist/store/run-store.d.ts +5 -2
  196. package/dist/store/run-store.d.ts.map +1 -1
  197. package/dist/store/run-store.js +48 -4
  198. package/media/Cargo.lock +16 -0
  199. package/media/Cargo.toml +16 -1
  200. package/media/src/encoder.rs +56 -12
  201. package/media/src/frame.rs +7 -1
  202. package/media/src/main.rs +20 -2
  203. package/media/src/place.rs +230 -11
  204. package/media/src/process_ownership_windows.rs +1058 -0
  205. package/media/src/recording.rs +15 -7
  206. package/media/src/replies.rs +55 -0
  207. package/media/src/server.rs +72 -2
  208. package/media/src/store.rs +71 -2
  209. package/package.json +9 -4
  210. package/src/cli/install/media-notices.txt +465 -1
  211. package/supervisor/Cargo.lock +25 -0
  212. package/supervisor/Cargo.toml +22 -0
  213. package/supervisor/NOTICES +464 -0
  214. package/supervisor/build.rs +44 -0
  215. package/supervisor/src/command.rs +612 -0
  216. package/supervisor/src/jobs.rs +1650 -0
  217. package/supervisor/src/main.rs +71 -0
  218. package/supervisor/src/reply.rs +367 -0
@@ -7,6 +7,8 @@ import { Deadline } from "../protocol/deadline.js";
7
7
  import { describeExit } from "../shared/process-exit.js";
8
8
  import { readMetadataProcess, readMetadataProcessAsync } from "../shared/metadata-process.js";
9
9
  import { OwnedProcessGroup } from "../shared/process-ownership.js";
10
+ import { consolesDetached, holdLaunch, launchesHeldByJob, prepareOwnedLaunch } from "../shared/process-system.js";
11
+ import { encoderVariables, hostVariable } from "./host.js";
10
12
  import { encodeRequestHead, MAX_FRAME_BYTES, MAX_FRAME_ID_CHARACTERS, MAX_ID_CHARACTERS, MAX_IDENTITY_CHARACTERS, MAX_OUTPUT_SIDE, MAX_PATH_BYTES, MAX_SEQUENCE_BYTES, MAX_SEQUENCE_FRAMES, MEDIA_PROTOCOL_VERSION, MediaProtocolError, MediaVersionMismatch, ReplyReader, } from "./protocol.js";
11
13
  export { MAX_FRAME_BYTES, MAX_FRAME_ID_CHARACTERS, MAX_ID_CHARACTERS, MAX_IDENTITY_CHARACTERS, MAX_OUTPUT_SIDE, MAX_PATH_BYTES, MAX_SEQUENCE_BYTES, MAX_SEQUENCE_FRAMES, MEDIA_PROTOCOL_VERSION } from "./protocol.js";
12
14
  /** The most request bytes retained across the write queue and pipe. */
@@ -126,8 +128,8 @@ export function mediaOwnershipSystem(root, metadata = { read: readMetadataProces
126
128
  /** Paths needed by the media encoder, with a fixed locale and no application or judge credentials. */
127
129
  export function mediaEnvironment(env) {
128
130
  const result = { LC_ALL: 'C' };
129
- for (const name of ['PATH', 'TMPDIR']) {
130
- const value = env[name];
131
+ for (const name of encoderVariables) {
132
+ const value = hostVariable(env, name);
131
133
  if (value !== undefined)
132
134
  result[name] = value;
133
135
  }
@@ -207,7 +209,8 @@ export function captureEncoderOwnership(worker, encoderPid) {
207
209
  }
208
210
  /**
209
211
  * Retest's media process, `retest-media`, run as a child in a process group of its own; each encoder it starts
210
- * leads a group of its own too. Frames go to it over a pipe with their bytes untouched; each recording ends with
212
+ * leads a group of its own too. On Windows the process is held in a job of its own instead, and its encoders are born
213
+ * in that job. Frames go to it over a pipe with their bytes untouched; each recording ends with
211
214
  * exactly one `Ended` from the process. The client never invents an outcome: if the process ends before a
212
215
  * recording does, the client stops only the encoder processes whose launch ownership it recorded, and the promise
213
216
  * rejects with how the process ended and any file left. Unreadable or changed ownership is a cleanup failure.
@@ -290,8 +293,16 @@ export class MediaProcess {
290
293
  if (value !== undefined && (!Number.isSafeInteger(value) || value < 1))
291
294
  throw new RangeError('media admission limits must be positive whole numbers');
292
295
  }
293
- const child = spawn(options.executable, options.args ?? [], { stdio: 'pipe', detached: true, env: options.env ?? mediaEnvironment(process.env) });
294
- const ownership = child.pid === undefined ? undefined : new OwnedProcessGroup(child.pid, process.pid, mediaOwnershipSystem(child.pid));
296
+ try {
297
+ prepareOwnedLaunch();
298
+ }
299
+ catch (error) {
300
+ throw new MediaProcessError(errorMessage(error), { cause: error });
301
+ }
302
+ // On Windows a runner without a console would otherwise give the media process a console window of its own.
303
+ const child = spawn(options.executable, options.args ?? [], { stdio: 'pipe', detached: consolesDetached, windowsHide: true, env: options.env ?? mediaEnvironment(process.env) });
304
+ // On Windows the media process is held in a job of its own, and its encoders are born in it.
305
+ const ownership = child.pid === undefined ? undefined : launchesHeldByJob ? holdLaunch(child) : new OwnedProcessGroup(child.pid, process.pid, mediaOwnershipSystem(child.pid));
295
306
  const ownershipProblems = ownership?.capture() ?? [];
296
307
  const reader = new ReplyReader();
297
308
  const greeting = deferred();
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The value of a variable as the host reads it. A plain record copied from a Windows environment can hold `Path`
3
+ * where a caller asks for `PATH`.
4
+ *
5
+ * @example hostVariable({ Path: 'C:\\Windows' }, 'PATH') // 'C:\\Windows' on Windows, undefined elsewhere
6
+ */
7
+ export declare function hostVariable(env: Readonly<Record<string, string | undefined>>, name: string): string | undefined;
8
+ /**
9
+ * The file a program name is found as on PATH: the name itself, or on Windows the name with `.exe` when it has no
10
+ * extension of its own.
11
+ *
12
+ * @example programFileName('ffmpeg') // 'ffmpeg.exe' on Windows, 'ffmpeg' elsewhere
13
+ */
14
+ export declare function programFileName(name: string): string;
15
+ /** The variables the media process and its encoder start with: where programs and temporary files are. */
16
+ export declare const encoderVariables: readonly string[];
17
+ /** The variables Rust's tools start with: where programs, the user's home, the toolchains and temporary files are. */
18
+ export declare const toolchainVariables: readonly string[];
19
+ /**
20
+ * Where a source build of the media binary puts Cargo's output. The MSVC linker cannot write a path longer than 260
21
+ * characters, and a build script's path beneath a cache's staging folder can be longer, so on Windows the build goes to
22
+ * a short folder of its own in the system's temporary folder; elsewhere it stays in the staging folder it builds for.
23
+ *
24
+ * @example mediaBuildFolder('C:\\Users\\ada\\AppData\\Local\\retest\\media\\media-0.1.0.staging-1-x') // 'C:\\Users\\ada\\AppData\\Local\\Temp\\retest-media-1-9f2c41aa'
25
+ */
26
+ export declare function mediaBuildFolder(staging: string): string;
27
+ /**
28
+ * A program that exists on every host and is not ffmpeg, for a media process started only to greet: its encoder probe
29
+ * fails at once and nothing is encoded. Node itself stands in on Windows, which has no `/usr/bin/false`.
30
+ */
31
+ export declare const notAnEncoder: string;
32
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/media/host.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKhH;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,0GAA0G;AAC1G,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAAyE,CAAA;AAEvH,sHAAsH;AACtH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAEW,CAAA;AAE3D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,MAAsD,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { tmpdir } from 'node:os';
3
+ import { extname, join } from 'node:path';
4
+ // What finding and starting the media programs differs in on Windows, decided once: a program is a file named with
5
+ // `.exe`, variable names are one name whatever their case, so `Path` is `PATH`, and programs expect the system
6
+ // folder's variable and name their temporary folder TEMP and TMP.
7
+ const windows = process.platform === 'win32';
8
+ /**
9
+ * The value of a variable as the host reads it. A plain record copied from a Windows environment can hold `Path`
10
+ * where a caller asks for `PATH`.
11
+ *
12
+ * @example hostVariable({ Path: 'C:\\Windows' }, 'PATH') // 'C:\\Windows' on Windows, undefined elsewhere
13
+ */
14
+ export function hostVariable(env, name) {
15
+ if (!windows || env[name] !== undefined)
16
+ return env[name];
17
+ const upper = name.toUpperCase();
18
+ const found = Object.keys(env).find((key) => key.toUpperCase() === upper);
19
+ return found === undefined ? undefined : env[found];
20
+ }
21
+ /**
22
+ * The file a program name is found as on PATH: the name itself, or on Windows the name with `.exe` when it has no
23
+ * extension of its own.
24
+ *
25
+ * @example programFileName('ffmpeg') // 'ffmpeg.exe' on Windows, 'ffmpeg' elsewhere
26
+ */
27
+ export function programFileName(name) {
28
+ return windows && extname(name) === '' ? `${name}.exe` : name;
29
+ }
30
+ /** The variables the media process and its encoder start with: where programs and temporary files are. */
31
+ export const encoderVariables = windows ? ['PATH', 'SystemRoot', 'TEMP', 'TMP'] : ['PATH', 'TMPDIR'];
32
+ /** The variables Rust's tools start with: where programs, the user's home, the toolchains and temporary files are. */
33
+ export const toolchainVariables = windows
34
+ ? ['PATH', 'HOME', 'USERPROFILE', 'CARGO_HOME', 'RUSTUP_HOME', 'TEMP', 'TMP']
35
+ : ['PATH', 'HOME', 'CARGO_HOME', 'RUSTUP_HOME', 'TMPDIR'];
36
+ /**
37
+ * Where a source build of the media binary puts Cargo's output. The MSVC linker cannot write a path longer than 260
38
+ * characters, and a build script's path beneath a cache's staging folder can be longer, so on Windows the build goes to
39
+ * a short folder of its own in the system's temporary folder; elsewhere it stays in the staging folder it builds for.
40
+ *
41
+ * @example mediaBuildFolder('C:\\Users\\ada\\AppData\\Local\\retest\\media\\media-0.1.0.staging-1-x') // 'C:\\Users\\ada\\AppData\\Local\\Temp\\retest-media-1-9f2c41aa'
42
+ */
43
+ export function mediaBuildFolder(staging) {
44
+ return windows ? join(tmpdir(), `retest-media-${process.pid}-${randomBytes(4).toString('hex')}`) : join(staging, 'target');
45
+ }
46
+ /**
47
+ * A program that exists on every host and is not ffmpeg, for a media process started only to greet: its encoder probe
48
+ * fails at once and nothing is encoded. Node itself stands in on Windows, which has no `/usr/bin/false`.
49
+ */
50
+ export const notAnEncoder = windows ? process.execPath : '/usr/bin/false';
@@ -1 +1 @@
1
- {"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../src/media/locate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAQ7D,MAAM,MAAM,oBAAoB,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;CAAE,CAAA;AAChO,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,kBAAkB,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AACxT,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AACvH,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAChL,eAAO,MAAM,SAAS,EAAE,MAA8O,CAAA;AAEtQ,yGAAyG;AACzG,wBAAsB,YAAY,CAAC,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,KAAK,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAOrH;AAED,6GAA6G;AAC7G,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;AACpH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA"}
1
+ {"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../src/media/locate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAS7D,MAAM,MAAM,oBAAoB,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;CAAE,CAAA;AAChO,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,kBAAkB,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AACxT,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AACvH,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAChL,eAAO,MAAM,SAAS,EAAE,MAAqR,CAAA;AAE7S,yGAAyG;AACzG,wBAAsB,YAAY,CAAC,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,KAAK,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAOrH;AAED,6GAA6G;AAC7G,wBAAgB,WAAW,CAAC,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;AACpH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA"}
@@ -1,10 +1,11 @@
1
1
  import { lstat, realpath } from 'node:fs/promises';
2
+ import { sep } from 'node:path';
2
3
  import { Deadline } from "../protocol/deadline.js";
3
4
  import { inspectMedia } from "../cli/install/media-record.js";
4
5
  import { mediaTarget } from "../cli/install/media-pins.js";
5
6
  import { findMediaTool, probeMediaBinary } from "../cli/install/media-tools.js";
6
7
  import { checkFileIdentity, describeRefusal, openRegularFile } from "../shared/regular-file.js";
7
- export const ffmpegFix = 'Install ffmpeg with your host package manager, for example brew install ffmpeg on macOS or sudo apt-get install ffmpeg on Debian, then set RETEST_FFMPEG to its executable or put it on PATH. Retest ships and downloads no ffmpeg.';
8
+ export const ffmpegFix = 'Install ffmpeg with your host package manager, for example brew install ffmpeg on macOS, sudo apt-get install ffmpeg on Debian or winget install Gyan.FFmpeg on Windows, then set RETEST_FFMPEG to its executable or put it on PATH. Retest ships and downloads no ffmpeg.';
8
9
  /** An explicit setting, then RETEST_FFMPEG, then PATH. An unusable explicit name never falls through. */
9
10
  export async function locateFfmpeg(options = {}) {
10
11
  const env = options.env ?? process.env;
@@ -56,7 +57,7 @@ async function discoverLocation(options, deadline) {
56
57
  const env = options.env ?? process.env;
57
58
  const target = mediaTarget();
58
59
  if (target === undefined)
59
- return { ok: false, message: `Media discovery has no host target for ${process.platform} ${process.arch}. macOS arm64 is exercised; Linux x64 is unverified.` };
60
+ return { ok: false, message: `Retest builds retest-media for macOS arm64, Linux x64 and Windows x64, and this machine is ${process.platform} ${process.arch}, so there is none to find.` };
60
61
  const given = options.executable ?? env['RETEST_MEDIA_BINARY'];
61
62
  let executable;
62
63
  let source;
@@ -76,7 +77,7 @@ async function discoverLocation(options, deadline) {
76
77
  if (canonical === undefined)
77
78
  return { ok: false, message: `${executable} disappeared or cannot be read after discovery. Run npx retest install media, or name a readable release binary.` };
78
79
  const cachedFolder = inspection === undefined ? undefined : await realpath(inspection.folder).catch(() => undefined);
79
- const fromCache = inspection !== undefined && (executable === inspection.executablePath || executable.startsWith(`${inspection.folder}/`) || (cachedFolder !== undefined && canonical.startsWith(`${cachedFolder}/`)));
80
+ const fromCache = inspection !== undefined && (executable === inspection.executablePath || executable.startsWith(`${inspection.folder}${sep}`) || (cachedFolder !== undefined && canonical.startsWith(`${cachedFolder}${sep}`)));
80
81
  if (fromCache && inspection !== undefined && inspection.state !== 'installed')
81
82
  return { ok: false, message: `${inspection.problems.join(' ')} Remove ${inspection.folder} and run npx retest install media.` };
82
83
  if (!fromCache)
@@ -1 +1 @@
1
- {"version":3,"file":"processes.d.ts","sourceRoot":"","sources":["../../src/native/processes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"processes.d.ts","sourceRoot":"","sources":["../../src/native/processes.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import { errorMessage } from "../protocol/failures.js";
9
9
  import { maxTimeout } from "../protocol/timeouts.js";
10
10
  import { processTableOutputLimit, readMetadataProcess, readMetadataProcessAsync } from "../shared/metadata-process.js";
11
11
  import { OwnedProcessGroup, sameProcessIdentity } from "../shared/process-ownership.js";
12
+ import { consolesDetached, holdLaunch, launchesHeldByJob, prepareOwnedLaunch } from "../shared/process-system.js";
12
13
  import { NativeOutputLines } from "./output.js";
13
14
  /** The tools as macOS installs them. */
14
15
  export const systemTools = {
@@ -59,10 +60,12 @@ export async function runCommand(command, args, options) {
59
60
  return { code: null, signal: null, stdout: '', stderr: '', timedOut: false, stopped: true, started: false, cleanupProblems: [] };
60
61
  let child;
61
62
  try {
63
+ if (options.ownershipSystem === undefined)
64
+ prepareOwnedLaunch();
62
65
  child = spawn(command, args, {
63
66
  cwd: options.cwd,
64
67
  env: childEnvironment(options.environment, options.hiddenVariables),
65
- detached: true,
68
+ detached: consolesDetached,
66
69
  stdio: ['ignore', 'pipe', 'pipe'],
67
70
  });
68
71
  }
@@ -333,8 +336,9 @@ class GroupGuard {
333
336
  #outputClosed = false;
334
337
  constructor(child, system) {
335
338
  this.#child = child;
336
- this.#table = system === undefined ? new ProcessTable() : undefined;
337
- const owner = child.pid === undefined ? undefined : new OwnedProcessGroup(child.pid, process.pid, system ?? this.#table);
339
+ this.#table = system === undefined && !launchesHeldByJob ? new ProcessTable() : undefined;
340
+ // Where a job holds each launch, the job is its table; the process table `ps` reads exists only on Unix.
341
+ const owner = child.pid === undefined ? undefined : system === undefined && launchesHeldByJob ? holdLaunch(child) : new OwnedProcessGroup(child.pid, process.pid, system ?? this.#table);
338
342
  this.#owner = owner;
339
343
  this.#initial = owner === undefined ? Promise.resolve([]) : this.#reading(() => owner.capture());
340
344
  this.#exited = child.exitCode !== null || child.signalCode !== null;
@@ -79,5 +79,5 @@ export declare function describeInputFiles(files: readonly InputFileRecord[], li
79
79
  *
80
80
  * @example inputFilesProblem([{ name: 'a/b.txt', base64: '' }], 'setInputFiles') // { class: 'usage', … }
81
81
  */
82
- export declare function inputFilesProblem(files: readonly InputFileRecord[], method: string): Failure | undefined;
82
+ export declare function inputFilesProblem(files: readonly InputFileRecord[], method: string, platform?: NodeJS.Platform): Failure | undefined;
83
83
  //# sourceMappingURL=files.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/protocol/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAG5C,OAAO,EAAK,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAG5C;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpH,iIAAiI;AACjI,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAExC;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACjE;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA;AAEnC,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,eAAe,CAGxD,CAAA;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAA2G,CAAA;AAE3J,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,YAAY,CAKlD,CAAA;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,CAKhD,CAAA;AAMF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAI3F;AAMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAMxG"}
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/protocol/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAG5C,OAAO,EAAK,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAG5C;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpH,iIAAiI;AACjI,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAExC;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACjE;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA;AAEnC,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,eAAe,CAGxD,CAAA;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAA2G,CAAA;AAE3J,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,YAAY,CAKlD,CAAA;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,CAKhD,CAAA;AAWF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAI3F;AAMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,OAAO,GAAG,SAAS,CAMtJ"}
@@ -21,6 +21,11 @@ export const filesAnswerSchema = s.union([
21
21
  ]);
22
22
  // A name a file may take in a folder: no separator, and not one of the names that mean a folder itself.
23
23
  const separators = /[/\\\0]/;
24
+ // An absolute folder as the test file's process writes one: `/…` on macOS and Linux; on Windows a drive (`C:\…`) or a
25
+ // share (`\\server\share\…`). On Windows a drive with no separator after it, such as `C:tests`, is read against that
26
+ // drive's working folder, and `\tests` or `/tests` against the working folder's drive, so none of them is one; on macOS
27
+ // and Linux `C:\tests` and `\\server\tests` are names in the working folder.
28
+ const absoluteFolder = { posix: /^\//, windows: /^(?:[A-Za-z]:[\\/]|\\\\[^\\/])/ };
24
29
  const base64Text = /^[A-Za-z0-9+/]*={0,2}$/;
25
30
  /**
26
31
  * Names the files a test gave an input, the way the test wrote them: a path as written, a file by content by its name,
@@ -44,19 +49,19 @@ function describeInputFile(file) {
44
49
  *
45
50
  * @example inputFilesProblem([{ name: 'a/b.txt', base64: '' }], 'setInputFiles') // { class: 'usage', … }
46
51
  */
47
- export function inputFilesProblem(files, method) {
52
+ export function inputFilesProblem(files, method, platform = process.platform) {
48
53
  for (const file of files) {
49
- const problem = 'path' in file ? pathProblem(file) : contentProblem(file);
54
+ const problem = 'path' in file ? pathProblem(file, platform) : contentProblem(file);
50
55
  if (problem !== undefined)
51
56
  return failure('usage', `${method}() ${problem}`);
52
57
  }
53
58
  return undefined;
54
59
  }
55
- function pathProblem({ path, folder }) {
60
+ function pathProblem({ path, folder }, platform) {
56
61
  if (path === '' || path.includes('\0'))
57
62
  return 'takes a path to a file, received an empty path.';
58
- // The folder is the calling file's, which the test file's process reads as an absolute POSIX path.
59
- return folder.startsWith('/') ? undefined : `received the path ${JSON.stringify(path)} with a folder Retest cannot resolve it against.`;
63
+ // The folder is the calling file's, which the test file's process gives as an absolute path of this platform's.
64
+ return absoluteFolder[platform === 'win32' ? 'windows' : 'posix'].test(folder) ? undefined : `received the path ${JSON.stringify(path)} with a folder Retest cannot resolve it against.`;
60
65
  }
61
66
  function contentProblem({ name, mimeType, base64 }) {
62
67
  if (name === '' || name === '.' || name === '..' || separators.test(name)) {
@@ -5,11 +5,20 @@ export declare const retestCommand = "npx retest";
5
5
  /** The config a run reads when `--config` does not name another, in the root directory. */
6
6
  export declare const defaultConfigFile = "retest.config.ts";
7
7
  /**
8
- * Quotes a value for a POSIX shell, as lightly as it allows.
8
+ * Quotes a value for the shell a person pastes the command into, as lightly as it allows: a POSIX shell, or on Windows
9
+ * PowerShell and Git Bash.
9
10
  *
10
11
  * @example shellQuote('examples/task.retest.ts > saves a task') // '"examples/task.retest.ts > saves a task"'
11
12
  */
12
- export declare function shellQuote(value: string): string;
13
+ export declare function shellQuote(value: string, platform?: NodeJS.Platform): string;
14
+ /**
15
+ * A run folder as a printed command names it: with forward slashes on Windows too, which cmd.exe, PowerShell and Git
16
+ * Bash all hand to the program as they are, and Windows reads as separators, so a folder with no space needs no quotes
17
+ * in any of them.
18
+ *
19
+ * @example commandPath('.retest\\runs\\2026-09-30T09-15-00.000Z', 'win32') // '.retest/runs/2026-09-30T09-15-00.000Z'
20
+ */
21
+ export declare function commandPath(path: string, platform?: NodeJS.Platform): string;
13
22
  /**
14
23
  * What to run again: a file, the line a test is declared on, the row of a `test.for` there, and the targets
15
24
  * that pick out its variant.
@@ -42,5 +51,5 @@ export type InspectCommandOptions = {
42
51
  json?: boolean;
43
52
  };
44
53
  /** @example formatInspectCommand({ runFolder: 'runs/a', json: true }) // 'npx retest inspect runs/a --json' */
45
- export declare function formatInspectCommand(options: InspectCommandOptions): string;
54
+ export declare function formatInspectCommand(options: InspectCommandOptions, platform?: NodeJS.Platform): string;
46
55
  //# sourceMappingURL=commands.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/reporters/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAKlD,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEnE,yFAAyF;AACzF,eAAO,MAAM,aAAa,eAAe,CAAA;AAEzC,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,qBAAqB,CAAA;AAKnD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAA;AAE/H;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC,GAAG,OAAO,CAIjE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAajG;AAQD,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,+GAA+G;AAC/G,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAK3E"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/reporters/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAKlD,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAEnE,yFAAyF;AACzF,eAAO,MAAM,aAAa,eAAe,CAAA;AAEzC,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,qBAAqB,CAAA;AAanD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAK9F;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAE9F;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAA;AAE/H;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC,GAAG,OAAO,CAIjE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAajG;AAQD,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,+GAA+G;AAC/G,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,CAKzH"}
@@ -7,19 +7,37 @@ import { variantPairs } from "../protocol/variant.js";
7
7
  export const retestCommand = 'npx retest';
8
8
  /** The config a run reads when `--config` does not name another, in the root directory. */
9
9
  export const defaultConfigFile = 'retest.config.ts';
10
- const bare = /^[\w@%+=:,./-]+$/;
11
- const needsSingleQuotes = /["$`\\!]/;
10
+ // A POSIX shell, and on Windows PowerShell and Git Bash, which read the same quotes. PowerShell takes a bare comma for its
11
+ // array operator and a leading @ for splatting, so on Windows a value holding either is quoted too; a backslash is
12
+ // single-quoted there as everywhere, which Git Bash would otherwise read as an escape. PowerShell also reads the
13
+ // typographic double quotes “ ” „ as a double quote, so a value holding one is single-quoted, and the typographic single
14
+ // quotes ‘ ’ ‚ ‛ as a single quote, so inside single quotes each is doubled, as a plain one is. cmd.exe reads no single
15
+ // quotes and is not a shell these commands are written for.
16
+ const posixQuoting = { bare: /^[\w@%+=:,./-]+$/, needsSingleQuotes: /["$`\\!]/, singleQuoted: (value) => value.replaceAll("'", `'\\''`) };
17
+ const windowsQuoting = { bare: /^[\w%+=:./-][\w@%+=:./-]*$/, needsSingleQuotes: /["$`\\!“”„]/, singleQuoted: (value) => value.replace(/['‘’‚‛]/g, '$&$&') };
12
18
  /**
13
- * Quotes a value for a POSIX shell, as lightly as it allows.
19
+ * Quotes a value for the shell a person pastes the command into, as lightly as it allows: a POSIX shell, or on Windows
20
+ * PowerShell and Git Bash.
14
21
  *
15
22
  * @example shellQuote('examples/task.retest.ts > saves a task') // '"examples/task.retest.ts > saves a task"'
16
23
  */
17
- export function shellQuote(value) {
24
+ export function shellQuote(value, platform = process.platform) {
25
+ const { bare, needsSingleQuotes, singleQuoted } = platform === 'win32' ? windowsQuoting : posixQuoting;
18
26
  if (bare.test(value))
19
27
  return value;
20
28
  if (!needsSingleQuotes.test(value))
21
29
  return `"${value}"`;
22
- return `'${value.replaceAll("'", `'\\''`)}'`;
30
+ return `'${singleQuoted(value)}'`;
31
+ }
32
+ /**
33
+ * A run folder as a printed command names it: with forward slashes on Windows too, which cmd.exe, PowerShell and Git
34
+ * Bash all hand to the program as they are, and Windows reads as separators, so a folder with no space needs no quotes
35
+ * in any of them.
36
+ *
37
+ * @example commandPath('.retest\\runs\\2026-09-30T09-15-00.000Z', 'win32') // '.retest/runs/2026-09-30T09-15-00.000Z'
38
+ */
39
+ export function commandPath(path, platform = process.platform) {
40
+ return platform === 'win32' ? path.replaceAll('\\', '/') : path;
23
41
  }
24
42
  /**
25
43
  * Whether the command line can run this run's tests again as it ran them. It cannot when a program gave the run host
@@ -56,7 +74,7 @@ export function formatRerunCommand(run, request) {
56
74
  parts.push(...targetOptions(request.targets));
57
75
  const given = commandLineTimeouts === undefined ? changedTimeouts(timeouts) : formatTimeouts(commandLineTimeouts);
58
76
  if (given !== '')
59
- parts.push('--timeouts', given);
77
+ parts.push('--timeouts', shellQuote(given));
60
78
  return parts.join(' ');
61
79
  }
62
80
  function changedTimeouts(timeouts) {
@@ -67,14 +85,14 @@ function changedTimeouts(timeouts) {
67
85
  return formatTimeouts(changed);
68
86
  }
69
87
  /** @example formatInspectCommand({ runFolder: 'runs/a', json: true }) // 'npx retest inspect runs/a --json' */
70
- export function formatInspectCommand(options) {
71
- const parts = [retestCommand, 'inspect', shellQuote(options.runFolder)];
88
+ export function formatInspectCommand(options, platform = process.platform) {
89
+ const parts = [retestCommand, 'inspect', shellQuote(commandPath(options.runFolder, platform), platform)];
72
90
  if (options.testId !== undefined)
73
- parts.push('--test', shellQuote(options.testId), ...targetOptions(options.targets));
91
+ parts.push('--test', shellQuote(options.testId, platform), ...targetOptions(options.targets, platform));
74
92
  if (options.json === true)
75
93
  parts.push('--json');
76
94
  return parts.join(' ');
77
95
  }
78
- function targetOptions(targets) {
79
- return variantPairs(targets).flatMap((pair) => ['--target', shellQuote(pair)]);
96
+ function targetOptions(targets, platform = process.platform) {
97
+ return variantPairs(targets).flatMap((pair) => ['--target', shellQuote(pair, platform)]);
80
98
  }
@@ -29,7 +29,7 @@ export function renderCard(card, options) {
29
29
  function heading(card, style) {
30
30
  const after = card.test === undefined ? describeFileProblem(card.fileProblem) : formatDuration(card.test.durationMs);
31
31
  const variant = card.variant === undefined ? '' : ` ${style.cyan(card.variant)}`;
32
- return ` ${style.red('✗')} ${style.bold(card.title)}${variant} ${style.dim(after)}`;
32
+ return ` ${style.red(style.marks.failed)} ${style.bold(card.title)}${variant} ${style.dim(after)}`;
33
33
  }
34
34
  // The failure first, then each other host check that failed, then the host checks that never ran.
35
35
  function summary(card, style) {
@@ -1,10 +1,12 @@
1
1
  import type { ChildOutput } from '../runner/contract.ts';
2
2
  import type { Reporter } from './reporter.ts';
3
- import { type Writer } from './style.ts';
3
+ import { type Marks, type Writer } from './style.ts';
4
4
  export type HumanReporterOptions = {
5
5
  stdout: Writer;
6
6
  stderr: Writer;
7
7
  color: boolean;
8
+ /** The marks the terminal draws for a pass and a failure; the glyphs when absent. */
9
+ marks?: Marks;
8
10
  /** The run folder as the person gave it, used in printed paths and commands. */
9
11
  runFolder: string;
10
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"human.d.ts","sourceRoot":"","sources":["../../src/reporters/human.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAsC7C,OAAO,EAA0C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAYhF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAAA;AAE9E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA0GhF"}
1
+ {"version":3,"file":"human.d.ts","sourceRoot":"","sources":["../../src/reporters/human.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAsC7C,OAAO,EAA8B,KAAK,KAAK,EAAc,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAY5F,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,qFAAqF;IACrF,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;CAAE,CAAA;AAE9E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA0GhF"}
@@ -16,7 +16,7 @@ import { acrossTargets, describeBrowser, describeProxy, runTargets, targetSummar
16
16
  * @example runFiles(options, [createHumanReporter({ stdout, stderr, color: true, runFolder })])
17
17
  */
18
18
  export function createHumanReporter(options) {
19
- const style = createStyle(options.color);
19
+ const style = createStyle(options.color, options.marks);
20
20
  const record = new RunRecord();
21
21
  const echo = createChildEcho({ stdout: options.stdout, stderr: options.stderr, style });
22
22
  const write = (text) => {
@@ -61,7 +61,7 @@ export function createHumanReporter(options) {
61
61
  return;
62
62
  case 'app.failed':
63
63
  head();
64
- write(` ${style.red('✗')} ${event.app} ${style.dim(describeAppEvent(event))}\n`);
64
+ write(` ${style.red(style.marks.failed)} ${event.app} ${style.dim(describeAppEvent(event))}\n`);
65
65
  return;
66
66
  case 'collection.completed':
67
67
  head();
@@ -69,11 +69,11 @@ export function createHumanReporter(options) {
69
69
  return;
70
70
  case 'collection.failed':
71
71
  head();
72
- write(`\n ${style.red('✗')} ${style.bold(event.file)} ${style.dim(describeFileProblem('collection'))}\n`);
72
+ write(`\n ${style.red(style.marks.failed)} ${style.bold(event.file)} ${style.dim(describeFileProblem('collection'))}\n`);
73
73
  return;
74
74
  case 'file.failed':
75
75
  head();
76
- write(` ${style.red('✗')} ${style.bold(event.file)} ${style.dim(describeFileProblem('process'))}\n`);
76
+ write(` ${style.red(style.marks.failed)} ${style.bold(event.file)} ${style.dim(describeFileProblem('process'))}\n`);
77
77
  return;
78
78
  case 'test.finished': {
79
79
  head();
@@ -142,8 +142,8 @@ function browserLine(browser) {
142
142
  function testLines(event, test, context) {
143
143
  const { style } = context;
144
144
  const marks = {
145
- passed: style.green('✓'),
146
- failed: style.red('✗'),
145
+ passed: style.green(style.marks.passed),
146
+ failed: style.red(style.marks.failed),
147
147
  error: style.yellow('!'),
148
148
  not_run: style.dim('-'),
149
149
  inconclusive: style.yellow('?'),
@@ -268,12 +268,12 @@ function targetLines(summaries, style) {
268
268
  function targetMark(summary, style) {
269
269
  const { counts } = summary;
270
270
  if (counts.failed > 0)
271
- return style.red('✗');
271
+ return style.red(style.marks.failed);
272
272
  if (counts.error > 0 || counts.notRun > 0)
273
273
  return style.yellow('!');
274
274
  if (counts.inconclusive > 0)
275
275
  return style.yellow('?');
276
- return style.green('✓');
276
+ return style.green(style.marks.passed);
277
277
  }
278
278
  function fileProblemCounts(result) {
279
279
  const problems = result.files.map(fileProblemOf);
@@ -1,4 +1,22 @@
1
1
  export type Paint = (text: string) => string;
2
+ /**
3
+ * The marks a report draws for something that passed or failed, for a step that starts, and in place of a line break
4
+ * kept on one line.
5
+ */
6
+ export type Marks = {
7
+ passed: string;
8
+ failed: string;
9
+ step: string;
10
+ lineBreak: string;
11
+ };
12
+ /** The marks a terminal with the glyphs draws, and every report that is not written to a terminal. */
13
+ export declare const unicodeMarks: Marks;
14
+ /**
15
+ * The marks for a Windows console whose fonts lack the glyphs. Consolas and Lucida Console, the fonts of the console
16
+ * host behind cmd.exe and PowerShell, have no ✓, ✗ or ⏎, Lucida Console has no ▸, and that console draws a box for a
17
+ * glyph its font lacks; both fonts have √, ×, ► and ¶.
18
+ */
19
+ export declare const consoleMarks: Marks;
2
20
  export type Style = {
3
21
  bold: Paint;
4
22
  dim: Paint;
@@ -6,17 +24,18 @@ export type Style = {
6
24
  green: Paint;
7
25
  yellow: Paint;
8
26
  cyan: Paint;
27
+ marks: Marks;
9
28
  };
10
29
  /** Something text can be written to, such as `process.stdout`. */
11
30
  export type Writer = {
12
31
  write(text: string): unknown;
13
32
  };
14
33
  /**
15
- * ANSI styles, or plain text when `enabled` is false.
34
+ * ANSI styles, or plain text when `enabled` is false, with the marks the terminal draws.
16
35
  *
17
36
  * @example createStyle(false).red('failed') // 'failed'
18
37
  */
19
- export declare function createStyle(enabled: boolean): Style;
38
+ export declare function createStyle(enabled: boolean, marks?: Marks): Style;
20
39
  /** The length of text as a terminal shows it, without colour codes. */
21
40
  export declare function visibleLength(text: string): number;
22
41
  //# sourceMappingURL=style.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/reporters/style.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;AAE5C,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,KAAK,CAAA;IACX,GAAG,EAAE,KAAK,CAAA;IACV,GAAG,EAAE,KAAK,CAAA;IACV,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,KAAK,CAAA;IACb,IAAI,EAAE,KAAK,CAAA;CACZ,CAAA;AAED,kEAAkE;AAClE,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAErD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,CAWnD;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/reporters/style.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;AAE5C;;;GAGG;AACH,MAAM,MAAM,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvF,sGAAsG;AACtG,eAAO,MAAM,YAAY,EAAE,KAA+D,CAAA;AAE1F;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,KAA+D,CAAA;AAE1F,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,KAAK,CAAA;IACX,GAAG,EAAE,KAAK,CAAA;IACV,GAAG,EAAE,KAAK,CAAA;IACV,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,KAAK,CAAA;IACb,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,KAAK,CAAA;CACb,CAAA;AAED,kEAAkE;AAClE,MAAM,MAAM,MAAM,GAAG;IAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAErD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,GAAE,KAAoB,GAAG,KAAK,CAYhF;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
@@ -1,9 +1,17 @@
1
+ /** The marks a terminal with the glyphs draws, and every report that is not written to a terminal. */
2
+ export const unicodeMarks = { passed: '✓', failed: '✗', step: '▸', lineBreak: '⏎' };
1
3
  /**
2
- * ANSI styles, or plain text when `enabled` is false.
4
+ * The marks for a Windows console whose fonts lack the glyphs. Consolas and Lucida Console, the fonts of the console
5
+ * host behind cmd.exe and PowerShell, have no ✓, ✗ or ⏎, Lucida Console has no ▸, and that console draws a box for a
6
+ * glyph its font lacks; both fonts have √, ×, ► and ¶.
7
+ */
8
+ export const consoleMarks = { passed: '√', failed: '×', step: '►', lineBreak: '¶' };
9
+ /**
10
+ * ANSI styles, or plain text when `enabled` is false, with the marks the terminal draws.
3
11
  *
4
12
  * @example createStyle(false).red('failed') // 'failed'
5
13
  */
6
- export function createStyle(enabled) {
14
+ export function createStyle(enabled, marks = unicodeMarks) {
7
15
  const paint = (open, close) => enabled ? (text) => `\u001b[${open}m${text}\u001b[${close}m` : (text) => text;
8
16
  return {
9
17
  bold: paint(1, 22),
@@ -12,6 +20,7 @@ export function createStyle(enabled) {
12
20
  green: paint(32, 39),
13
21
  yellow: paint(33, 39),
14
22
  cyan: paint(36, 39),
23
+ marks,
15
24
  };
16
25
  }
17
26
  /** The length of text as a terminal shows it, without colour codes. */