doc-detective 4.26.8 → 4.27.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 (71) hide show
  1. package/dist/common/src/schemas/schemas.json +522 -64
  2. package/dist/common/src/types/generated/config_v3.d.ts +10 -2
  3. package/dist/common/src/types/generated/config_v3.d.ts.map +1 -1
  4. package/dist/common/src/types/generated/resolvedTests_v3.d.ts +10 -2
  5. package/dist/common/src/types/generated/resolvedTests_v3.d.ts.map +1 -1
  6. package/dist/common/src/types/generated/runShell_v3.d.ts +6 -2
  7. package/dist/common/src/types/generated/runShell_v3.d.ts.map +1 -1
  8. package/dist/common/src/types/generated/step_v3.d.ts +6 -2
  9. package/dist/common/src/types/generated/step_v3.d.ts.map +1 -1
  10. package/dist/common/src/types/generated/test_v3.d.ts +12 -4
  11. package/dist/common/src/types/generated/test_v3.d.ts.map +1 -1
  12. package/dist/core/index.d.ts.map +1 -1
  13. package/dist/core/index.js +20 -1
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/tests/processSurface.d.ts +1 -0
  16. package/dist/core/tests/processSurface.d.ts.map +1 -1
  17. package/dist/core/tests/processSurface.js +2 -0
  18. package/dist/core/tests/processSurface.js.map +1 -1
  19. package/dist/core/tests/runCode.d.ts.map +1 -1
  20. package/dist/core/tests/runCode.js +61 -14
  21. package/dist/core/tests/runCode.js.map +1 -1
  22. package/dist/core/tests/runShell.d.ts.map +1 -1
  23. package/dist/core/tests/runShell.js +20 -2
  24. package/dist/core/tests/runShell.js.map +1 -1
  25. package/dist/core/tests/startSurface.d.ts.map +1 -1
  26. package/dist/core/tests/startSurface.js +29 -14
  27. package/dist/core/tests/startSurface.js.map +1 -1
  28. package/dist/core/utils.d.ts +20 -1
  29. package/dist/core/utils.d.ts.map +1 -1
  30. package/dist/core/utils.js +169 -18
  31. package/dist/core/utils.js.map +1 -1
  32. package/dist/hints/context.d.ts +1 -0
  33. package/dist/hints/context.d.ts.map +1 -1
  34. package/dist/hints/context.js +11 -0
  35. package/dist/hints/context.js.map +1 -1
  36. package/dist/hints/hints.d.ts.map +1 -1
  37. package/dist/hints/hints.js +22 -0
  38. package/dist/hints/hints.js.map +1 -1
  39. package/dist/hints/types.d.ts +7 -0
  40. package/dist/hints/types.d.ts.map +1 -1
  41. package/dist/index.cjs +1570 -616
  42. package/dist/runtime/androidInstaller.d.ts.map +1 -1
  43. package/dist/runtime/androidInstaller.js +1 -62
  44. package/dist/runtime/androidInstaller.js.map +1 -1
  45. package/dist/runtime/archiveUtils.d.ts +3 -0
  46. package/dist/runtime/archiveUtils.d.ts.map +1 -0
  47. package/dist/runtime/archiveUtils.js +100 -0
  48. package/dist/runtime/archiveUtils.js.map +1 -0
  49. package/dist/runtime/cacheDir.d.ts +5 -0
  50. package/dist/runtime/cacheDir.d.ts.map +1 -1
  51. package/dist/runtime/cacheDir.js +3 -0
  52. package/dist/runtime/cacheDir.js.map +1 -1
  53. package/dist/runtime/inferRuntimeNeeds.d.ts +5 -1
  54. package/dist/runtime/inferRuntimeNeeds.d.ts.map +1 -1
  55. package/dist/runtime/inferRuntimeNeeds.js +38 -2
  56. package/dist/runtime/inferRuntimeNeeds.js.map +1 -1
  57. package/dist/runtime/installCommand.d.ts.map +1 -1
  58. package/dist/runtime/installCommand.js +32 -3
  59. package/dist/runtime/installCommand.js.map +1 -1
  60. package/dist/runtime/installer.d.ts +2 -2
  61. package/dist/runtime/installer.d.ts.map +1 -1
  62. package/dist/runtime/installer.js +42 -5
  63. package/dist/runtime/installer.js.map +1 -1
  64. package/dist/runtime/windowsBash.d.ts +41 -0
  65. package/dist/runtime/windowsBash.d.ts.map +1 -0
  66. package/dist/runtime/windowsBash.js +386 -0
  67. package/dist/runtime/windowsBash.js.map +1 -0
  68. package/dist/utils.d.ts.map +1 -1
  69. package/dist/utils.js +17 -0
  70. package/dist/utils.js.map +1 -1
  71. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -22409,7 +22409,7 @@ var init_schemas = __esm({
22409
22409
  anyOf: [
22410
22410
  {
22411
22411
  title: "Run shell command (simple)",
22412
- description: "Command to perform in the machine's default shell.",
22412
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
22413
22413
  type: "string",
22414
22414
  transform: [
22415
22415
  "trim"
@@ -22424,7 +22424,16 @@ var init_schemas = __esm({
22424
22424
  properties: {
22425
22425
  command: {
22426
22426
  type: "string",
22427
- description: "Command to perform in the machine's default shell."
22427
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
22428
+ },
22429
+ shell: {
22430
+ type: "string",
22431
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
22432
+ enum: [
22433
+ "bash",
22434
+ "cmd",
22435
+ "powershell"
22436
+ ]
22428
22437
  },
22429
22438
  args: {
22430
22439
  type: "array",
@@ -22551,7 +22560,7 @@ var init_schemas = __esm({
22551
22560
  schemas: {
22552
22561
  string: {
22553
22562
  title: "Run shell command (simple)",
22554
- description: "Command to perform in the machine's default shell.",
22563
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
22555
22564
  type: "string",
22556
22565
  transform: [
22557
22566
  "trim"
@@ -22566,7 +22575,16 @@ var init_schemas = __esm({
22566
22575
  properties: {
22567
22576
  command: {
22568
22577
  type: "string",
22569
- description: "Command to perform in the machine's default shell."
22578
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
22579
+ },
22580
+ shell: {
22581
+ type: "string",
22582
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
22583
+ enum: [
22584
+ "bash",
22585
+ "cmd",
22586
+ "powershell"
22587
+ ]
22570
22588
  },
22571
22589
  args: {
22572
22590
  type: "array",
@@ -22692,6 +22710,15 @@ var init_schemas = __esm({
22692
22710
  },
22693
22711
  examples: [
22694
22712
  "docker run hello-world",
22713
+ {
22714
+ command: "echo %USERNAME%",
22715
+ shell: "cmd"
22716
+ },
22717
+ {
22718
+ command: '[[ "ok" == o* ]] && echo bashism',
22719
+ shell: "bash",
22720
+ stdio: "bashism"
22721
+ },
22695
22722
  {
22696
22723
  command: "echo",
22697
22724
  args: [
@@ -48079,7 +48106,7 @@ var init_schemas = __esm({
48079
48106
  anyOf: [
48080
48107
  {
48081
48108
  title: "Run shell command (simple)",
48082
- description: "Command to perform in the machine's default shell.",
48109
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
48083
48110
  type: "string",
48084
48111
  transform: [
48085
48112
  "trim"
@@ -48094,7 +48121,16 @@ var init_schemas = __esm({
48094
48121
  properties: {
48095
48122
  command: {
48096
48123
  type: "string",
48097
- description: "Command to perform in the machine's default shell."
48124
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
48125
+ },
48126
+ shell: {
48127
+ type: "string",
48128
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
48129
+ enum: [
48130
+ "bash",
48131
+ "cmd",
48132
+ "powershell"
48133
+ ]
48098
48134
  },
48099
48135
  args: {
48100
48136
  type: "array",
@@ -48221,7 +48257,7 @@ var init_schemas = __esm({
48221
48257
  schemas: {
48222
48258
  string: {
48223
48259
  title: "Run shell command (simple)",
48224
- description: "Command to perform in the machine's default shell.",
48260
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
48225
48261
  type: "string",
48226
48262
  transform: [
48227
48263
  "trim"
@@ -48236,7 +48272,16 @@ var init_schemas = __esm({
48236
48272
  properties: {
48237
48273
  command: {
48238
48274
  type: "string",
48239
- description: "Command to perform in the machine's default shell."
48275
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
48276
+ },
48277
+ shell: {
48278
+ type: "string",
48279
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
48280
+ enum: [
48281
+ "bash",
48282
+ "cmd",
48283
+ "powershell"
48284
+ ]
48240
48285
  },
48241
48286
  args: {
48242
48287
  type: "array",
@@ -48362,6 +48407,15 @@ var init_schemas = __esm({
48362
48407
  },
48363
48408
  examples: [
48364
48409
  "docker run hello-world",
48410
+ {
48411
+ command: "echo %USERNAME%",
48412
+ shell: "cmd"
48413
+ },
48414
+ {
48415
+ command: '[[ "ok" == o* ]] && echo bashism',
48416
+ shell: "bash",
48417
+ stdio: "bashism"
48418
+ },
48365
48419
  {
48366
48420
  command: "echo",
48367
48421
  args: [
@@ -48863,6 +48917,16 @@ var init_schemas = __esm({
48863
48917
  type: "boolean",
48864
48918
  default: true
48865
48919
  },
48920
+ shell: {
48921
+ description: "Default shell for `runShell` steps (and `runCode`'s shell-based execution). `runShell` steps can override this value with their own `shell` field. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
48922
+ type: "string",
48923
+ enum: [
48924
+ "bash",
48925
+ "cmd",
48926
+ "powershell"
48927
+ ],
48928
+ default: "bash"
48929
+ },
48866
48930
  cacheDir: {
48867
48931
  description: "Directory for lazy-installed runtime assets (heavy npm packages, browser binaries, ffmpeg). Defaults to `<os.tmpdir()>/doc-detective/`. Override here, with the `DOC_DETECTIVE_CACHE_DIR` env var, or with `--cache-dir` on the CLI when the default temp location is unsuitable (e.g., baked container images where temp gets cleared on reboot).",
48868
48932
  type: "string",
@@ -67984,7 +68048,7 @@ var init_schemas = __esm({
67984
68048
  anyOf: [
67985
68049
  {
67986
68050
  title: "Run shell command (simple)",
67987
- description: "Command to perform in the machine's default shell.",
68051
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
67988
68052
  type: "string",
67989
68053
  transform: [
67990
68054
  "trim"
@@ -67999,7 +68063,16 @@ var init_schemas = __esm({
67999
68063
  properties: {
68000
68064
  command: {
68001
68065
  type: "string",
68002
- description: "Command to perform in the machine's default shell."
68066
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
68067
+ },
68068
+ shell: {
68069
+ type: "string",
68070
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
68071
+ enum: [
68072
+ "bash",
68073
+ "cmd",
68074
+ "powershell"
68075
+ ]
68003
68076
  },
68004
68077
  args: {
68005
68078
  type: "array",
@@ -68126,7 +68199,7 @@ var init_schemas = __esm({
68126
68199
  schemas: {
68127
68200
  string: {
68128
68201
  title: "Run shell command (simple)",
68129
- description: "Command to perform in the machine's default shell.",
68202
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
68130
68203
  type: "string",
68131
68204
  transform: [
68132
68205
  "trim"
@@ -68141,7 +68214,16 @@ var init_schemas = __esm({
68141
68214
  properties: {
68142
68215
  command: {
68143
68216
  type: "string",
68144
- description: "Command to perform in the machine's default shell."
68217
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
68218
+ },
68219
+ shell: {
68220
+ type: "string",
68221
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
68222
+ enum: [
68223
+ "bash",
68224
+ "cmd",
68225
+ "powershell"
68226
+ ]
68145
68227
  },
68146
68228
  args: {
68147
68229
  type: "array",
@@ -68267,6 +68349,15 @@ var init_schemas = __esm({
68267
68349
  },
68268
68350
  examples: [
68269
68351
  "docker run hello-world",
68352
+ {
68353
+ command: "echo %USERNAME%",
68354
+ shell: "cmd"
68355
+ },
68356
+ {
68357
+ command: '[[ "ok" == o* ]] && echo bashism',
68358
+ shell: "bash",
68359
+ stdio: "bashism"
68360
+ },
68270
68361
  {
68271
68362
  command: "echo",
68272
68363
  args: [
@@ -93754,6 +93845,9 @@ var init_schemas = __esm({
93754
93845
  },
93755
93846
  examples: [
93756
93847
  {},
93848
+ {
93849
+ shell: "powershell"
93850
+ },
93757
93851
  {
93758
93852
  input: ".",
93759
93853
  output: ".",
@@ -126880,7 +126974,7 @@ var init_schemas = __esm({
126880
126974
  anyOf: [
126881
126975
  {
126882
126976
  title: "Run shell command (simple)",
126883
- description: "Command to perform in the machine's default shell.",
126977
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
126884
126978
  type: "string",
126885
126979
  transform: [
126886
126980
  "trim"
@@ -126895,7 +126989,16 @@ var init_schemas = __esm({
126895
126989
  properties: {
126896
126990
  command: {
126897
126991
  type: "string",
126898
- description: "Command to perform in the machine's default shell."
126992
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
126993
+ },
126994
+ shell: {
126995
+ type: "string",
126996
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
126997
+ enum: [
126998
+ "bash",
126999
+ "cmd",
127000
+ "powershell"
127001
+ ]
126899
127002
  },
126900
127003
  args: {
126901
127004
  type: "array",
@@ -127022,7 +127125,7 @@ var init_schemas = __esm({
127022
127125
  schemas: {
127023
127126
  string: {
127024
127127
  title: "Run shell command (simple)",
127025
- description: "Command to perform in the machine's default shell.",
127128
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
127026
127129
  type: "string",
127027
127130
  transform: [
127028
127131
  "trim"
@@ -127037,7 +127140,16 @@ var init_schemas = __esm({
127037
127140
  properties: {
127038
127141
  command: {
127039
127142
  type: "string",
127040
- description: "Command to perform in the machine's default shell."
127143
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
127144
+ },
127145
+ shell: {
127146
+ type: "string",
127147
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
127148
+ enum: [
127149
+ "bash",
127150
+ "cmd",
127151
+ "powershell"
127152
+ ]
127041
127153
  },
127042
127154
  args: {
127043
127155
  type: "array",
@@ -127163,6 +127275,15 @@ var init_schemas = __esm({
127163
127275
  },
127164
127276
  examples: [
127165
127277
  "docker run hello-world",
127278
+ {
127279
+ command: "echo %USERNAME%",
127280
+ shell: "cmd"
127281
+ },
127282
+ {
127283
+ command: '[[ "ok" == o* ]] && echo bashism',
127284
+ shell: "bash",
127285
+ stdio: "bashism"
127286
+ },
127166
127287
  {
127167
127288
  command: "echo",
127168
127289
  args: [
@@ -152550,7 +152671,7 @@ var init_schemas = __esm({
152550
152671
  anyOf: [
152551
152672
  {
152552
152673
  title: "Run shell command (simple)",
152553
- description: "Command to perform in the machine's default shell.",
152674
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
152554
152675
  type: "string",
152555
152676
  transform: [
152556
152677
  "trim"
@@ -152565,7 +152686,16 @@ var init_schemas = __esm({
152565
152686
  properties: {
152566
152687
  command: {
152567
152688
  type: "string",
152568
- description: "Command to perform in the machine's default shell."
152689
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
152690
+ },
152691
+ shell: {
152692
+ type: "string",
152693
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
152694
+ enum: [
152695
+ "bash",
152696
+ "cmd",
152697
+ "powershell"
152698
+ ]
152569
152699
  },
152570
152700
  args: {
152571
152701
  type: "array",
@@ -152692,7 +152822,7 @@ var init_schemas = __esm({
152692
152822
  schemas: {
152693
152823
  string: {
152694
152824
  title: "Run shell command (simple)",
152695
- description: "Command to perform in the machine's default shell.",
152825
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
152696
152826
  type: "string",
152697
152827
  transform: [
152698
152828
  "trim"
@@ -152707,7 +152837,16 @@ var init_schemas = __esm({
152707
152837
  properties: {
152708
152838
  command: {
152709
152839
  type: "string",
152710
- description: "Command to perform in the machine's default shell."
152840
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
152841
+ },
152842
+ shell: {
152843
+ type: "string",
152844
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
152845
+ enum: [
152846
+ "bash",
152847
+ "cmd",
152848
+ "powershell"
152849
+ ]
152711
152850
  },
152712
152851
  args: {
152713
152852
  type: "array",
@@ -152833,6 +152972,15 @@ var init_schemas = __esm({
152833
152972
  },
152834
152973
  examples: [
152835
152974
  "docker run hello-world",
152975
+ {
152976
+ command: "echo %USERNAME%",
152977
+ shell: "cmd"
152978
+ },
152979
+ {
152980
+ command: '[[ "ok" == o* ]] && echo bashism',
152981
+ shell: "bash",
152982
+ stdio: "bashism"
152983
+ },
152836
152984
  {
152837
152985
  command: "echo",
152838
152986
  args: [
@@ -153334,6 +153482,16 @@ var init_schemas = __esm({
153334
153482
  type: "boolean",
153335
153483
  default: true
153336
153484
  },
153485
+ shell: {
153486
+ description: "Default shell for `runShell` steps (and `runCode`'s shell-based execution). `runShell` steps can override this value with their own `shell` field. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
153487
+ type: "string",
153488
+ enum: [
153489
+ "bash",
153490
+ "cmd",
153491
+ "powershell"
153492
+ ],
153493
+ default: "bash"
153494
+ },
153337
153495
  cacheDir: {
153338
153496
  description: "Directory for lazy-installed runtime assets (heavy npm packages, browser binaries, ffmpeg). Defaults to `<os.tmpdir()>/doc-detective/`. Override here, with the `DOC_DETECTIVE_CACHE_DIR` env var, or with `--cache-dir` on the CLI when the default temp location is unsuitable (e.g., baked container images where temp gets cleared on reboot).",
153339
153497
  type: "string",
@@ -172455,7 +172613,7 @@ var init_schemas = __esm({
172455
172613
  anyOf: [
172456
172614
  {
172457
172615
  title: "Run shell command (simple)",
172458
- description: "Command to perform in the machine's default shell.",
172616
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
172459
172617
  type: "string",
172460
172618
  transform: [
172461
172619
  "trim"
@@ -172470,7 +172628,16 @@ var init_schemas = __esm({
172470
172628
  properties: {
172471
172629
  command: {
172472
172630
  type: "string",
172473
- description: "Command to perform in the machine's default shell."
172631
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
172632
+ },
172633
+ shell: {
172634
+ type: "string",
172635
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
172636
+ enum: [
172637
+ "bash",
172638
+ "cmd",
172639
+ "powershell"
172640
+ ]
172474
172641
  },
172475
172642
  args: {
172476
172643
  type: "array",
@@ -172597,7 +172764,7 @@ var init_schemas = __esm({
172597
172764
  schemas: {
172598
172765
  string: {
172599
172766
  title: "Run shell command (simple)",
172600
- description: "Command to perform in the machine's default shell.",
172767
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
172601
172768
  type: "string",
172602
172769
  transform: [
172603
172770
  "trim"
@@ -172612,7 +172779,16 @@ var init_schemas = __esm({
172612
172779
  properties: {
172613
172780
  command: {
172614
172781
  type: "string",
172615
- description: "Command to perform in the machine's default shell."
172782
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
172783
+ },
172784
+ shell: {
172785
+ type: "string",
172786
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
172787
+ enum: [
172788
+ "bash",
172789
+ "cmd",
172790
+ "powershell"
172791
+ ]
172616
172792
  },
172617
172793
  args: {
172618
172794
  type: "array",
@@ -172738,6 +172914,15 @@ var init_schemas = __esm({
172738
172914
  },
172739
172915
  examples: [
172740
172916
  "docker run hello-world",
172917
+ {
172918
+ command: "echo %USERNAME%",
172919
+ shell: "cmd"
172920
+ },
172921
+ {
172922
+ command: '[[ "ok" == o* ]] && echo bashism',
172923
+ shell: "bash",
172924
+ stdio: "bashism"
172925
+ },
172741
172926
  {
172742
172927
  command: "echo",
172743
172928
  args: [
@@ -198225,6 +198410,9 @@ var init_schemas = __esm({
198225
198410
  },
198226
198411
  examples: [
198227
198412
  {},
198413
+ {
198414
+ shell: "powershell"
198415
+ },
198228
198416
  {
198229
198417
  input: ".",
198230
198418
  output: ".",
@@ -219803,7 +219991,7 @@ var init_schemas = __esm({
219803
219991
  anyOf: [
219804
219992
  {
219805
219993
  title: "Run shell command (simple)",
219806
- description: "Command to perform in the machine's default shell.",
219994
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
219807
219995
  type: "string",
219808
219996
  transform: [
219809
219997
  "trim"
@@ -219818,7 +220006,16 @@ var init_schemas = __esm({
219818
220006
  properties: {
219819
220007
  command: {
219820
220008
  type: "string",
219821
- description: "Command to perform in the machine's default shell."
220009
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
220010
+ },
220011
+ shell: {
220012
+ type: "string",
220013
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
220014
+ enum: [
220015
+ "bash",
220016
+ "cmd",
220017
+ "powershell"
220018
+ ]
219822
220019
  },
219823
220020
  args: {
219824
220021
  type: "array",
@@ -219945,7 +220142,7 @@ var init_schemas = __esm({
219945
220142
  schemas: {
219946
220143
  string: {
219947
220144
  title: "Run shell command (simple)",
219948
- description: "Command to perform in the machine's default shell.",
220145
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
219949
220146
  type: "string",
219950
220147
  transform: [
219951
220148
  "trim"
@@ -219960,7 +220157,16 @@ var init_schemas = __esm({
219960
220157
  properties: {
219961
220158
  command: {
219962
220159
  type: "string",
219963
- description: "Command to perform in the machine's default shell."
220160
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
220161
+ },
220162
+ shell: {
220163
+ type: "string",
220164
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
220165
+ enum: [
220166
+ "bash",
220167
+ "cmd",
220168
+ "powershell"
220169
+ ]
219964
220170
  },
219965
220171
  args: {
219966
220172
  type: "array",
@@ -220086,6 +220292,15 @@ var init_schemas = __esm({
220086
220292
  },
220087
220293
  examples: [
220088
220294
  "docker run hello-world",
220295
+ {
220296
+ command: "echo %USERNAME%",
220297
+ shell: "cmd"
220298
+ },
220299
+ {
220300
+ command: '[[ "ok" == o* ]] && echo bashism',
220301
+ shell: "bash",
220302
+ stdio: "bashism"
220303
+ },
220089
220304
  {
220090
220305
  command: "echo",
220091
220306
  args: [
@@ -264677,7 +264892,7 @@ var init_schemas = __esm({
264677
264892
  anyOf: [
264678
264893
  {
264679
264894
  title: "Run shell command (simple)",
264680
- description: "Command to perform in the machine's default shell.",
264895
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
264681
264896
  type: "string",
264682
264897
  transform: [
264683
264898
  "trim"
@@ -264692,7 +264907,16 @@ var init_schemas = __esm({
264692
264907
  properties: {
264693
264908
  command: {
264694
264909
  type: "string",
264695
- description: "Command to perform in the machine's default shell."
264910
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
264911
+ },
264912
+ shell: {
264913
+ type: "string",
264914
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
264915
+ enum: [
264916
+ "bash",
264917
+ "cmd",
264918
+ "powershell"
264919
+ ]
264696
264920
  },
264697
264921
  args: {
264698
264922
  type: "array",
@@ -264819,7 +265043,7 @@ var init_schemas = __esm({
264819
265043
  schemas: {
264820
265044
  string: {
264821
265045
  title: "Run shell command (simple)",
264822
- description: "Command to perform in the machine's default shell.",
265046
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
264823
265047
  type: "string",
264824
265048
  transform: [
264825
265049
  "trim"
@@ -264834,7 +265058,16 @@ var init_schemas = __esm({
264834
265058
  properties: {
264835
265059
  command: {
264836
265060
  type: "string",
264837
- description: "Command to perform in the machine's default shell."
265061
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
265062
+ },
265063
+ shell: {
265064
+ type: "string",
265065
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
265066
+ enum: [
265067
+ "bash",
265068
+ "cmd",
265069
+ "powershell"
265070
+ ]
264838
265071
  },
264839
265072
  args: {
264840
265073
  type: "array",
@@ -264960,6 +265193,15 @@ var init_schemas = __esm({
264960
265193
  },
264961
265194
  examples: [
264962
265195
  "docker run hello-world",
265196
+ {
265197
+ command: "echo %USERNAME%",
265198
+ shell: "cmd"
265199
+ },
265200
+ {
265201
+ command: '[[ "ok" == o* ]] && echo bashism',
265202
+ shell: "bash",
265203
+ stdio: "bashism"
265204
+ },
264963
265205
  {
264964
265206
  command: "echo",
264965
265207
  args: [
@@ -312512,7 +312754,7 @@ var init_schemas = __esm({
312512
312754
  anyOf: [
312513
312755
  {
312514
312756
  title: "Run shell command (simple)",
312515
- description: "Command to perform in the machine's default shell.",
312757
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
312516
312758
  type: "string",
312517
312759
  transform: [
312518
312760
  "trim"
@@ -312527,7 +312769,16 @@ var init_schemas = __esm({
312527
312769
  properties: {
312528
312770
  command: {
312529
312771
  type: "string",
312530
- description: "Command to perform in the machine's default shell."
312772
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
312773
+ },
312774
+ shell: {
312775
+ type: "string",
312776
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
312777
+ enum: [
312778
+ "bash",
312779
+ "cmd",
312780
+ "powershell"
312781
+ ]
312531
312782
  },
312532
312783
  args: {
312533
312784
  type: "array",
@@ -312654,7 +312905,7 @@ var init_schemas = __esm({
312654
312905
  schemas: {
312655
312906
  string: {
312656
312907
  title: "Run shell command (simple)",
312657
- description: "Command to perform in the machine's default shell.",
312908
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
312658
312909
  type: "string",
312659
312910
  transform: [
312660
312911
  "trim"
@@ -312669,7 +312920,16 @@ var init_schemas = __esm({
312669
312920
  properties: {
312670
312921
  command: {
312671
312922
  type: "string",
312672
- description: "Command to perform in the machine's default shell."
312923
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
312924
+ },
312925
+ shell: {
312926
+ type: "string",
312927
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
312928
+ enum: [
312929
+ "bash",
312930
+ "cmd",
312931
+ "powershell"
312932
+ ]
312673
312933
  },
312674
312934
  args: {
312675
312935
  type: "array",
@@ -312795,6 +313055,15 @@ var init_schemas = __esm({
312795
313055
  },
312796
313056
  examples: [
312797
313057
  "docker run hello-world",
313058
+ {
313059
+ command: "echo %USERNAME%",
313060
+ shell: "cmd"
313061
+ },
313062
+ {
313063
+ command: '[[ "ok" == o* ]] && echo bashism',
313064
+ shell: "bash",
313065
+ stdio: "bashism"
313066
+ },
312798
313067
  {
312799
313068
  command: "echo",
312800
313069
  args: [
@@ -357386,7 +357655,7 @@ var init_schemas = __esm({
357386
357655
  anyOf: [
357387
357656
  {
357388
357657
  title: "Run shell command (simple)",
357389
- description: "Command to perform in the machine's default shell.",
357658
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
357390
357659
  type: "string",
357391
357660
  transform: [
357392
357661
  "trim"
@@ -357401,7 +357670,16 @@ var init_schemas = __esm({
357401
357670
  properties: {
357402
357671
  command: {
357403
357672
  type: "string",
357404
- description: "Command to perform in the machine's default shell."
357673
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
357674
+ },
357675
+ shell: {
357676
+ type: "string",
357677
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
357678
+ enum: [
357679
+ "bash",
357680
+ "cmd",
357681
+ "powershell"
357682
+ ]
357405
357683
  },
357406
357684
  args: {
357407
357685
  type: "array",
@@ -357528,7 +357806,7 @@ var init_schemas = __esm({
357528
357806
  schemas: {
357529
357807
  string: {
357530
357808
  title: "Run shell command (simple)",
357531
- description: "Command to perform in the machine's default shell.",
357809
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
357532
357810
  type: "string",
357533
357811
  transform: [
357534
357812
  "trim"
@@ -357543,7 +357821,16 @@ var init_schemas = __esm({
357543
357821
  properties: {
357544
357822
  command: {
357545
357823
  type: "string",
357546
- description: "Command to perform in the machine's default shell."
357824
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
357825
+ },
357826
+ shell: {
357827
+ type: "string",
357828
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
357829
+ enum: [
357830
+ "bash",
357831
+ "cmd",
357832
+ "powershell"
357833
+ ]
357547
357834
  },
357548
357835
  args: {
357549
357836
  type: "array",
@@ -357669,6 +357956,15 @@ var init_schemas = __esm({
357669
357956
  },
357670
357957
  examples: [
357671
357958
  "docker run hello-world",
357959
+ {
357960
+ command: "echo %USERNAME%",
357961
+ shell: "cmd"
357962
+ },
357963
+ {
357964
+ command: '[[ "ok" == o* ]] && echo bashism',
357965
+ shell: "bash",
357966
+ stdio: "bashism"
357967
+ },
357672
357968
  {
357673
357969
  command: "echo",
357674
357970
  args: [
@@ -384714,7 +385010,7 @@ var init_schemas = __esm({
384714
385010
  anyOf: [
384715
385011
  {
384716
385012
  title: "Run shell command (simple)",
384717
- description: "Command to perform in the machine's default shell.",
385013
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
384718
385014
  type: "string",
384719
385015
  transform: [
384720
385016
  "trim"
@@ -384729,7 +385025,16 @@ var init_schemas = __esm({
384729
385025
  properties: {
384730
385026
  command: {
384731
385027
  type: "string",
384732
- description: "Command to perform in the machine's default shell."
385028
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
385029
+ },
385030
+ shell: {
385031
+ type: "string",
385032
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
385033
+ enum: [
385034
+ "bash",
385035
+ "cmd",
385036
+ "powershell"
385037
+ ]
384733
385038
  },
384734
385039
  args: {
384735
385040
  type: "array",
@@ -384856,7 +385161,7 @@ var init_schemas = __esm({
384856
385161
  schemas: {
384857
385162
  string: {
384858
385163
  title: "Run shell command (simple)",
384859
- description: "Command to perform in the machine's default shell.",
385164
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
384860
385165
  type: "string",
384861
385166
  transform: [
384862
385167
  "trim"
@@ -384871,7 +385176,16 @@ var init_schemas = __esm({
384871
385176
  properties: {
384872
385177
  command: {
384873
385178
  type: "string",
384874
- description: "Command to perform in the machine's default shell."
385179
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
385180
+ },
385181
+ shell: {
385182
+ type: "string",
385183
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
385184
+ enum: [
385185
+ "bash",
385186
+ "cmd",
385187
+ "powershell"
385188
+ ]
384875
385189
  },
384876
385190
  args: {
384877
385191
  type: "array",
@@ -384997,6 +385311,15 @@ var init_schemas = __esm({
384997
385311
  },
384998
385312
  examples: [
384999
385313
  "docker run hello-world",
385314
+ {
385315
+ command: "echo %USERNAME%",
385316
+ shell: "cmd"
385317
+ },
385318
+ {
385319
+ command: '[[ "ok" == o* ]] && echo bashism',
385320
+ shell: "bash",
385321
+ stdio: "bashism"
385322
+ },
385000
385323
  {
385001
385324
  command: "echo",
385002
385325
  args: [
@@ -408434,7 +408757,7 @@ var init_schemas = __esm({
408434
408757
  anyOf: [
408435
408758
  {
408436
408759
  title: "Run shell command (simple)",
408437
- description: "Command to perform in the machine's default shell.",
408760
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
408438
408761
  type: "string",
408439
408762
  transform: [
408440
408763
  "trim"
@@ -408449,7 +408772,16 @@ var init_schemas = __esm({
408449
408772
  properties: {
408450
408773
  command: {
408451
408774
  type: "string",
408452
- description: "Command to perform in the machine's default shell."
408775
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
408776
+ },
408777
+ shell: {
408778
+ type: "string",
408779
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
408780
+ enum: [
408781
+ "bash",
408782
+ "cmd",
408783
+ "powershell"
408784
+ ]
408453
408785
  },
408454
408786
  args: {
408455
408787
  type: "array",
@@ -408576,7 +408908,7 @@ var init_schemas = __esm({
408576
408908
  schemas: {
408577
408909
  string: {
408578
408910
  title: "Run shell command (simple)",
408579
- description: "Command to perform in the machine's default shell.",
408911
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
408580
408912
  type: "string",
408581
408913
  transform: [
408582
408914
  "trim"
@@ -408591,7 +408923,16 @@ var init_schemas = __esm({
408591
408923
  properties: {
408592
408924
  command: {
408593
408925
  type: "string",
408594
- description: "Command to perform in the machine's default shell."
408926
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
408927
+ },
408928
+ shell: {
408929
+ type: "string",
408930
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
408931
+ enum: [
408932
+ "bash",
408933
+ "cmd",
408934
+ "powershell"
408935
+ ]
408595
408936
  },
408596
408937
  args: {
408597
408938
  type: "array",
@@ -408717,6 +409058,15 @@ var init_schemas = __esm({
408717
409058
  },
408718
409059
  examples: [
408719
409060
  "docker run hello-world",
409061
+ {
409062
+ command: "echo %USERNAME%",
409063
+ shell: "cmd"
409064
+ },
409065
+ {
409066
+ command: '[[ "ok" == o* ]] && echo bashism',
409067
+ shell: "bash",
409068
+ stdio: "bashism"
409069
+ },
408720
409070
  {
408721
409071
  command: "echo",
408722
409072
  args: [
@@ -453308,7 +453658,7 @@ var init_schemas = __esm({
453308
453658
  anyOf: [
453309
453659
  {
453310
453660
  title: "Run shell command (simple)",
453311
- description: "Command to perform in the machine's default shell.",
453661
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
453312
453662
  type: "string",
453313
453663
  transform: [
453314
453664
  "trim"
@@ -453323,7 +453673,16 @@ var init_schemas = __esm({
453323
453673
  properties: {
453324
453674
  command: {
453325
453675
  type: "string",
453326
- description: "Command to perform in the machine's default shell."
453676
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
453677
+ },
453678
+ shell: {
453679
+ type: "string",
453680
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
453681
+ enum: [
453682
+ "bash",
453683
+ "cmd",
453684
+ "powershell"
453685
+ ]
453327
453686
  },
453328
453687
  args: {
453329
453688
  type: "array",
@@ -453450,7 +453809,7 @@ var init_schemas = __esm({
453450
453809
  schemas: {
453451
453810
  string: {
453452
453811
  title: "Run shell command (simple)",
453453
- description: "Command to perform in the machine's default shell.",
453812
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
453454
453813
  type: "string",
453455
453814
  transform: [
453456
453815
  "trim"
@@ -453465,7 +453824,16 @@ var init_schemas = __esm({
453465
453824
  properties: {
453466
453825
  command: {
453467
453826
  type: "string",
453468
- description: "Command to perform in the machine's default shell."
453827
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
453828
+ },
453829
+ shell: {
453830
+ type: "string",
453831
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
453832
+ enum: [
453833
+ "bash",
453834
+ "cmd",
453835
+ "powershell"
453836
+ ]
453469
453837
  },
453470
453838
  args: {
453471
453839
  type: "array",
@@ -453591,6 +453959,15 @@ var init_schemas = __esm({
453591
453959
  },
453592
453960
  examples: [
453593
453961
  "docker run hello-world",
453962
+ {
453963
+ command: "echo %USERNAME%",
453964
+ shell: "cmd"
453965
+ },
453966
+ {
453967
+ command: '[[ "ok" == o* ]] && echo bashism',
453968
+ shell: "bash",
453969
+ stdio: "bashism"
453970
+ },
453594
453971
  {
453595
453972
  command: "echo",
453596
453973
  args: [
@@ -499874,7 +500251,7 @@ var init_schemas = __esm({
499874
500251
  anyOf: [
499875
500252
  {
499876
500253
  title: "Run shell command (simple)",
499877
- description: "Command to perform in the machine's default shell.",
500254
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
499878
500255
  type: "string",
499879
500256
  transform: [
499880
500257
  "trim"
@@ -499889,7 +500266,16 @@ var init_schemas = __esm({
499889
500266
  properties: {
499890
500267
  command: {
499891
500268
  type: "string",
499892
- description: "Command to perform in the machine's default shell."
500269
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
500270
+ },
500271
+ shell: {
500272
+ type: "string",
500273
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
500274
+ enum: [
500275
+ "bash",
500276
+ "cmd",
500277
+ "powershell"
500278
+ ]
499893
500279
  },
499894
500280
  args: {
499895
500281
  type: "array",
@@ -500016,7 +500402,7 @@ var init_schemas = __esm({
500016
500402
  schemas: {
500017
500403
  string: {
500018
500404
  title: "Run shell command (simple)",
500019
- description: "Command to perform in the machine's default shell.",
500405
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
500020
500406
  type: "string",
500021
500407
  transform: [
500022
500408
  "trim"
@@ -500031,7 +500417,16 @@ var init_schemas = __esm({
500031
500417
  properties: {
500032
500418
  command: {
500033
500419
  type: "string",
500034
- description: "Command to perform in the machine's default shell."
500420
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
500421
+ },
500422
+ shell: {
500423
+ type: "string",
500424
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
500425
+ enum: [
500426
+ "bash",
500427
+ "cmd",
500428
+ "powershell"
500429
+ ]
500035
500430
  },
500036
500431
  args: {
500037
500432
  type: "array",
@@ -500157,6 +500552,15 @@ var init_schemas = __esm({
500157
500552
  },
500158
500553
  examples: [
500159
500554
  "docker run hello-world",
500555
+ {
500556
+ command: "echo %USERNAME%",
500557
+ shell: "cmd"
500558
+ },
500559
+ {
500560
+ command: '[[ "ok" == o* ]] && echo bashism',
500561
+ shell: "bash",
500562
+ stdio: "bashism"
500563
+ },
500160
500564
  {
500161
500565
  command: "echo",
500162
500566
  args: [
@@ -548093,7 +548497,7 @@ var init_schemas = __esm({
548093
548497
  anyOf: [
548094
548498
  {
548095
548499
  title: "Run shell command (simple)",
548096
- description: "Command to perform in the machine's default shell.",
548500
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
548097
548501
  type: "string",
548098
548502
  transform: [
548099
548503
  "trim"
@@ -548108,7 +548512,16 @@ var init_schemas = __esm({
548108
548512
  properties: {
548109
548513
  command: {
548110
548514
  type: "string",
548111
- description: "Command to perform in the machine's default shell."
548515
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
548516
+ },
548517
+ shell: {
548518
+ type: "string",
548519
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
548520
+ enum: [
548521
+ "bash",
548522
+ "cmd",
548523
+ "powershell"
548524
+ ]
548112
548525
  },
548113
548526
  args: {
548114
548527
  type: "array",
@@ -548235,7 +548648,7 @@ var init_schemas = __esm({
548235
548648
  schemas: {
548236
548649
  string: {
548237
548650
  title: "Run shell command (simple)",
548238
- description: "Command to perform in the machine's default shell.",
548651
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
548239
548652
  type: "string",
548240
548653
  transform: [
548241
548654
  "trim"
@@ -548250,7 +548663,16 @@ var init_schemas = __esm({
548250
548663
  properties: {
548251
548664
  command: {
548252
548665
  type: "string",
548253
- description: "Command to perform in the machine's default shell."
548666
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
548667
+ },
548668
+ shell: {
548669
+ type: "string",
548670
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
548671
+ enum: [
548672
+ "bash",
548673
+ "cmd",
548674
+ "powershell"
548675
+ ]
548254
548676
  },
548255
548677
  args: {
548256
548678
  type: "array",
@@ -548376,6 +548798,15 @@ var init_schemas = __esm({
548376
548798
  },
548377
548799
  examples: [
548378
548800
  "docker run hello-world",
548801
+ {
548802
+ command: "echo %USERNAME%",
548803
+ shell: "cmd"
548804
+ },
548805
+ {
548806
+ command: '[[ "ok" == o* ]] && echo bashism',
548807
+ shell: "bash",
548808
+ stdio: "bashism"
548809
+ },
548379
548810
  {
548380
548811
  command: "echo",
548381
548812
  args: [
@@ -592967,7 +593398,7 @@ var init_schemas = __esm({
592967
593398
  anyOf: [
592968
593399
  {
592969
593400
  title: "Run shell command (simple)",
592970
- description: "Command to perform in the machine's default shell.",
593401
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
592971
593402
  type: "string",
592972
593403
  transform: [
592973
593404
  "trim"
@@ -592982,7 +593413,16 @@ var init_schemas = __esm({
592982
593413
  properties: {
592983
593414
  command: {
592984
593415
  type: "string",
592985
- description: "Command to perform in the machine's default shell."
593416
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
593417
+ },
593418
+ shell: {
593419
+ type: "string",
593420
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
593421
+ enum: [
593422
+ "bash",
593423
+ "cmd",
593424
+ "powershell"
593425
+ ]
592986
593426
  },
592987
593427
  args: {
592988
593428
  type: "array",
@@ -593109,7 +593549,7 @@ var init_schemas = __esm({
593109
593549
  schemas: {
593110
593550
  string: {
593111
593551
  title: "Run shell command (simple)",
593112
- description: "Command to perform in the machine's default shell.",
593552
+ description: "Command to perform in the default shell (`bash` on every platform, unless the config-level `shell` setting changes it).",
593113
593553
  type: "string",
593114
593554
  transform: [
593115
593555
  "trim"
@@ -593124,7 +593564,16 @@ var init_schemas = __esm({
593124
593564
  properties: {
593125
593565
  command: {
593126
593566
  type: "string",
593127
- description: "Command to perform in the machine's default shell."
593567
+ description: "Command to perform in the selected shell (see `shell`; defaults to `bash` on every platform)."
593568
+ },
593569
+ shell: {
593570
+ type: "string",
593571
+ description: "Shell to run the command in. If unset, uses the config-level `shell` setting, which defaults to `bash`. `cmd` and `powershell` are only supported on Windows. On Windows, `bash` resolves to Git Bash, which Doc Detective installs automatically if it isn't present.",
593572
+ enum: [
593573
+ "bash",
593574
+ "cmd",
593575
+ "powershell"
593576
+ ]
593128
593577
  },
593129
593578
  args: {
593130
593579
  type: "array",
@@ -593250,6 +593699,15 @@ var init_schemas = __esm({
593250
593699
  },
593251
593700
  examples: [
593252
593701
  "docker run hello-world",
593702
+ {
593703
+ command: "echo %USERNAME%",
593704
+ shell: "cmd"
593705
+ },
593706
+ {
593707
+ command: '[[ "ok" == o* ]] && echo bashism',
593708
+ shell: "bash",
593709
+ stdio: "bashism"
593710
+ },
593253
593711
  {
593254
593712
  command: "echo",
593255
593713
  args: [
@@ -631982,6 +632440,8 @@ function readInstalledRecord(ctx = {}) {
631982
632440
  };
631983
632441
  if (isPlainObject(parsed?.android))
631984
632442
  record.android = parsed.android;
632443
+ if (isPlainObject(parsed?.tools))
632444
+ record.tools = parsed.tools;
631985
632445
  return record;
631986
632446
  } catch {
631987
632447
  return emptyRecord();
@@ -632379,6 +632839,378 @@ var init_loader = __esm({
632379
632839
  }
632380
632840
  });
632381
632841
 
632842
+ // dist/runtime/archiveUtils.js
632843
+ async function downloadFile(url, dest, redirects = 0) {
632844
+ if (redirects > 10)
632845
+ throw new Error(`too many redirects fetching ${url}`);
632846
+ await new Promise((resolve, reject) => {
632847
+ const req = import_node_https.default.get(url, (res) => {
632848
+ const status = res.statusCode ?? 0;
632849
+ if (status >= 300 && status < 400 && res.headers.location) {
632850
+ res.resume();
632851
+ const target = new URL(res.headers.location, url).toString();
632852
+ downloadFile(target, dest, redirects + 1).then(resolve, reject);
632853
+ return;
632854
+ }
632855
+ if (status !== 200) {
632856
+ res.resume();
632857
+ reject(new Error(`download failed (HTTP ${status}) for ${url}`));
632858
+ return;
632859
+ }
632860
+ const file = import_node_fs4.default.createWriteStream(dest);
632861
+ res.pipe(file);
632862
+ file.on("finish", () => file.close(() => resolve()));
632863
+ file.on("error", (error) => {
632864
+ res.destroy();
632865
+ reject(error);
632866
+ });
632867
+ });
632868
+ req.setTimeout(6e4, () => req.destroy(new Error(`download timed out: ${url}`)));
632869
+ req.on("error", reject);
632870
+ });
632871
+ }
632872
+ async function run(cmd, args) {
632873
+ await new Promise((resolve, reject) => {
632874
+ let stderr = "";
632875
+ const child = (0, import_node_child_process2.spawn)(cmd, args, { windowsHide: true });
632876
+ child.stderr?.on("data", (d) => stderr += d.toString());
632877
+ child.on("error", reject);
632878
+ child.on("close", (code) => {
632879
+ if (code === 0)
632880
+ resolve();
632881
+ else
632882
+ reject(new Error(`${cmd} exited with code ${code}: ${stderr.slice(0, 500)}`));
632883
+ });
632884
+ });
632885
+ }
632886
+ async function extractZip(zipPath, destDir) {
632887
+ const attempts = process.platform === "win32" ? [
632888
+ ["tar", ["-xf", zipPath, "-C", destDir]],
632889
+ [
632890
+ "powershell",
632891
+ [
632892
+ "-NoProfile",
632893
+ "-NonInteractive",
632894
+ "-Command",
632895
+ // Escape apostrophes for PS single-quoted literals (doubling)
632896
+ // so a path containing `'` can't break the command parse.
632897
+ `Expand-Archive -LiteralPath '${zipPath.replace(/'/g, "''")}' -DestinationPath '${destDir.replace(/'/g, "''")}' -Force`
632898
+ ]
632899
+ ]
632900
+ ] : [
632901
+ ["unzip", ["-q", "-o", zipPath, "-d", destDir]],
632902
+ ["tar", ["-xf", zipPath, "-C", destDir]]
632903
+ ];
632904
+ let lastError;
632905
+ for (const [cmd, args] of attempts) {
632906
+ try {
632907
+ await run(cmd, args);
632908
+ return;
632909
+ } catch (error) {
632910
+ lastError = error;
632911
+ }
632912
+ }
632913
+ throw new Error(`couldn't extract ${zipPath}: no working zip extractor found (${lastError?.message ?? lastError})`);
632914
+ }
632915
+ var import_node_fs4, import_node_https, import_node_child_process2;
632916
+ var init_archiveUtils = __esm({
632917
+ "dist/runtime/archiveUtils.js"() {
632918
+ "use strict";
632919
+ import_node_fs4 = __toESM(require("node:fs"), 1);
632920
+ import_node_https = __toESM(require("node:https"), 1);
632921
+ import_node_child_process2 = require("node:child_process");
632922
+ }
632923
+ });
632924
+
632925
+ // dist/runtime/windowsBash.js
632926
+ var windowsBash_exports = {};
632927
+ __export(windowsBash_exports, {
632928
+ MINGIT_VERSION: () => MINGIT_VERSION,
632929
+ getCachedBashPath: () => getCachedBashPath,
632930
+ getGitBashDir: () => getGitBashDir,
632931
+ installBash: () => installBash,
632932
+ resolveWindowsBash: () => resolveWindowsBash
632933
+ });
632934
+ function depsWithDefaults(deps) {
632935
+ return {
632936
+ platform: deps.platform ?? process.platform,
632937
+ arch: deps.arch ?? process.arch,
632938
+ env: deps.env ?? process.env,
632939
+ fileExists: deps.fileExists ?? ((p) => import_node_fs5.default.existsSync(p)),
632940
+ verifyBash: deps.verifyBash ?? defaultVerifyBash,
632941
+ whereGit: deps.whereGit ?? defaultWhereGit,
632942
+ installMinGit: deps.installMinGit ?? installMinGit,
632943
+ logger: deps.logger ?? noopLogger
632944
+ };
632945
+ }
632946
+ function getToolsDir(ctx = {}) {
632947
+ return import_node_path4.default.join(getCacheDir(ctx), "tools");
632948
+ }
632949
+ function getGitBashDir(ctx = {}) {
632950
+ return import_node_path4.default.join(getToolsDir(ctx), "git-bash", MINGIT_VERSION);
632951
+ }
632952
+ function getCachedBashPath(ctx = {}) {
632953
+ return import_node_path4.default.join(getGitBashDir(ctx), "usr", "bin", "bash.exe");
632954
+ }
632955
+ function isSystem32Path(p) {
632956
+ return /[\\/](system32|sysnative)[\\/]/i.test(p);
632957
+ }
632958
+ function systemBashCandidates(gitPaths, env) {
632959
+ const candidates = [];
632960
+ for (const gitPath of gitPaths) {
632961
+ const root = import_node_path4.default.win32.dirname(import_node_path4.default.win32.dirname(gitPath));
632962
+ candidates.push(import_node_path4.default.win32.join(root, "bin", "bash.exe"));
632963
+ candidates.push(import_node_path4.default.win32.join(root, "usr", "bin", "bash.exe"));
632964
+ }
632965
+ for (const base of [
632966
+ env.ProgramFiles ?? env.PROGRAMFILES,
632967
+ env["ProgramFiles(x86)"],
632968
+ env.LOCALAPPDATA ? import_node_path4.default.win32.join(env.LOCALAPPDATA, "Programs") : void 0
632969
+ ]) {
632970
+ if (base)
632971
+ candidates.push(import_node_path4.default.win32.join(base, "Git", "bin", "bash.exe"));
632972
+ }
632973
+ return candidates.filter((p) => !isSystem32Path(p));
632974
+ }
632975
+ async function spawnCapture(cmd, args) {
632976
+ return await new Promise((resolve) => {
632977
+ let stdout = "";
632978
+ let child;
632979
+ try {
632980
+ child = (0, import_node_child_process3.spawn)(cmd, args, { windowsHide: true });
632981
+ } catch {
632982
+ resolve(null);
632983
+ return;
632984
+ }
632985
+ const timer = setTimeout(() => {
632986
+ try {
632987
+ child.kill();
632988
+ } catch {
632989
+ }
632990
+ resolve(null);
632991
+ }, 15e3);
632992
+ timer.unref?.();
632993
+ child.on("error", () => {
632994
+ clearTimeout(timer);
632995
+ resolve(null);
632996
+ });
632997
+ child.stdout?.on("data", (d) => stdout += d.toString());
632998
+ child.on("close", (code) => {
632999
+ clearTimeout(timer);
633000
+ resolve({ code, stdout });
633001
+ });
633002
+ });
633003
+ }
633004
+ async function defaultVerifyBash(bashPath) {
633005
+ const result = await spawnCapture(bashPath, ["--version"]);
633006
+ return result !== null && result.code === 0 && /GNU bash, version \d+/.test(result.stdout);
633007
+ }
633008
+ async function defaultWhereGit() {
633009
+ const result = await spawnCapture("where.exe", ["git"]);
633010
+ if (!result)
633011
+ return [];
633012
+ return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
633013
+ }
633014
+ async function sha256File(filePath) {
633015
+ return await new Promise((resolve, reject) => {
633016
+ const hash = import_node_crypto.default.createHash("sha256");
633017
+ const stream = import_node_fs5.default.createReadStream(filePath);
633018
+ stream.on("error", reject);
633019
+ stream.on("data", (chunk) => hash.update(chunk));
633020
+ stream.on("end", () => resolve(hash.digest("hex")));
633021
+ });
633022
+ }
633023
+ async function installMinGit(destDir, deps = {}) {
633024
+ const arch = deps.arch ?? process.arch;
633025
+ const logger = deps.logger ?? noopLogger;
633026
+ if (arch !== "x64" && arch !== "arm64") {
633027
+ throw new Error(`The bundled Git Bash (MinGit) isn't available for the ${arch} architecture. Install Git for Windows manually, or set \`shell\` to \`cmd\` or \`powershell\`.`);
633028
+ }
633029
+ const asset = MINGIT_ASSETS[arch === "arm64" ? "arm64" : "x64"];
633030
+ import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(destDir), { recursive: true });
633031
+ const zipPath = `${destDir}.download.zip`;
633032
+ try {
633033
+ logger(`Downloading Git Bash (MinGit ${MINGIT_VERSION}) into the Doc Detective cache \u2014 a one-time ~40 MB download\u2026`, "info");
633034
+ await downloadFile(asset.url, zipPath);
633035
+ const actual = await sha256File(zipPath);
633036
+ if (actual !== asset.sha256) {
633037
+ throw new Error(`MinGit download failed its checksum (expected ${asset.sha256}, got ${actual}). Refusing to install.`);
633038
+ }
633039
+ import_node_fs5.default.rmSync(destDir, { recursive: true, force: true });
633040
+ import_node_fs5.default.mkdirSync(destDir, { recursive: true });
633041
+ await extractZip(zipPath, destDir);
633042
+ const shPath = import_node_path4.default.join(destDir, "usr", "bin", "sh.exe");
633043
+ const bashPath = import_node_path4.default.join(destDir, "usr", "bin", "bash.exe");
633044
+ if (!import_node_fs5.default.existsSync(bashPath)) {
633045
+ if (!import_node_fs5.default.existsSync(shPath)) {
633046
+ throw new Error(`MinGit extraction is missing usr/bin/sh.exe under ${destDir}; the archive layout may have changed.`);
633047
+ }
633048
+ import_node_fs5.default.copyFileSync(shPath, bashPath);
633049
+ }
633050
+ } finally {
633051
+ import_node_fs5.default.rmSync(zipPath, { force: true });
633052
+ }
633053
+ }
633054
+ async function installAndVerify(ctx, deps) {
633055
+ await deps.installMinGit(getGitBashDir(ctx), deps);
633056
+ const cachedBash = getCachedBashPath(ctx);
633057
+ if (!deps.fileExists(cachedBash) || !await deps.verifyBash(cachedBash)) {
633058
+ throw new Error(`Git Bash install completed but ${cachedBash} isn't runnable. Re-run \`doc-detective install bash --force\`, or set a different shell (\`cmd\` or \`powershell\`).`);
633059
+ }
633060
+ try {
633061
+ const record = readInstalledRecord(ctx);
633062
+ record.tools = record.tools ?? {};
633063
+ record.tools["git-bash"] = {
633064
+ installedVersion: MINGIT_VERSION,
633065
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
633066
+ };
633067
+ writeInstalledRecord(record, ctx);
633068
+ } catch {
633069
+ }
633070
+ return cachedBash;
633071
+ }
633072
+ function quarantineDir(dir, logger) {
633073
+ try {
633074
+ if (!import_node_fs5.default.existsSync(dir))
633075
+ return;
633076
+ const quarantined = `${dir}.broken-${Date.now()}`;
633077
+ import_node_fs5.default.renameSync(dir, quarantined);
633078
+ logger(`Quarantined a broken Git Bash install to ${quarantined}.`, "warn");
633079
+ } catch {
633080
+ try {
633081
+ import_node_fs5.default.rmSync(dir, { recursive: true, force: true });
633082
+ } catch {
633083
+ }
633084
+ }
633085
+ }
633086
+ async function resolveWindowsBash(options = {}) {
633087
+ const { cacheDir, autoInstall = true } = options;
633088
+ const deps = depsWithDefaults(options.deps ?? {});
633089
+ if (deps.platform !== "win32") {
633090
+ throw new Error("resolveWindowsBash is only meaningful on Windows; POSIX platforms resolve bash from PATH.");
633091
+ }
633092
+ const ctx = cacheDir ? { cacheDir } : {};
633093
+ const cachedBash = getCachedBashPath(ctx);
633094
+ const memoKey = getCacheDir(ctx);
633095
+ const memoized = resolvedBashByCache.get(memoKey);
633096
+ if (memoized) {
633097
+ if (deps.fileExists(memoized))
633098
+ return memoized;
633099
+ resolvedBashByCache.delete(memoKey);
633100
+ }
633101
+ if (deps.fileExists(cachedBash)) {
633102
+ if (await deps.verifyBash(cachedBash)) {
633103
+ resolvedBashByCache.set(memoKey, cachedBash);
633104
+ return cachedBash;
633105
+ }
633106
+ quarantineDir(getGitBashDir(ctx), deps.logger);
633107
+ }
633108
+ const gitPaths = await deps.whereGit();
633109
+ for (const candidate of systemBashCandidates(gitPaths, deps.env)) {
633110
+ if (!deps.fileExists(candidate))
633111
+ continue;
633112
+ if (await deps.verifyBash(candidate)) {
633113
+ resolvedBashByCache.set(memoKey, candidate);
633114
+ return candidate;
633115
+ }
633116
+ }
633117
+ if (!autoInstall) {
633118
+ throw new Error("Git Bash isn't available on this Windows machine. Run `doc-detective install bash` to install it, install Git for Windows, or set a different shell (`cmd` or `powershell`) in the step or config.");
633119
+ }
633120
+ let pending = inFlightInstalls.get(memoKey);
633121
+ if (!pending) {
633122
+ pending = installAndVerify(ctx, deps);
633123
+ inFlightInstalls.set(memoKey, pending);
633124
+ pending.finally(() => inFlightInstalls.delete(memoKey)).catch(() => {
633125
+ });
633126
+ }
633127
+ const installed = await pending;
633128
+ resolvedBashByCache.set(memoKey, installed);
633129
+ return installed;
633130
+ }
633131
+ async function installBash(options = {}) {
633132
+ const { force = false, dryRun = false, ctx = {} } = options;
633133
+ const deps = depsWithDefaults(options.deps ?? {});
633134
+ const logger = deps.logger;
633135
+ if (deps.platform !== "win32") {
633136
+ return [
633137
+ {
633138
+ assetId: "git-bash",
633139
+ kind: "tool",
633140
+ action: "skipped",
633141
+ notes: ["Windows-only; POSIX systems resolve bash from PATH."]
633142
+ }
633143
+ ];
633144
+ }
633145
+ if (dryRun) {
633146
+ return [
633147
+ {
633148
+ assetId: "git-bash",
633149
+ kind: "tool",
633150
+ action: "dry-run",
633151
+ notes: [`would ensure MinGit ${MINGIT_VERSION} (or an existing Git for Windows bash)`]
633152
+ }
633153
+ ];
633154
+ }
633155
+ if (!force) {
633156
+ try {
633157
+ const resolved = await resolveWindowsBash({
633158
+ cacheDir: ctx.cacheDir,
633159
+ autoInstall: false,
633160
+ deps
633161
+ });
633162
+ return [
633163
+ {
633164
+ assetId: "git-bash",
633165
+ kind: "tool",
633166
+ action: "already-up-to-date",
633167
+ installedVersion: resolved === getCachedBashPath(ctx) ? MINGIT_VERSION : void 0,
633168
+ notes: [`bash at ${resolved}`]
633169
+ }
633170
+ ];
633171
+ } catch {
633172
+ }
633173
+ }
633174
+ const installed = await installAndVerify(ctx, deps);
633175
+ resolvedBashByCache.set(getCacheDir(ctx), installed);
633176
+ logger(`Installed Git Bash (MinGit ${MINGIT_VERSION}).`, "info");
633177
+ return [
633178
+ {
633179
+ assetId: "git-bash",
633180
+ kind: "tool",
633181
+ action: force ? "forced" : "installed",
633182
+ installedVersion: MINGIT_VERSION
633183
+ }
633184
+ ];
633185
+ }
633186
+ var import_node_fs5, import_node_path4, import_node_crypto, import_node_child_process3, MINGIT_VERSION, MINGIT_ASSETS, noopLogger, inFlightInstalls, resolvedBashByCache;
633187
+ var init_windowsBash = __esm({
633188
+ "dist/runtime/windowsBash.js"() {
633189
+ "use strict";
633190
+ import_node_fs5 = __toESM(require("node:fs"), 1);
633191
+ import_node_path4 = __toESM(require("node:path"), 1);
633192
+ import_node_crypto = __toESM(require("node:crypto"), 1);
633193
+ import_node_child_process3 = require("node:child_process");
633194
+ init_cacheDir();
633195
+ init_archiveUtils();
633196
+ MINGIT_VERSION = "2.55.0.2";
633197
+ MINGIT_ASSETS = {
633198
+ x64: {
633199
+ url: `https://github.com/git-for-windows/git/releases/download/v2.55.0.windows.2/MinGit-${MINGIT_VERSION}-64-bit.zip`,
633200
+ sha256: "e3ea2944cea4b3fabcd69c7c1669ef69b1b66c05ac7806d81224d0abad2dec31"
633201
+ },
633202
+ arm64: {
633203
+ url: `https://github.com/git-for-windows/git/releases/download/v2.55.0.windows.2/MinGit-${MINGIT_VERSION}-arm64.zip`,
633204
+ sha256: "0b2b81fdce284efd174cbb51b886ccea2fd271679c4b5c21f07d9e03bae51413"
633205
+ }
633206
+ };
633207
+ noopLogger = () => {
633208
+ };
633209
+ inFlightInstalls = /* @__PURE__ */ new Map();
633210
+ resolvedBashByCache = /* @__PURE__ */ new Map();
633211
+ }
633212
+ });
633213
+
632382
633214
  // dist/core/ptyWatchdog.js
632383
633215
  function defaultCreateWorker(data) {
632384
633216
  const url = new URL("./ptyProbeWorker.js", importMetaUrl);
@@ -632434,7 +633266,7 @@ function probePtyAllocation(opts) {
632434
633266
  });
632435
633267
  }
632436
633268
  async function ensurePtyBackendOnDisk(opts) {
632437
- const exists = opts.exists ?? import_node_fs4.default.existsSync;
633269
+ const exists = opts.exists ?? import_node_fs6.default.existsSync;
632438
633270
  const first = opts.resolvePath();
632439
633271
  if (first && exists(first))
632440
633272
  return first;
@@ -632464,11 +633296,11 @@ async function assertConptyAllocatable(opts) {
632464
633296
  throw err;
632465
633297
  }
632466
633298
  }
632467
- var import_node_fs4, import_node_worker_threads, PTY_PROBE_TIMEOUT_MS;
633299
+ var import_node_fs6, import_node_worker_threads, PTY_PROBE_TIMEOUT_MS;
632468
633300
  var init_ptyWatchdog = __esm({
632469
633301
  "dist/core/ptyWatchdog.js"() {
632470
633302
  "use strict";
632471
- import_node_fs4 = __toESM(require("node:fs"), 1);
633303
+ import_node_fs6 = __toESM(require("node:fs"), 1);
632472
633304
  import_node_worker_threads = require("node:worker_threads");
632473
633305
  PTY_PROBE_TIMEOUT_MS = Number(process.env.DOC_DETECTIVE_PTY_PROBE_TIMEOUT_MS) || 15e3;
632474
633306
  }
@@ -632599,12 +633431,15 @@ function backgroundSleep(ms) {
632599
633431
  return new Promise((resolve) => setTimeout(resolve, ms));
632600
633432
  }
632601
633433
  function spawnBackgroundCommand(cmd, args = [], options = {}) {
632602
- const spawnOptions = { shell: true };
633434
+ const spawnOptions = { shell: options.shell || true };
632603
633435
  if (process.platform === "win32")
632604
633436
  spawnOptions.windowsHide = true;
632605
633437
  if (options.cwd)
632606
633438
  spawnOptions.cwd = options.cwd;
632607
- const child = (0, import_node_child_process2.spawn)(cmd, args, spawnOptions);
633439
+ const bgShellEnv = shellSpawnEnv(options.shell);
633440
+ if (bgShellEnv)
633441
+ spawnOptions.env = bgShellEnv;
633442
+ const child = (0, import_node_child_process4.spawn)(cmd, args, spawnOptions);
632608
633443
  let stdout = "";
632609
633444
  let stderr = "";
632610
633445
  const subscribers = /* @__PURE__ */ new Set();
@@ -632644,12 +633479,19 @@ function spawnBackgroundCommand(cmd, args = [], options = {}) {
632644
633479
  exited
632645
633480
  };
632646
633481
  }
632647
- function quoteShellArg(arg) {
632648
- if (process.platform === "win32") {
633482
+ function quoteShellArg(arg, style) {
633483
+ const resolvedStyle = style ?? (process.platform === "win32" ? "cmd" : "posix");
633484
+ if (resolvedStyle === "cmd") {
632649
633485
  return `"${arg.replace(/"/g, '""')}"`;
632650
633486
  }
633487
+ if (resolvedStyle === "powershell") {
633488
+ return `'${arg.replace(/'/g, "''")}'`;
633489
+ }
632651
633490
  return `'${arg.replace(/'/g, `'\\''`)}'`;
632652
633491
  }
633492
+ function isCmdShellExecutable(shellExecutable) {
633493
+ return /(^|[\\/])cmd(\.exe)?$/i.test(shellExecutable);
633494
+ }
632653
633495
  async function spawnPtyBackgroundCommand(cmd, args = [], options = {}) {
632654
633496
  let pty;
632655
633497
  try {
@@ -632669,11 +633511,13 @@ async function spawnPtyBackgroundCommand(cmd, args = [], options = {}) {
632669
633511
  })
632670
633512
  });
632671
633513
  await assertConptyAllocatable({ ptyModulePath });
632672
- const argstr = args.length ? " " + args.map(quoteShellArg).join(" ") : "";
632673
- const fullCommand = cmd + argstr;
632674
633514
  const isWin = process.platform === "win32";
632675
- const shell = isWin ? process.env.ComSpec || "cmd.exe" : "/bin/sh";
632676
- const shellArgs = isWin ? ["/d", "/s", "/c", fullCommand] : ["-c", fullCommand];
633515
+ const shell = options.shell || (isWin ? process.env.ComSpec || "cmd.exe" : "/bin/sh");
633516
+ const isCmdShell = isCmdShellExecutable(shell);
633517
+ const quoteStyle = isCmdShell ? "cmd" : /powershell(\.exe)?$/i.test(shell) ? "powershell" : "posix";
633518
+ const argstr = args.length ? " " + args.map((arg) => quoteShellArg(arg, quoteStyle)).join(" ") : "";
633519
+ const fullCommand = cmd + argstr;
633520
+ const shellArgs = isCmdShell ? ["/d", "/s", "/c", fullCommand] : ["-c", fullCommand];
632677
633521
  let ptyProcess;
632678
633522
  try {
632679
633523
  ptyProcess = pty.spawn(shell, shellArgs, {
@@ -632684,7 +633528,7 @@ async function spawnPtyBackgroundCommand(cmd, args = [], options = {}) {
632684
633528
  cols: 120,
632685
633529
  rows: 30,
632686
633530
  cwd: options.cwd || process.cwd(),
632687
- env: process.env
633531
+ env: shellSpawnEnv(options.shell) ?? process.env
632688
633532
  });
632689
633533
  } catch (error) {
632690
633534
  const err = new Error(`PTY could not be created on this platform: ${error?.message ?? error}`);
@@ -632953,19 +633797,19 @@ function appendQueryParams(url, params) {
632953
633797
  return pathAndAuthority + (query ? "?" + query : "") + fragment;
632954
633798
  }
632955
633799
  function cleanTemp() {
632956
- const tempDir = import_node_path4.default.join(import_node_os2.default.tmpdir(), "doc-detective");
632957
- if (!import_node_fs5.default.existsSync(tempDir))
633800
+ const tempDir = import_node_path5.default.join(import_node_os2.default.tmpdir(), "doc-detective");
633801
+ if (!import_node_fs7.default.existsSync(tempDir))
632958
633802
  return;
632959
- for (const entry of import_node_fs5.default.readdirSync(tempDir)) {
633803
+ for (const entry of import_node_fs7.default.readdirSync(tempDir)) {
632960
633804
  if (PRESERVED_TEMP_ENTRIES.has(entry))
632961
633805
  continue;
632962
- const curPath = import_node_path4.default.join(tempDir, entry);
633806
+ const curPath = import_node_path5.default.join(tempDir, entry);
632963
633807
  try {
632964
- const stat = import_node_fs5.default.statSync(curPath);
633808
+ const stat = import_node_fs7.default.statSync(curPath);
632965
633809
  if (stat.isDirectory()) {
632966
- import_node_fs5.default.rmSync(curPath, { recursive: true, force: true });
633810
+ import_node_fs7.default.rmSync(curPath, { recursive: true, force: true });
632967
633811
  } else {
632968
- import_node_fs5.default.unlinkSync(curPath);
633812
+ import_node_fs7.default.unlinkSync(curPath);
632969
633813
  }
632970
633814
  } catch {
632971
633815
  }
@@ -632987,7 +633831,7 @@ function safeFilenameFromUrl(fileURL, fallback) {
632987
633831
  raw = fileURL;
632988
633832
  }
632989
633833
  raw = raw.split("?")[0].split("#")[0];
632990
- const base = import_node_path4.default.basename(raw.replace(/\\/g, "/"));
633834
+ const base = import_node_path5.default.basename(raw.replace(/\\/g, "/"));
632991
633835
  return sanitizeFilesystemName(base, fallback);
632992
633836
  }
632993
633837
  function redactUrlForOutput(value) {
@@ -633099,22 +633943,22 @@ async function fetchFile(fileURL, opts = {}) {
633099
633943
  data = response.data.toString();
633100
633944
  }
633101
633945
  const fileName = safeFilenameFromUrl(fileURL, "fetched_file");
633102
- const hash = import_node_crypto.default.createHash("md5").update(data).digest("hex");
633103
- const ddTempDir = import_node_path4.default.join(import_node_os2.default.tmpdir(), "doc-detective");
633104
- const filePath = import_node_path4.default.join(ddTempDir, `${hash}_${fileName}`);
633105
- const resolvedDir = import_node_path4.default.resolve(ddTempDir);
633106
- const resolvedFile = import_node_path4.default.resolve(filePath);
633107
- if (!resolvedFile.startsWith(resolvedDir + import_node_path4.default.sep)) {
633946
+ const hash = import_node_crypto2.default.createHash("md5").update(data).digest("hex");
633947
+ const ddTempDir = import_node_path5.default.join(import_node_os2.default.tmpdir(), "doc-detective");
633948
+ const filePath = import_node_path5.default.join(ddTempDir, `${hash}_${fileName}`);
633949
+ const resolvedDir = import_node_path5.default.resolve(ddTempDir);
633950
+ const resolvedFile = import_node_path5.default.resolve(filePath);
633951
+ if (!resolvedFile.startsWith(resolvedDir + import_node_path5.default.sep)) {
633108
633952
  return {
633109
633953
  result: "error",
633110
633954
  message: new Error(`Refusing to write outside temp dir: ${resolvedFile}`)
633111
633955
  };
633112
633956
  }
633113
- if (!import_node_fs5.default.existsSync(ddTempDir)) {
633114
- import_node_fs5.default.mkdirSync(ddTempDir, { recursive: true });
633957
+ if (!import_node_fs7.default.existsSync(ddTempDir)) {
633958
+ import_node_fs7.default.mkdirSync(ddTempDir, { recursive: true });
633115
633959
  }
633116
- if (!import_node_fs5.default.existsSync(filePath)) {
633117
- import_node_fs5.default.writeFileSync(filePath, data);
633960
+ if (!import_node_fs7.default.existsSync(filePath)) {
633961
+ import_node_fs7.default.writeFileSync(filePath, data);
633118
633962
  }
633119
633963
  return { result: "success", path: filePath };
633120
633964
  } catch (error) {
@@ -633122,7 +633966,7 @@ async function fetchFile(fileURL, opts = {}) {
633122
633966
  }
633123
633967
  }
633124
633968
  async function loadEnvs(envsFile) {
633125
- const fileExists = import_node_fs5.default.existsSync(envsFile);
633969
+ const fileExists = import_node_fs7.default.existsSync(envsFile);
633126
633970
  if (fileExists) {
633127
633971
  const { default: dotenv } = await import("dotenv");
633128
633972
  dotenv.config({ path: envsFile, override: true });
@@ -633184,10 +634028,10 @@ function expandRequirementPath(entry, env) {
633184
634028
  function commandOnPath(command, env, existsSync2) {
633185
634029
  const hasSeparator = command.includes("/") || command.includes("\\");
633186
634030
  const pathValue = env.PATH ?? env.Path ?? "";
633187
- const directories = hasSeparator ? [""] : pathValue.split(import_node_path4.default.delimiter).filter(Boolean);
634031
+ const directories = hasSeparator ? [""] : pathValue.split(import_node_path5.default.delimiter).filter(Boolean);
633188
634032
  const extensions = process.platform === "win32" ? ["", ...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)] : [""];
633189
634033
  for (const directory of directories) {
633190
- const base = hasSeparator ? command : import_node_path4.default.join(directory, command);
634034
+ const base = hasSeparator ? command : import_node_path5.default.join(directory, command);
633191
634035
  for (const extension of extensions) {
633192
634036
  if (existsSync2(base + extension))
633193
634037
  return true;
@@ -633197,7 +634041,7 @@ function commandOnPath(command, env, existsSync2) {
633197
634041
  }
633198
634042
  function evaluateContextRequirements({ requires, deps = {} }) {
633199
634043
  const env = deps.env ?? process.env;
633200
- const existsSync2 = deps.existsSync ?? import_node_fs5.default.existsSync;
634044
+ const existsSync2 = deps.existsSync ?? import_node_fs7.default.existsSync;
633201
634045
  const platform = deps.platform ?? process.platform;
633202
634046
  const commandExists = deps.commandExists ?? ((command) => commandOnPath(command, env, existsSync2));
633203
634047
  const isObjectForm = requires && typeof requires === "object" && !Array.isArray(requires);
@@ -633268,28 +634112,28 @@ function getOrInitRunTimestamp(config) {
633268
634112
  function getRunOutputDir(config, { create = true } = {}) {
633269
634113
  if (config?.__runOutputDir) {
633270
634114
  if (create)
633271
- import_node_fs5.default.mkdirSync(config.__runOutputDir, { recursive: true });
634115
+ import_node_fs7.default.mkdirSync(config.__runOutputDir, { recursive: true });
633272
634116
  return config.__runOutputDir;
633273
634117
  }
633274
634118
  let base = String(config?.output || ".");
633275
634119
  const reportFileExtensions = [".json", ".html", ".htm"];
633276
634120
  if (reportFileExtensions.some((ext) => base.toLowerCase().endsWith(ext))) {
633277
- base = import_node_path4.default.dirname(base);
634121
+ base = import_node_path5.default.dirname(base);
633278
634122
  }
633279
- const runsRoot = import_node_path4.default.resolve(base, ".doc-detective", "runs");
634123
+ const runsRoot = import_node_path5.default.resolve(base, ".doc-detective", "runs");
633280
634124
  const runId = getOrInitRunTimestamp(config);
633281
- let dir = import_node_path4.default.join(runsRoot, runId);
634125
+ let dir = import_node_path5.default.join(runsRoot, runId);
633282
634126
  if (create) {
633283
- import_node_fs5.default.mkdirSync(runsRoot, { recursive: true });
634127
+ import_node_fs7.default.mkdirSync(runsRoot, { recursive: true });
633284
634128
  let suffix = 2;
633285
634129
  for (; ; ) {
633286
634130
  try {
633287
- import_node_fs5.default.mkdirSync(dir);
634131
+ import_node_fs7.default.mkdirSync(dir);
633288
634132
  break;
633289
634133
  } catch (error) {
633290
634134
  if (error?.code !== "EEXIST")
633291
634135
  throw error;
633292
- dir = import_node_path4.default.join(runsRoot, `${runId}-${suffix++}`);
634136
+ dir = import_node_path5.default.join(runsRoot, `${runId}-${suffix++}`);
633293
634137
  }
633294
634138
  }
633295
634139
  }
@@ -633309,9 +634153,77 @@ function runArchivesArtifacts(config = {}, specs = []) {
633309
634153
  const active = Array.isArray(config?.reporters) && config.reporters.length > 0 ? config.reporters : ["terminal", "json", "runFolder"];
633310
634154
  return active.some((reporter) => typeof reporter === "string" && (reporter.toLowerCase() === "runfolder" || reporter === "runFolderReporter"));
633311
634155
  }
634156
+ function resolveShellName({ config, step } = {}) {
634157
+ return step?.runShell?.shell ?? config?.shell ?? "bash";
634158
+ }
634159
+ function defaultProbePosixBash() {
634160
+ if (!posixBashProbe) {
634161
+ posixBashProbe = new Promise((resolve) => {
634162
+ let child;
634163
+ try {
634164
+ child = (0, import_node_child_process4.spawn)("bash", ["--version"]);
634165
+ } catch {
634166
+ resolve(false);
634167
+ return;
634168
+ }
634169
+ child.on("error", () => resolve(false));
634170
+ child.on("close", (code) => resolve(code === 0));
634171
+ });
634172
+ }
634173
+ return posixBashProbe;
634174
+ }
634175
+ async function resolveShellExecutable(shellName, deps = {}) {
634176
+ const platform = deps.platform ?? process.platform;
634177
+ const env = deps.env ?? process.env;
634178
+ switch (shellName) {
634179
+ case "bash": {
634180
+ if (platform === "win32") {
634181
+ const resolveBash = deps.resolveWindowsBash ?? resolveWindowsBash;
634182
+ return await resolveBash({ cacheDir: deps.cacheDir });
634183
+ }
634184
+ const probe = deps.probePosixBash ?? defaultProbePosixBash;
634185
+ if (!await probe()) {
634186
+ throw new Error("The default `bash` shell isn't available on this system. Install bash (e.g. `apk add bash` on Alpine, `apt-get install bash` on Debian slim images) to run shell steps.");
634187
+ }
634188
+ return "bash";
634189
+ }
634190
+ case "cmd": {
634191
+ if (platform !== "win32") {
634192
+ throw new Error("The `cmd` shell is only supported on Windows. Use `bash` (the default) or gate the step with `runOn`.");
634193
+ }
634194
+ return env.ComSpec || "cmd.exe";
634195
+ }
634196
+ case "powershell": {
634197
+ if (platform !== "win32") {
634198
+ throw new Error("The `powershell` shell is only supported on Windows. Use `bash` (the default) or gate the step with `runOn`.");
634199
+ }
634200
+ return "powershell.exe";
634201
+ }
634202
+ default:
634203
+ throw new Error(`Unsupported shell: ${shellName}. Supported shells: bash, cmd, powershell.`);
634204
+ }
634205
+ }
634206
+ function shellSpawnEnv(shellExecutable, deps = {}) {
634207
+ const platform = deps.platform ?? process.platform;
634208
+ const env = deps.env ?? process.env;
634209
+ if (platform !== "win32" || !shellExecutable)
634210
+ return void 0;
634211
+ if (!/bash(\.exe)?$/i.test(shellExecutable))
634212
+ return void 0;
634213
+ const dir = import_node_path5.default.win32.dirname(shellExecutable);
634214
+ if (!import_node_path5.default.win32.isAbsolute(dir))
634215
+ return void 0;
634216
+ const pathKey = Object.keys(env).find((k) => k.toUpperCase() === "PATH") ?? "Path";
634217
+ const existing = env[pathKey];
634218
+ return {
634219
+ ...env,
634220
+ // No trailing delimiter (an empty PATH segment) when PATH was unset.
634221
+ [pathKey]: existing ? `${dir}${import_node_path5.default.win32.delimiter}${existing}` : dir
634222
+ };
634223
+ }
633312
634224
  async function spawnCommand(cmd, args = [], options = {}) {
633313
634225
  const spawnOptions = {
633314
- shell: true
634226
+ shell: options.shell || true
633315
634227
  };
633316
634228
  if (process.platform === "win32") {
633317
634229
  spawnOptions.windowsHide = true;
@@ -633319,7 +634231,10 @@ async function spawnCommand(cmd, args = [], options = {}) {
633319
634231
  if (options.cwd) {
633320
634232
  spawnOptions.cwd = options.cwd;
633321
634233
  }
633322
- const runCommand = (0, import_node_child_process2.spawn)(cmd, args, spawnOptions);
634234
+ const shellEnv = shellSpawnEnv(options.shell);
634235
+ if (shellEnv)
634236
+ spawnOptions.env = shellEnv;
634237
+ const runCommand = (0, import_node_child_process4.spawn)(cmd, args, spawnOptions);
633323
634238
  runCommand.on("error", (error) => {
633324
634239
  });
633325
634240
  const exitCodePromise = new Promise((resolve) => {
@@ -633404,19 +634319,20 @@ function llevenshteinDistance(s, t) {
633404
634319
  }
633405
634320
  return arr[t.length][s.length];
633406
634321
  }
633407
- var import_node_fs5, import_node_os2, import_node_path4, import_node_crypto, import_promises, import_node_net, import_axios, import_node_child_process2, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS;
634322
+ var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, posixBashProbe;
633408
634323
  var init_utils = __esm({
633409
634324
  "dist/core/utils.js"() {
633410
634325
  "use strict";
633411
- import_node_fs5 = __toESM(require("node:fs"), 1);
634326
+ import_node_fs7 = __toESM(require("node:fs"), 1);
633412
634327
  import_node_os2 = __toESM(require("node:os"), 1);
633413
- import_node_path4 = __toESM(require("node:path"), 1);
633414
- import_node_crypto = __toESM(require("node:crypto"), 1);
634328
+ import_node_path5 = __toESM(require("node:path"), 1);
634329
+ import_node_crypto2 = __toESM(require("node:crypto"), 1);
633415
634330
  import_promises = __toESM(require("node:dns/promises"), 1);
633416
634331
  import_node_net = __toESM(require("node:net"), 1);
633417
634332
  import_axios = __toESM(require("axios"), 1);
633418
- import_node_child_process2 = require("node:child_process");
634333
+ import_node_child_process4 = require("node:child_process");
633419
634334
  init_loader();
634335
+ init_windowsBash();
633420
634336
  init_ptyWatchdog();
633421
634337
  BACKGROUND_BUFFER_LIMIT = 256 * 1024;
633422
634338
  PTY_PACKAGE = "@homebridge/node-pty-prebuilt-multiarch";
@@ -633433,7 +634349,10 @@ var init_utils = __esm({
633433
634349
  PRESERVED_TEMP_ENTRIES = /* @__PURE__ */ new Set([
633434
634350
  "browsers",
633435
634351
  "runtime",
633436
- "installed.json"
634352
+ "installed.json",
634353
+ // Tool downloads (git-bash — the MinGit backing runShell's Windows `bash`
634354
+ // shell). Wiping it would force a ~40 MB re-download on every run.
634355
+ "tools"
633437
634356
  ]);
633438
634357
  FETCH_BINARY_DEFAULTS = {
633439
634358
  responseType: "arraybuffer",
@@ -633456,7 +634375,7 @@ __export(browsers_exports, {
633456
634375
  verifyDriverBinary: () => verifyDriverBinary
633457
634376
  });
633458
634377
  function isAllowedDriverPath(binaryPath) {
633459
- return typeof binaryPath === "string" && import_node_path5.default.isAbsolute(binaryPath) && ALLOWED_DRIVER_PATH.test(binaryPath);
634378
+ return typeof binaryPath === "string" && import_node_path6.default.isAbsolute(binaryPath) && ALLOWED_DRIVER_PATH.test(binaryPath);
633460
634379
  }
633461
634380
  function parseDriverVersion(output) {
633462
634381
  const m = output.match(/(\d+\.\d+(?:\.\d+)*)/);
@@ -633555,13 +634474,13 @@ function withTimeout(p, ms, label) {
633555
634474
  async function ensureBrowserInstalled(name, options = {}) {
633556
634475
  const { ctx = {} } = options;
633557
634476
  const dedupeKey = `${name}:${getBrowsersDir(ctx)}`;
633558
- const inFlight = inFlightInstalls.get(dedupeKey);
634477
+ const inFlight = inFlightInstalls2.get(dedupeKey);
633559
634478
  if (inFlight)
633560
634479
  return inFlight;
633561
634480
  const p = ensureBrowserInstalledImpl(name, options).finally(() => {
633562
- inFlightInstalls.delete(dedupeKey);
634481
+ inFlightInstalls2.delete(dedupeKey);
633563
634482
  });
633564
- inFlightInstalls.set(dedupeKey, p);
634483
+ inFlightInstalls2.set(dedupeKey, p);
633565
634484
  return p;
633566
634485
  }
633567
634486
  async function ensureBrowserInstalledImpl(name, options = {}) {
@@ -633581,12 +634500,12 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633581
634500
  }
633582
634501
  if (!force && existing && isStillFresh(existing.latestCheckedAt, now)) {
633583
634502
  if (existing.latestKnownVersion === existing.installedVersion) {
633584
- const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
633585
- return { path: path27, version: existing.installedVersion, outdated: false };
634503
+ const path28 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634504
+ return { path: path28, version: existing.installedVersion, outdated: false };
633586
634505
  }
633587
- const path26 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634506
+ const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
633588
634507
  logger(`${name} ${existing.installedVersion} installed in ${cacheDir}; "${BROWSER_CHANNELS[name]}" channel is now ${existing.latestKnownVersion}. Run \`doc-detective install browsers ${name} --force\` to update.`, "warn");
633589
- return { path: path26, version: existing.installedVersion, outdated: true };
634508
+ return { path: path27, version: existing.installedVersion, outdated: true };
633590
634509
  }
633591
634510
  let latest;
633592
634511
  try {
@@ -633594,8 +634513,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633594
634513
  } catch (err) {
633595
634514
  logger(`Channel resolution for ${name} skipped: ${String(err)}`, "debug");
633596
634515
  if (existing) {
633597
- const path26 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
633598
- return { path: path26, version: existing.installedVersion, outdated: false };
634516
+ const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634517
+ return { path: path27, version: existing.installedVersion, outdated: false };
633599
634518
  }
633600
634519
  throw err;
633601
634520
  }
@@ -633606,8 +634525,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633606
634525
  latestCheckedAt: now.toISOString()
633607
634526
  };
633608
634527
  writeInstalledRecord(record, ctx);
633609
- const path26 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
633610
- return { path: path26, version: latest, outdated: false };
634528
+ const path27 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634529
+ return { path: path27, version: latest, outdated: false };
633611
634530
  }
633612
634531
  if (!force && existing) {
633613
634532
  record.browsers[name] = {
@@ -633617,8 +634536,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633617
634536
  };
633618
634537
  writeInstalledRecord(record, ctx);
633619
634538
  logger(`${name} ${existing.installedVersion} installed in ${cacheDir}; "${BROWSER_CHANNELS[name]}" channel is now ${latest}. Run \`doc-detective install browsers ${name} --force\` to update.`, "warn");
633620
- const path26 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
633621
- return { path: path26, version: existing.installedVersion, outdated: true };
634539
+ const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634540
+ return { path: path27, version: existing.installedVersion, outdated: true };
633622
634541
  }
633623
634542
  logger(`Installing ${name} ${latest} into ${cacheDir}`, "info");
633624
634543
  await browsersModule.install({
@@ -633626,9 +634545,9 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633626
634545
  buildId: latest,
633627
634546
  cacheDir
633628
634547
  });
633629
- let path25 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
633630
- if (name === "chromedriver" && isAllowedDriverPath(path25)) {
633631
- let verify = await verifyDriverBinary(name, path25, { exec: deps.verifyExec });
634548
+ let path26 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634549
+ if (name === "chromedriver" && isAllowedDriverPath(path26)) {
634550
+ let verify = await verifyDriverBinary(name, path26, { exec: deps.verifyExec });
633632
634551
  if (!verify.ok) {
633633
634552
  logger(`Installed ${name} ${latest} failed validation (${verify.error}); reinstalling once.`, "warn");
633634
634553
  try {
@@ -633637,11 +634556,11 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633637
634556
  logger(`Failed to prune broken ${name} ${latest}: ${String(err)}`, "debug");
633638
634557
  }
633639
634558
  await browsersModule.install({ browser: name, buildId: latest, cacheDir });
633640
- path25 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
633641
- verify = await verifyDriverBinary(name, path25, { exec: deps.verifyExec });
634559
+ path26 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634560
+ verify = await verifyDriverBinary(name, path26, { exec: deps.verifyExec });
633642
634561
  }
633643
634562
  if (!verify.ok) {
633644
- throw new Error(`${name} ${latest} is present but non-functional after a reinstall (${verify.error}). It may be a partial or corrupt download; delete ${path25} or reinstall.`);
634563
+ throw new Error(`${name} ${latest} is present but non-functional after a reinstall (${verify.error}). It may be a partial or corrupt download; delete ${path26} or reinstall.`);
633645
634564
  }
633646
634565
  }
633647
634566
  if (existing && existing.installedVersion !== latest) {
@@ -633662,7 +634581,7 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
633662
634581
  latestCheckedAt: now.toISOString()
633663
634582
  };
633664
634583
  writeInstalledRecord(record, ctx);
633665
- return { path: path25, version: latest, outdated: false };
634584
+ return { path: path26, version: latest, outdated: false };
633666
634585
  }
633667
634586
  async function locateExecutable(browsersModule, name, buildId, cacheDir, platform) {
633668
634587
  if (typeof browsersModule.computeExecutablePath === "function") {
@@ -633695,24 +634614,24 @@ async function withGeckodriverCacheDir(cacheDir, fn) {
633695
634614
  }
633696
634615
  }
633697
634616
  function isPathInside(child, dir) {
633698
- const resolvedDir = import_node_path5.default.resolve(dir);
633699
- const resolvedChild = import_node_path5.default.resolve(child);
633700
- return resolvedChild === resolvedDir || resolvedChild.startsWith(resolvedDir + import_node_path5.default.sep);
634617
+ const resolvedDir = import_node_path6.default.resolve(dir);
634618
+ const resolvedChild = import_node_path6.default.resolve(child);
634619
+ return resolvedChild === resolvedDir || resolvedChild.startsWith(resolvedDir + import_node_path6.default.sep);
633701
634620
  }
633702
634621
  function geckodriverBinaryInCache(cacheDir) {
633703
634622
  const binName = process.platform === "win32" ? "geckodriver.exe" : "geckodriver";
633704
- const rootCandidate = import_node_path5.default.join(cacheDir, binName);
634623
+ const rootCandidate = import_node_path6.default.join(cacheDir, binName);
633705
634624
  try {
633706
- if (import_node_fs6.default.existsSync(rootCandidate))
634625
+ if (import_node_fs8.default.existsSync(rootCandidate))
633707
634626
  return rootCandidate;
633708
634627
  } catch {
633709
634628
  }
633710
634629
  try {
633711
- for (const entry of import_node_fs6.default.readdirSync(cacheDir, { withFileTypes: true })) {
634630
+ for (const entry of import_node_fs8.default.readdirSync(cacheDir, { withFileTypes: true })) {
633712
634631
  if (!entry.isDirectory())
633713
634632
  continue;
633714
- const nested = import_node_path5.default.join(cacheDir, entry.name, binName);
633715
- if (import_node_fs6.default.existsSync(nested))
634633
+ const nested = import_node_path6.default.join(cacheDir, entry.name, binName);
634634
+ if (import_node_fs8.default.existsSync(nested))
633716
634635
  return nested;
633717
634636
  }
633718
634637
  } catch {
@@ -633750,8 +634669,8 @@ async function ensureGeckodriver(ctxBag, record, existing, logger) {
633750
634669
  if (!verify.ok) {
633751
634670
  logger(`Downloaded geckodriver failed validation (${verify.error}); re-downloading once.`, "warn");
633752
634671
  try {
633753
- if (binaryPath && binaryPath !== cacheDir && import_node_fs6.default.existsSync(binaryPath)) {
633754
- import_node_fs6.default.rmSync(binaryPath, { force: true });
634672
+ if (binaryPath && binaryPath !== cacheDir && import_node_fs8.default.existsSync(binaryPath)) {
634673
+ import_node_fs8.default.rmSync(binaryPath, { force: true });
633755
634674
  }
633756
634675
  } catch {
633757
634676
  }
@@ -633788,13 +634707,13 @@ function getInstalledBrowsers(ctx = {}) {
633788
634707
  latestKnownVersion: entry.latestKnownVersion
633789
634708
  }));
633790
634709
  }
633791
- var import_node_child_process3, import_node_fs6, import_node_path5, DRIVER_VERSION_ARGS, DRIVER_VERIFY_TIMEOUT_MS, ALLOWED_DRIVER_PATH, defaultDriverExec, BROWSER_CHANNELS, FRESHNESS_TTL_MS, RESOLVE_TIMEOUT_MS, RUNTIME_DEBUG2, defaultLogger2, inFlightInstalls, geckodriverEnvQueue;
634710
+ var import_node_child_process5, import_node_fs8, import_node_path6, DRIVER_VERSION_ARGS, DRIVER_VERIFY_TIMEOUT_MS, ALLOWED_DRIVER_PATH, defaultDriverExec, BROWSER_CHANNELS, FRESHNESS_TTL_MS, RESOLVE_TIMEOUT_MS, RUNTIME_DEBUG2, defaultLogger2, inFlightInstalls2, geckodriverEnvQueue;
633792
634711
  var init_browsers = __esm({
633793
634712
  "dist/runtime/browsers.js"() {
633794
634713
  "use strict";
633795
- import_node_child_process3 = require("node:child_process");
633796
- import_node_fs6 = __toESM(require("node:fs"), 1);
633797
- import_node_path5 = __toESM(require("node:path"), 1);
634714
+ import_node_child_process5 = require("node:child_process");
634715
+ import_node_fs8 = __toESM(require("node:fs"), 1);
634716
+ import_node_path6 = __toESM(require("node:path"), 1);
633798
634717
  init_cacheDir();
633799
634718
  init_loader();
633800
634719
  DRIVER_VERSION_ARGS = {
@@ -633805,7 +634724,7 @@ var init_browsers = __esm({
633805
634724
  DRIVER_VERIFY_TIMEOUT_MS = 1e4;
633806
634725
  ALLOWED_DRIVER_PATH = /[\\/](?:geckodriver|chromedriver|safaridriver)(?:\.exe)?$/i;
633807
634726
  defaultDriverExec = (binaryPath, args, timeoutMs) => new Promise((resolve) => {
633808
- (0, import_node_child_process3.execFile)(binaryPath, args, { timeout: timeoutMs, windowsHide: true }, (err, stdout, stderr) => {
634727
+ (0, import_node_child_process5.execFile)(binaryPath, args, { timeout: timeoutMs, windowsHide: true }, (err, stdout, stderr) => {
633809
634728
  const out = typeof stdout === "string" ? stdout : String(stdout ?? "");
633810
634729
  const errOut = typeof stderr === "string" ? stderr : String(stderr ?? "");
633811
634730
  if (err && typeof err.code === "number") {
@@ -633834,22 +634753,22 @@ var init_browsers = __esm({
633834
634753
  else
633835
634754
  console.log(msg);
633836
634755
  };
633837
- inFlightInstalls = /* @__PURE__ */ new Map();
634756
+ inFlightInstalls2 = /* @__PURE__ */ new Map();
633838
634757
  geckodriverEnvQueue = Promise.resolve();
633839
634758
  }
633840
634759
  });
633841
634760
 
633842
634761
  // dist/core/appium.js
633843
634762
  function appiumHomeForDriverPath(driverEntry) {
633844
- const marker = `${import_node_path6.default.sep}node_modules${import_node_path6.default.sep}`;
634763
+ const marker = `${import_node_path7.default.sep}node_modules${import_node_path7.default.sep}`;
633845
634764
  const idx = driverEntry.lastIndexOf(marker);
633846
634765
  return idx === -1 ? null : driverEntry.slice(0, idx);
633847
634766
  }
633848
634767
  function runtimeHomeHasBrowserDriver(runtimeDir) {
633849
- const nm = import_node_path6.default.join(runtimeDir, "node_modules");
633850
- if (!(0, import_node_fs7.existsSync)(import_node_path6.default.join(nm, "appium")))
634768
+ const nm = import_node_path7.default.join(runtimeDir, "node_modules");
634769
+ if (!(0, import_node_fs9.existsSync)(import_node_path7.default.join(nm, "appium")))
633851
634770
  return false;
633852
- return BROWSER_DRIVER_PACKAGES.some((driver) => (0, import_node_fs7.existsSync)(import_node_path6.default.join(nm, driver)));
634771
+ return BROWSER_DRIVER_PACKAGES.some((driver) => (0, import_node_fs9.existsSync)(import_node_path7.default.join(nm, driver)));
633853
634772
  }
633854
634773
  function setAppiumHome(ctx = {}) {
633855
634774
  const runtimeDir = getRuntimeDir({ cacheDir: ctx.cacheDir });
@@ -633867,27 +634786,27 @@ function setAppiumHome(ctx = {}) {
633867
634786
  return;
633868
634787
  }
633869
634788
  }
633870
- const corePath = import_node_path6.default.join(__dirname3, "../../node_modules");
634789
+ const corePath = import_node_path7.default.join(__dirname3, "../../node_modules");
633871
634790
  const pathArray = corePath.split("node_modules");
633872
634791
  let appiumParentPath = pathArray[0];
633873
634792
  for (let i = 1; i < pathArray.length; i++) {
633874
- if ((0, import_node_fs7.existsSync)(import_node_path6.default.join(appiumParentPath, "node_modules", "appium"))) {
634793
+ if ((0, import_node_fs9.existsSync)(import_node_path7.default.join(appiumParentPath, "node_modules", "appium"))) {
633875
634794
  break;
633876
634795
  }
633877
- appiumParentPath = import_node_path6.default.join(appiumParentPath, "node_modules", pathArray[i]);
634796
+ appiumParentPath = import_node_path7.default.join(appiumParentPath, "node_modules", pathArray[i]);
633878
634797
  }
633879
634798
  process.env.APPIUM_HOME = appiumParentPath;
633880
634799
  }
633881
- var import_node_path6, import_node_fs7, import_node_url4, __dirname3, BROWSER_DRIVER_PACKAGES;
634800
+ var import_node_path7, import_node_fs9, import_node_url4, __dirname3, BROWSER_DRIVER_PACKAGES;
633882
634801
  var init_appium = __esm({
633883
634802
  "dist/core/appium.js"() {
633884
634803
  "use strict";
633885
- import_node_path6 = __toESM(require("node:path"), 1);
633886
- import_node_fs7 = require("node:fs");
634804
+ import_node_path7 = __toESM(require("node:path"), 1);
634805
+ import_node_fs9 = require("node:fs");
633887
634806
  import_node_url4 = require("node:url");
633888
634807
  init_cacheDir();
633889
634808
  init_loader();
633890
- __dirname3 = import_node_path6.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
634809
+ __dirname3 = import_node_path7.default.dirname((0, import_node_url4.fileURLToPath)(importMetaUrl));
633891
634810
  BROWSER_DRIVER_PACKAGES = [
633892
634811
  "appium-chromium-driver",
633893
634812
  "appium-geckodriver",
@@ -633924,7 +634843,7 @@ async function readFile({ fileURLOrPath }) {
633924
634843
  }
633925
634844
  } else {
633926
634845
  try {
633927
- content = await import_node_fs8.default.promises.readFile(fileURLOrPath, "utf8");
634846
+ content = await import_node_fs10.default.promises.readFile(fileURLOrPath, "utf8");
633928
634847
  } catch (error) {
633929
634848
  if (error.code === "ENOENT") {
633930
634849
  console.warn(`File not found: ${fileURLOrPath}`);
@@ -633996,13 +634915,13 @@ async function resolvePaths({ config, object, filePath, nested = false, objectTy
633996
634915
  if (relativePath.startsWith("https://") || relativePath.startsWith("http://") || relativePath.startsWith("heretto:")) {
633997
634916
  return relativePath;
633998
634917
  }
633999
- if (import_node_path7.default.isAbsolute(relativePath)) {
634918
+ if (import_node_path8.default.isAbsolute(relativePath)) {
634000
634919
  return relativePath;
634001
634920
  }
634002
- const fileExists = import_node_fs8.default.existsSync(filePath2);
634003
- const isFile = fileExists ? import_node_fs8.default.lstatSync(filePath2).isFile() : import_node_path7.default.parse(filePath2).ext !== "";
634004
- const basePath = isFile ? import_node_path7.default.dirname(filePath2) : filePath2;
634005
- return baseType === "file" ? import_node_path7.default.resolve(basePath, relativePath) : import_node_path7.default.resolve(relativePath);
634921
+ const fileExists = import_node_fs10.default.existsSync(filePath2);
634922
+ const isFile = fileExists ? import_node_fs10.default.lstatSync(filePath2).isFile() : import_node_path8.default.parse(filePath2).ext !== "";
634923
+ const basePath = isFile ? import_node_path8.default.dirname(filePath2) : filePath2;
634924
+ return baseType === "file" ? import_node_path8.default.resolve(basePath, relativePath) : import_node_path8.default.resolve(relativePath);
634006
634925
  }
634007
634926
  const relativePathBase = config.relativePathBase;
634008
634927
  let pathProperties;
@@ -634052,7 +634971,7 @@ async function resolvePaths({ config, object, filePath, nested = false, objectTy
634052
634971
  isStep: property === "steps"
634053
634972
  });
634054
634973
  } else if (typeof item === "string" && pathProperties.includes(property)) {
634055
- const resolved = property === "path" && object.directory && import_node_path7.default.isAbsolute(object.directory) ? resolve(relativePathBase, item, object.directory) : resolve(relativePathBase, item, filePath);
634974
+ const resolved = property === "path" && object.directory && import_node_path8.default.isAbsolute(object.directory) ? resolve(relativePathBase, item, object.directory) : resolve(relativePathBase, item, filePath);
634056
634975
  object[property][i] = resolved;
634057
634976
  }
634058
634977
  }
@@ -634070,7 +634989,7 @@ async function resolvePaths({ config, object, filePath, nested = false, objectTy
634070
634989
  }
634071
634990
  if (pathProperties.includes(property) || isStep && stepShorthandPathProperties.includes(property)) {
634072
634991
  if (property === "path" && object.directory) {
634073
- const directory = import_node_path7.default.isAbsolute(object.directory) ? object.directory : resolve(relativePathBase, object.directory, filePath);
634992
+ const directory = import_node_path8.default.isAbsolute(object.directory) ? object.directory : resolve(relativePathBase, object.directory, filePath);
634074
634993
  object[property] = resolve(relativePathBase, object[property], directory);
634075
634994
  } else {
634076
634995
  object[property] = resolve(relativePathBase, object[property], filePath);
@@ -634080,12 +634999,12 @@ async function resolvePaths({ config, object, filePath, nested = false, objectTy
634080
634999
  }
634081
635000
  return object;
634082
635001
  }
634083
- var import_node_fs8, import_node_path7, import_yaml, import_axios2;
635002
+ var import_node_fs10, import_node_path8, import_yaml, import_axios2;
634084
635003
  var init_files = __esm({
634085
635004
  "dist/core/files.js"() {
634086
635005
  "use strict";
634087
- import_node_fs8 = __toESM(require("node:fs"), 1);
634088
- import_node_path7 = __toESM(require("node:path"), 1);
635006
+ import_node_fs10 = __toESM(require("node:fs"), 1);
635007
+ import_node_path8 = __toESM(require("node:path"), 1);
634089
635008
  import_yaml = __toESM(require("yaml"), 1);
634090
635009
  import_axios2 = __toESM(require("axios"), 1);
634091
635010
  init_validate();
@@ -634108,10 +635027,10 @@ async function getOperation(definition = {}, operationId = "", responseCode = ""
634108
635027
  if (!operationId) {
634109
635028
  throw new Error("OperationId is required.");
634110
635029
  }
634111
- for (const path25 in definition.paths) {
634112
- for (const method in definition.paths[path25]) {
634113
- if (definition.paths[path25][method].operationId === operationId) {
634114
- const operation = definition.paths[path25][method];
635030
+ for (const path26 in definition.paths) {
635031
+ for (const method in definition.paths[path26]) {
635032
+ if (definition.paths[path26][method].operationId === operationId) {
635033
+ const operation = definition.paths[path26][method];
634115
635034
  if (!server) {
634116
635035
  if (definition.servers && definition.servers.length > 0) {
634117
635036
  server = definition.servers[0].url;
@@ -634119,9 +635038,9 @@ async function getOperation(definition = {}, operationId = "", responseCode = ""
634119
635038
  throw new Error("No server URL provided and no servers defined in the OpenAPI definition.");
634120
635039
  }
634121
635040
  }
634122
- const example = await compileExample(operation, server + path25, responseCode, exampleKey);
635041
+ const example = await compileExample(operation, server + path26, responseCode, exampleKey);
634123
635042
  const schemas2 = getSchemas(operation, responseCode);
634124
- return { path: path25, method, definition: operation, schemas: schemas2, example };
635043
+ return { path: path26, method, definition: operation, schemas: schemas2, example };
634125
635044
  }
634126
635045
  }
634127
635046
  }
@@ -634142,15 +635061,15 @@ function getSchemas(definition = {}, responseCode = "") {
634142
635061
  schemas2.response = definition.responses[responseCode].content[Object.keys(definition.responses[responseCode].content)[0]].schema;
634143
635062
  return schemas2;
634144
635063
  }
634145
- async function compileExample(operation = {}, path25 = "", responseCode = "", exampleKey = "") {
635064
+ async function compileExample(operation = {}, path26 = "", responseCode = "", exampleKey = "") {
634146
635065
  if (!operation) {
634147
635066
  throw new Error("Operation is required.");
634148
635067
  }
634149
- if (!path25) {
635068
+ if (!path26) {
634150
635069
  throw new Error("Path is required.");
634151
635070
  }
634152
635071
  let example = {
634153
- url: path25,
635072
+ url: path26,
634154
635073
  request: { parameters: {}, headers: {}, body: {} },
634155
635074
  response: { headers: {}, body: {} }
634156
635075
  };
@@ -634529,7 +635448,7 @@ function clearAppCache(config) {
634529
635448
  async function probeBrowserEnvironment({ config, browsersDir }) {
634530
635449
  setAppiumHome({ cacheDir: config?.cacheDir });
634531
635450
  const cwd = process.cwd();
634532
- process.chdir(import_node_path8.default.join(__dirname4, "../.."));
635451
+ process.chdir(import_node_path9.default.join(__dirname4, "../.."));
634533
635452
  let installedBrowsers = [];
634534
635453
  let browserDetectionFailed = false;
634535
635454
  let appiumDriverOutput = "";
@@ -634564,7 +635483,7 @@ async function probeBrowserEnvironment({ config, browsersDir }) {
634564
635483
  });
634565
635484
  return;
634566
635485
  }
634567
- const child = (0, import_node_child_process4.spawn)(process.execPath, [appiumEntry, "driver", "list"], { env: process.env });
635486
+ const child = (0, import_node_child_process6.spawn)(process.execPath, [appiumEntry, "driver", "list"], { env: process.env });
634568
635487
  let stdout = "";
634569
635488
  let stderr = "";
634570
635489
  child.stdout?.on("data", (c) => {
@@ -634664,7 +635583,7 @@ function probeSafariVersion(timeoutMs) {
634664
635583
  return new Promise((resolve) => {
634665
635584
  let child;
634666
635585
  try {
634667
- child = (0, import_node_child_process4.spawn)("defaults", [
635586
+ child = (0, import_node_child_process6.spawn)("defaults", [
634668
635587
  "read",
634669
635588
  "/Applications/Safari.app/Contents/Info.plist",
634670
635589
  "CFBundleShortVersionString"
@@ -634745,7 +635664,7 @@ async function getBrowserDiagnostics({ config }) {
634745
635664
  const version = await probeSafariVersion(4e3);
634746
635665
  safariApp = version !== null;
634747
635666
  safariVersion = version ?? void 0;
634748
- safaridriver = import_node_fs9.default.existsSync("/usr/bin/safaridriver");
635667
+ safaridriver = import_node_fs11.default.existsSync("/usr/bin/safaridriver");
634749
635668
  } catch {
634750
635669
  detectionFailed = true;
634751
635670
  }
@@ -634767,23 +635686,23 @@ async function getBrowserDiagnostics({ config }) {
634767
635686
  });
634768
635687
  return { browsers, detectionFailed };
634769
635688
  }
634770
- var import_node_os3, import_node_fs9, import_node_path8, import_node_child_process4, import_node_url5, __dirname4, platformMap, defaultFileTypes, cachedAppsByDir;
635689
+ var import_node_os3, import_node_fs11, import_node_path9, import_node_child_process6, import_node_url5, __dirname4, platformMap, defaultFileTypes, cachedAppsByDir;
634771
635690
  var init_config = __esm({
634772
635691
  "dist/core/config.js"() {
634773
635692
  "use strict";
634774
635693
  import_node_os3 = __toESM(require("node:os"), 1);
634775
- import_node_fs9 = __toESM(require("node:fs"), 1);
635694
+ import_node_fs11 = __toESM(require("node:fs"), 1);
634776
635695
  init_validate();
634777
635696
  init_utils();
634778
- import_node_path8 = __toESM(require("node:path"), 1);
634779
- import_node_child_process4 = require("node:child_process");
635697
+ import_node_path9 = __toESM(require("node:path"), 1);
635698
+ import_node_child_process6 = require("node:child_process");
634780
635699
  init_loader();
634781
635700
  init_cacheDir();
634782
635701
  init_browsers();
634783
635702
  init_appium();
634784
635703
  init_openapi();
634785
635704
  import_node_url5 = require("node:url");
634786
- __dirname4 = import_node_path8.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
635705
+ __dirname4 = import_node_path9.default.dirname((0, import_node_url5.fileURLToPath)(importMetaUrl));
634787
635706
  platformMap = {
634788
635707
  darwin: "mac",
634789
635708
  linux: "linux",
@@ -635108,13 +636027,15 @@ var inferRuntimeNeeds_exports = {};
635108
636027
  __export(inferRuntimeNeeds_exports, {
635109
636028
  inferRuntimeNeeds: () => inferRuntimeNeeds
635110
636029
  });
635111
- function inferRuntimeNeeds(resolvedSpecs) {
636030
+ function inferRuntimeNeeds(resolvedSpecs, options = {}) {
635112
636031
  const browsers = /* @__PURE__ */ new Set();
635113
636032
  const npmPackages = /* @__PURE__ */ new Set();
636033
+ const configShell = options.configShell ?? "bash";
635114
636034
  const specs = Array.isArray(resolvedSpecs) ? resolvedSpecs : resolvedSpecs && Array.isArray(resolvedSpecs.specs) ? resolvedSpecs.specs : [];
635115
636035
  let sawBrowserStep = false;
635116
636036
  let sawScreenshotStep = false;
635117
636037
  let sawRecordingStep = false;
636038
+ let sawBashShellStep = false;
635118
636039
  for (const spec of specs) {
635119
636040
  collectBrowserNamesFromRunOn(spec?.runOn, browsers);
635120
636041
  for (const test of arrayOrEmpty(spec?.tests)) {
@@ -635132,6 +636053,8 @@ function inferRuntimeNeeds(resolvedSpecs) {
635132
636053
  sawScreenshotStep = true;
635133
636054
  if (flags.recording)
635134
636055
  sawRecordingStep = true;
636056
+ if (stepNeedsBash(step, configShell))
636057
+ sawBashShellStep = true;
635135
636058
  collectStartSurfaceEngines(step, browsers);
635136
636059
  }
635137
636060
  }
@@ -635143,6 +636066,8 @@ function inferRuntimeNeeds(resolvedSpecs) {
635143
636066
  sawScreenshotStep = true;
635144
636067
  if (flags.recording)
635145
636068
  sawRecordingStep = true;
636069
+ if (stepNeedsBash(step, configShell))
636070
+ sawBashShellStep = true;
635146
636071
  collectStartSurfaceEngines(step, browsers);
635147
636072
  }
635148
636073
  }
@@ -635172,7 +636097,26 @@ function inferRuntimeNeeds(resolvedSpecs) {
635172
636097
  if (sawRecordingStep) {
635173
636098
  npmPackages.add("@ffmpeg-installer/ffmpeg");
635174
636099
  }
635175
- return { browsers, npmPackages };
636100
+ return { browsers, npmPackages, windowsBash: sawBashShellStep };
636101
+ }
636102
+ function stepNeedsBash(step, configShell) {
636103
+ if (!step || typeof step !== "object")
636104
+ return false;
636105
+ if ("runShell" in step) {
636106
+ const stepShell = step.runShell && typeof step.runShell === "object" ? step.runShell.shell : void 0;
636107
+ if ((stepShell ?? configShell) === "bash")
636108
+ return true;
636109
+ }
636110
+ if ("runCode" in step && step.runCode?.language === "bash")
636111
+ return true;
636112
+ if ("startSurface" in step && configShell === "bash") {
636113
+ for (const d of startSurfaceDescriptors(step)) {
636114
+ if (d && typeof d === "object" && typeof d.process === "string") {
636115
+ return true;
636116
+ }
636117
+ }
636118
+ }
636119
+ return false;
635176
636120
  }
635177
636121
  function arrayOrEmpty(v) {
635178
636122
  return Array.isArray(v) ? v : [];
@@ -635252,10 +636196,10 @@ module.exports = __toCommonJS(index_exports);
635252
636196
  init_config();
635253
636197
 
635254
636198
  // dist/core/detectTests.js
635255
- var import_node_fs11 = __toESM(require("node:fs"), 1);
635256
- var import_node_path10 = __toESM(require("node:path"), 1);
636199
+ var import_node_fs13 = __toESM(require("node:fs"), 1);
636200
+ var import_node_path11 = __toESM(require("node:path"), 1);
635257
636201
  var import_node_os5 = __toESM(require("node:os"), 1);
635258
- var import_node_crypto3 = __toESM(require("node:crypto"), 1);
636202
+ var import_node_crypto4 = __toESM(require("node:crypto"), 1);
635259
636203
  var import_yaml3 = __toESM(require("yaml"), 1);
635260
636204
  init_validate();
635261
636205
 
@@ -636131,13 +637075,13 @@ init_files();
636131
637075
  init_utils();
636132
637076
 
636133
637077
  // dist/core/integrations/heretto.js
636134
- var import_node_fs10 = __toESM(require("node:fs"), 1);
636135
- var import_node_path9 = __toESM(require("node:path"), 1);
636136
- var import_node_https = __toESM(require("node:https"), 1);
637078
+ var import_node_fs12 = __toESM(require("node:fs"), 1);
637079
+ var import_node_path10 = __toESM(require("node:path"), 1);
637080
+ var import_node_https2 = __toESM(require("node:https"), 1);
636137
637081
  var import_node_http = __toESM(require("node:http"), 1);
636138
637082
  var import_axios3 = __toESM(require("axios"), 1);
636139
637083
  var import_node_os4 = __toESM(require("node:os"), 1);
636140
- var import_node_crypto2 = __toESM(require("node:crypto"), 1);
637084
+ var import_node_crypto3 = __toESM(require("node:crypto"), 1);
636141
637085
  var import_adm_zip = __toESM(require("adm-zip"), 1);
636142
637086
  var HerettoUploader = class {
636143
637087
  /**
@@ -636174,7 +637118,7 @@ var HerettoUploader = class {
636174
637118
  const apiBaseUrl = `https://${integrationConfig.organizationId}.heretto.com`;
636175
637119
  let fileId = sourceIntegration.fileId;
636176
637120
  let parentFolderId = sourceIntegration.parentFolderId;
636177
- const filename = import_node_path9.default.basename(sourceIntegration.filePath);
637121
+ const filename = import_node_path10.default.basename(sourceIntegration.filePath);
636178
637122
  const relativeFilePath = sourceIntegration.filePath;
636179
637123
  if (!fileId && integrationConfig.resourceDependencies) {
636180
637124
  const resolvedFile = this.resolveFromDependencies({
@@ -636214,9 +637158,9 @@ var HerettoUploader = class {
636214
637158
  }
636215
637159
  }
636216
637160
  if (!parentFolderId && relativeFilePath) {
636217
- const parentDirPath = import_node_path9.default.dirname(relativeFilePath);
637161
+ const parentDirPath = import_node_path10.default.dirname(relativeFilePath);
636218
637162
  if (parentDirPath && parentDirPath !== ".") {
636219
- const folderName = import_node_path9.default.basename(parentDirPath);
637163
+ const folderName = import_node_path10.default.basename(parentDirPath);
636220
637164
  log3(config, "debug", `Searching for parent folder by name: ${folderName}`);
636221
637165
  parentFolderId = await this.searchFolderByName({
636222
637166
  apiBaseUrl,
@@ -636292,11 +637236,11 @@ var HerettoUploader = class {
636292
637236
  return result;
636293
637237
  }
636294
637238
  }
636295
- if (!import_node_fs10.default.existsSync(localFilePath)) {
637239
+ if (!import_node_fs12.default.existsSync(localFilePath)) {
636296
637240
  result.description = `Local file not found: ${localFilePath}`;
636297
637241
  return result;
636298
637242
  }
636299
- const fileContent = import_node_fs10.default.readFileSync(localFilePath);
637243
+ const fileContent = import_node_fs12.default.readFileSync(localFilePath);
636300
637244
  const contentType = this.getContentType(localFilePath);
636301
637245
  try {
636302
637246
  await this.uploadFile({
@@ -636327,7 +637271,7 @@ var HerettoUploader = class {
636327
637271
  resolveFromDependencies({ resourceDependencies, filePath, filename, log: log3 }) {
636328
637272
  if (!resourceDependencies)
636329
637273
  return null;
636330
- const normalizedPath = import_node_path9.default.posix.normalize(filePath.replace(/\\/g, "/")).replace(/^\.\.\/+/g, "").replace(/^\.\//, "");
637274
+ const normalizedPath = import_node_path10.default.posix.normalize(filePath.replace(/\\/g, "/")).replace(/^\.\.\/+/g, "").replace(/^\.\//, "");
636331
637275
  for (const [depPath, info] of Object.entries(resourceDependencies)) {
636332
637276
  if (depPath.startsWith("_"))
636333
637277
  continue;
@@ -636337,14 +637281,14 @@ var HerettoUploader = class {
636337
637281
  return info;
636338
637282
  }
636339
637283
  }
636340
- const parentDir2 = import_node_path9.default.dirname(normalizedPath);
636341
- const parentFolderName = import_node_path9.default.basename(parentDir2);
637284
+ const parentDir2 = import_node_path10.default.dirname(normalizedPath);
637285
+ const parentFolderName = import_node_path10.default.basename(parentDir2);
636342
637286
  for (const [depPath, info] of Object.entries(resourceDependencies)) {
636343
637287
  if (depPath.startsWith("_"))
636344
637288
  continue;
636345
- const depFilename = import_node_path9.default.basename(depPath);
636346
- const depParentDir = import_node_path9.default.dirname(depPath);
636347
- const depParentFolderName = import_node_path9.default.basename(depParentDir);
637289
+ const depFilename = import_node_path10.default.basename(depPath);
637290
+ const depParentDir = import_node_path10.default.dirname(depPath);
637291
+ const depParentFolderName = import_node_path10.default.basename(depParentDir);
636348
637292
  if (depFilename === filename && depParentFolderName === parentFolderName) {
636349
637293
  log3("debug", `Found filename+folder match in dependencies: ${depPath}`);
636350
637294
  return info;
@@ -636353,7 +637297,7 @@ var HerettoUploader = class {
636353
637297
  for (const [depPath, info] of Object.entries(resourceDependencies)) {
636354
637298
  if (depPath.startsWith("_"))
636355
637299
  continue;
636356
- const depFilename = import_node_path9.default.basename(depPath);
637300
+ const depFilename = import_node_path10.default.basename(depPath);
636357
637301
  if (depFilename === filename) {
636358
637302
  log3("debug", `Found filename match in dependencies: ${depPath}`);
636359
637303
  return info;
@@ -636384,17 +637328,17 @@ var HerettoUploader = class {
636384
637328
  };
636385
637329
  if (!resourceDependencies)
636386
637330
  return result;
636387
- const normalizedPath = import_node_path9.default.posix.normalize(filePath.replace(/\\/g, "/")).replace(/^(\.\.\/)+/g, "").replace(/^\.\//, "");
636388
- const parentDir2 = import_node_path9.default.dirname(normalizedPath);
636389
- const targetFolderName = import_node_path9.default.basename(parentDir2);
637331
+ const normalizedPath = import_node_path10.default.posix.normalize(filePath.replace(/\\/g, "/")).replace(/^(\.\.\/)+/g, "").replace(/^\.\//, "");
637332
+ const parentDir2 = import_node_path10.default.dirname(normalizedPath);
637333
+ const targetFolderName = import_node_path10.default.basename(parentDir2);
636390
637334
  result.targetFolderName = targetFolderName;
636391
637335
  result.ditamapParentFolderId = resourceDependencies._ditamapParentFolderId || null;
636392
637336
  log3("debug", `Looking for parent folder '${targetFolderName}' in dependencies`);
636393
637337
  for (const [depPath, info] of Object.entries(resourceDependencies)) {
636394
637338
  if (depPath.startsWith("_"))
636395
637339
  continue;
636396
- const depParentDir = import_node_path9.default.dirname(depPath);
636397
- const depFolderName = import_node_path9.default.basename(depParentDir);
637340
+ const depParentDir = import_node_path10.default.dirname(depPath);
637341
+ const depFolderName = import_node_path10.default.basename(depParentDir);
636398
637342
  if (depFolderName === targetFolderName && info.parentFolderId) {
636399
637343
  log3("debug", `Found sibling file ${depPath} with parent folder ID: ${info.parentFolderId}`);
636400
637344
  result.folderId = info.parentFolderId;
@@ -636421,7 +637365,7 @@ var HerettoUploader = class {
636421
637365
  async getChildFolderByName({ apiBaseUrl, apiToken, username, parentFolderId, folderName, log: log3 }) {
636422
637366
  const folderUrl = new URL(`/rest/all-files/${parentFolderId}`, apiBaseUrl);
636423
637367
  return new Promise((resolve, reject) => {
636424
- const protocol = folderUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637368
+ const protocol = folderUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636425
637369
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636426
637370
  const options = {
636427
637371
  hostname: folderUrl.hostname,
@@ -636480,7 +637424,7 @@ var HerettoUploader = class {
636480
637424
  const createUrl = new URL(`/rest/all-files/${parentFolderId}`, apiBaseUrl);
636481
637425
  const createBody = `<resource><name>${this.escapeXml(filename)}</name><mime-type>${mimeType}</mime-type></resource>`;
636482
637426
  return new Promise((resolve, reject) => {
636483
- const protocol = createUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637427
+ const protocol = createUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636484
637428
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636485
637429
  const options = {
636486
637430
  hostname: createUrl.hostname,
@@ -636539,7 +637483,7 @@ var HerettoUploader = class {
636539
637483
  async getFileInFolder({ apiBaseUrl, apiToken, username, folderId, filename, log: log3 }) {
636540
637484
  const folderUrl = new URL(`/rest/all-files/${folderId}`, apiBaseUrl);
636541
637485
  return new Promise((resolve, reject) => {
636542
- const protocol = folderUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637486
+ const protocol = folderUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636543
637487
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636544
637488
  const options = {
636545
637489
  hostname: folderUrl.hostname,
@@ -636611,7 +637555,7 @@ var HerettoUploader = class {
636611
637555
  searchResultType: "FOLDERS_ONLY"
636612
637556
  });
636613
637557
  return new Promise((resolve, reject) => {
636614
- const protocol = searchUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637558
+ const protocol = searchUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636615
637559
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636616
637560
  const options = {
636617
637561
  hostname: searchUrl.hostname,
@@ -636682,7 +637626,7 @@ var HerettoUploader = class {
636682
637626
  searchResultType: "FILES_ONLY"
636683
637627
  });
636684
637628
  return new Promise((resolve, reject) => {
636685
- const protocol = searchUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637629
+ const protocol = searchUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636686
637630
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636687
637631
  const options = {
636688
637632
  hostname: searchUrl.hostname,
@@ -636745,7 +637689,7 @@ var HerettoUploader = class {
636745
637689
  async uploadFile({ apiBaseUrl, apiToken, username, documentId, content, contentType, log: log3 }) {
636746
637690
  const uploadUrl = new URL(`/rest/all-files/${documentId}/content`, apiBaseUrl);
636747
637691
  return new Promise((resolve, reject) => {
636748
- const protocol = uploadUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637692
+ const protocol = uploadUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636749
637693
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636750
637694
  const options = {
636751
637695
  hostname: uploadUrl.hostname,
@@ -636791,7 +637735,7 @@ var HerettoUploader = class {
636791
637735
  async getDocumentInfo({ apiBaseUrl, apiToken, username, documentId, log: log3 }) {
636792
637736
  const docUrl = new URL(`/rest/all-files/${documentId}`, apiBaseUrl);
636793
637737
  return new Promise((resolve, reject) => {
636794
- const protocol = docUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637738
+ const protocol = docUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636795
637739
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636796
637740
  const options = {
636797
637741
  hostname: docUrl.hostname,
@@ -636858,7 +637802,7 @@ var HerettoUploader = class {
636858
637802
  async getDocumentContent({ apiBaseUrl, apiToken, username, documentId, log: log3 }) {
636859
637803
  const contentUrl = new URL(`/rest/all-files/${documentId}/content`, apiBaseUrl);
636860
637804
  return new Promise((resolve, reject) => {
636861
- const protocol = contentUrl.protocol === "https:" ? import_node_https.default : import_node_http.default;
637805
+ const protocol = contentUrl.protocol === "https:" ? import_node_https2.default : import_node_http.default;
636862
637806
  const authString = Buffer.from(`${username}:${apiToken}`).toString("base64");
636863
637807
  const options = {
636864
637808
  hostname: contentUrl.hostname,
@@ -636898,7 +637842,7 @@ var HerettoUploader = class {
636898
637842
  * @returns {string} MIME content type
636899
637843
  */
636900
637844
  getContentType(filePath) {
636901
- const ext = import_node_path9.default.extname(filePath).toLowerCase();
637845
+ const ext = import_node_path10.default.extname(filePath).toLowerCase();
636902
637846
  const contentTypes = {
636903
637847
  ".png": "image/png",
636904
637848
  ".jpg": "image/jpeg",
@@ -637070,39 +638014,39 @@ async function pollJobStatus(client, fileId, jobId, log3, config) {
637070
638014
  return null;
637071
638015
  }
637072
638016
  async function downloadAndExtractOutput(client, fileId, jobId, herettoName, log3, config, deps) {
637073
- const fsModule = deps?.fsModule || import_node_fs10.default;
638017
+ const fsModule = deps?.fsModule || import_node_fs12.default;
637074
638018
  const ZipClass = deps?.ZipClass || import_adm_zip.default;
637075
- const tempDir = import_node_path9.default.join(import_node_os4.default.tmpdir(), "doc-detective");
637076
- const hash = import_node_crypto2.default.createHash("md5").update(`${herettoName}_${jobId}`).digest("hex");
638019
+ const tempDir = import_node_path10.default.join(import_node_os4.default.tmpdir(), "doc-detective");
638020
+ const hash = import_node_crypto3.default.createHash("md5").update(`${herettoName}_${jobId}`).digest("hex");
637077
638021
  try {
637078
638022
  fsModule.mkdirSync(tempDir, { recursive: true });
637079
- const outputDir = import_node_path9.default.join(tempDir, `heretto_${hash}`);
638023
+ const outputDir = import_node_path10.default.join(tempDir, `heretto_${hash}`);
637080
638024
  log3(config, "debug", `Downloading publishing job output for ${herettoName}...`);
637081
638025
  const response = await client.get(`/files/${fileId}/publishes/${jobId}/assets-all`, {
637082
638026
  responseType: "arraybuffer",
637083
638027
  timeout: DOWNLOAD_TIMEOUT_MS,
637084
638028
  headers: { Accept: "application/octet-stream" }
637085
638029
  });
637086
- const zipPath = import_node_path9.default.join(tempDir, `heretto_${hash}.zip`);
638030
+ const zipPath = import_node_path10.default.join(tempDir, `heretto_${hash}.zip`);
637087
638031
  fsModule.writeFileSync(zipPath, response.data);
637088
638032
  log3(config, "debug", `Extracting output to ${outputDir}...`);
637089
638033
  const zip = new ZipClass(zipPath);
637090
- const resolvedOutputDir = import_node_path9.default.resolve(outputDir);
638034
+ const resolvedOutputDir = import_node_path10.default.resolve(outputDir);
637091
638035
  for (const entry of zip.getEntries()) {
637092
- const normalizedName = import_node_path9.default.posix.normalize(entry.entryName.replace(/\\/g, "/"));
638036
+ const normalizedName = import_node_path10.default.posix.normalize(entry.entryName.replace(/\\/g, "/"));
637093
638037
  if (normalizedName.startsWith("..") || normalizedName.includes("/..")) {
637094
638038
  log3(config, "warning", `Skipping ZIP entry with path traversal: ${entry.entryName}`);
637095
638039
  continue;
637096
638040
  }
637097
- const resolvedPath = import_node_path9.default.resolve(outputDir, normalizedName);
637098
- if (!resolvedPath.startsWith(resolvedOutputDir + import_node_path9.default.sep) && resolvedPath !== resolvedOutputDir) {
638041
+ const resolvedPath = import_node_path10.default.resolve(outputDir, normalizedName);
638042
+ if (!resolvedPath.startsWith(resolvedOutputDir + import_node_path10.default.sep) && resolvedPath !== resolvedOutputDir) {
637099
638043
  log3(config, "warning", `Skipping ZIP entry outside output directory: ${entry.entryName}`);
637100
638044
  continue;
637101
638045
  }
637102
638046
  if (entry.isDirectory) {
637103
638047
  fsModule.mkdirSync(resolvedPath, { recursive: true });
637104
638048
  } else {
637105
- fsModule.mkdirSync(import_node_path9.default.dirname(resolvedPath), { recursive: true });
638049
+ fsModule.mkdirSync(import_node_path10.default.dirname(resolvedPath), { recursive: true });
637106
638050
  fsModule.writeFileSync(resolvedPath, entry.getData());
637107
638051
  }
637108
638052
  }
@@ -637111,14 +638055,14 @@ async function downloadAndExtractOutput(client, fileId, jobId, herettoName, log3
637111
638055
  return outputDir;
637112
638056
  } catch (error) {
637113
638057
  try {
637114
- const zipCleanupPath = import_node_path9.default.join(tempDir, `heretto_${hash}.zip`);
638058
+ const zipCleanupPath = import_node_path10.default.join(tempDir, `heretto_${hash}.zip`);
637115
638059
  if (fsModule.existsSync(zipCleanupPath)) {
637116
638060
  fsModule.unlinkSync(zipCleanupPath);
637117
638061
  }
637118
638062
  } catch {
637119
638063
  }
637120
638064
  try {
637121
- const cleanupOutputDir = import_node_path9.default.join(tempDir, `heretto_${hash}`);
638065
+ const cleanupOutputDir = import_node_path10.default.join(tempDir, `heretto_${hash}`);
637122
638066
  if (fsModule.existsSync(cleanupOutputDir)) {
637123
638067
  fsModule.rmSync(cleanupOutputDir, { recursive: true, force: true });
637124
638068
  }
@@ -637197,7 +638141,7 @@ async function getResourceDependencies(restClient, ditamapId, log3, config) {
637197
638141
  pathToUuidMap[relativePath] = {
637198
638142
  uuid,
637199
638143
  fullPath: uri,
637200
- name: name || import_node_path9.default.basename(relativePath || ""),
638144
+ name: name || import_node_path10.default.basename(relativePath || ""),
637201
638145
  parentFolderId
637202
638146
  };
637203
638147
  }
@@ -637265,12 +638209,12 @@ async function detectTests2({ config }) {
637265
638209
  return specs;
637266
638210
  }
637267
638211
  function generateSpecId(filePath) {
637268
- const absolutePath = import_node_path10.default.resolve(filePath);
638212
+ const absolutePath = import_node_path11.default.resolve(filePath);
637269
638213
  const cwd = process.cwd();
637270
- const candidate = import_node_path10.default.relative(cwd, absolutePath);
637271
- const isInsideCwd = candidate.length > 0 && !candidate.startsWith("..") && !import_node_path10.default.isAbsolute(candidate);
638214
+ const candidate = import_node_path11.default.relative(cwd, absolutePath);
638215
+ const isInsideCwd = candidate.length > 0 && !candidate.startsWith("..") && !import_node_path11.default.isAbsolute(candidate);
637272
638216
  const relativePath = isInsideCwd ? candidate : absolutePath;
637273
- const normalizedPath = relativePath.split(import_node_path10.default.sep).join("/").replace(/^\.\//, "").replace(/[^a-zA-Z0-9._\-\/]/g, "_");
638217
+ const normalizedPath = relativePath.split(import_node_path11.default.sep).join("/").replace(/^\.\//, "").replace(/[^a-zA-Z0-9._\-\/]/g, "_");
637274
638218
  return normalizedPath;
637275
638219
  }
637276
638220
  async function isValidSourceFile({ config, files, source }) {
@@ -637281,7 +638225,7 @@ async function isValidSourceFile({ config, files, source }) {
637281
638225
  });
637282
638226
  if (files.indexOf(source) >= 0)
637283
638227
  return false;
637284
- if (import_node_path10.default.extname(source) === ".json" || import_node_path10.default.extname(source) === ".yaml" || import_node_path10.default.extname(source) === ".yml") {
638228
+ if (import_node_path11.default.extname(source) === ".json" || import_node_path11.default.extname(source) === ".yaml" || import_node_path11.default.extname(source) === ".yml") {
637285
638229
  const content = await readFile({ fileURLOrPath: source });
637286
638230
  if (typeof content !== "object") {
637287
638231
  log(config, "debug", `${source} isn't a valid test specification. Skipping.`);
@@ -637301,11 +638245,11 @@ async function isValidSourceFile({ config, files, source }) {
637301
638245
  if (test.before) {
637302
638246
  let beforePath = "";
637303
638247
  if (config.relativePathBase === "file") {
637304
- beforePath = import_node_path10.default.resolve(import_node_path10.default.dirname(source), test.before);
638248
+ beforePath = import_node_path11.default.resolve(import_node_path11.default.dirname(source), test.before);
637305
638249
  } else {
637306
- beforePath = import_node_path10.default.resolve(test.before);
638250
+ beforePath = import_node_path11.default.resolve(test.before);
637307
638251
  }
637308
- if (!import_node_fs11.default.existsSync(beforePath)) {
638252
+ if (!import_node_fs13.default.existsSync(beforePath)) {
637309
638253
  log(config, "debug", `${beforePath} is specified to run before a test but isn't a valid file. Skipping ${source}.`);
637310
638254
  return false;
637311
638255
  }
@@ -637313,18 +638257,18 @@ async function isValidSourceFile({ config, files, source }) {
637313
638257
  if (test.after) {
637314
638258
  let afterPath = "";
637315
638259
  if (config.relativePathBase === "file") {
637316
- afterPath = import_node_path10.default.resolve(import_node_path10.default.dirname(source), test.after);
638260
+ afterPath = import_node_path11.default.resolve(import_node_path11.default.dirname(source), test.after);
637317
638261
  } else {
637318
- afterPath = import_node_path10.default.resolve(test.after);
638262
+ afterPath = import_node_path11.default.resolve(test.after);
637319
638263
  }
637320
- if (!import_node_fs11.default.existsSync(afterPath)) {
638264
+ if (!import_node_fs13.default.existsSync(afterPath)) {
637321
638265
  log(config, "debug", `${afterPath} is specified to run after a test but isn't a valid file. Skipping ${source}.`);
637322
638266
  return false;
637323
638267
  }
637324
638268
  }
637325
638269
  }
637326
638270
  }
637327
- const extension = import_node_path10.default.extname(source).substring(1);
638271
+ const extension = import_node_path11.default.extname(source).substring(1);
637328
638272
  if (!allowedExtensions.includes(extension)) {
637329
638273
  log(config, "debug", `${source} extension isn't specified in a \`config.fileTypes\` object. Skipping.`);
637330
638274
  return false;
@@ -637332,12 +638276,12 @@ async function isValidSourceFile({ config, files, source }) {
637332
638276
  return true;
637333
638277
  }
637334
638278
  async function processDitaMap({ config, source }) {
637335
- const hash = import_node_crypto3.default.createHash("md5").update(source).digest("hex");
637336
- const tmpBase = import_node_path10.default.join(import_node_os5.default.tmpdir(), "doc-detective");
637337
- const outputDir = import_node_path10.default.join(tmpBase, `ditamap_${hash}`);
637338
- if (!import_node_fs11.default.existsSync(tmpBase)) {
638279
+ const hash = import_node_crypto4.default.createHash("md5").update(source).digest("hex");
638280
+ const tmpBase = import_node_path11.default.join(import_node_os5.default.tmpdir(), "doc-detective");
638281
+ const outputDir = import_node_path11.default.join(tmpBase, `ditamap_${hash}`);
638282
+ if (!import_node_fs13.default.existsSync(tmpBase)) {
637339
638283
  log(config, "debug", `Creating temp directory: ${tmpBase}`);
637340
- import_node_fs11.default.mkdirSync(tmpBase, { recursive: true });
638284
+ import_node_fs13.default.mkdirSync(tmpBase, { recursive: true });
637341
638285
  }
637342
638286
  const ditaVersion = await spawnCommand("dita", ["--version"]);
637343
638287
  if (ditaVersion.exitCode !== 0) {
@@ -637444,13 +638388,13 @@ async function qualifyFiles({ config }) {
637444
638388
  let isFile = false;
637445
638389
  let isDir = false;
637446
638390
  try {
637447
- isFile = import_node_fs11.default.statSync(source).isFile();
637448
- isDir = import_node_fs11.default.statSync(source).isDirectory();
638391
+ isFile = import_node_fs13.default.statSync(source).isFile();
638392
+ isDir = import_node_fs13.default.statSync(source).isDirectory();
637449
638393
  } catch {
637450
638394
  log(config, "warning", `Cannot access path: ${source}. Skipping.`);
637451
638395
  continue;
637452
638396
  }
637453
- if (isFile && import_node_path10.default.extname(source) === ".ditamap" && !ignoredDitaMaps.some((ignored) => source.includes(ignored)) && config.processDitaMaps) {
638397
+ if (isFile && import_node_path11.default.extname(source) === ".ditamap" && !ignoredDitaMaps.some((ignored) => source.includes(ignored)) && config.processDitaMaps) {
637454
638398
  const ditaOutput = await processDitaMap({ config, source });
637455
638399
  if (ditaOutput) {
637456
638400
  const currentIndex = sequence.findIndex((e) => e.source === source);
@@ -637459,7 +638403,7 @@ async function qualifyFiles({ config }) {
637459
638403
  }
637460
638404
  continue;
637461
638405
  }
637462
- const resolved = import_node_path10.default.resolve(source);
638406
+ const resolved = import_node_path11.default.resolve(source);
637463
638407
  if (isFile && await isValidSourceFile({ config, files, source: resolved })) {
637464
638408
  files.push(resolved);
637465
638409
  if (!phaseByFile.has(resolved))
@@ -637468,15 +638412,15 @@ async function qualifyFiles({ config }) {
637468
638412
  dirs = [];
637469
638413
  dirs[0] = source;
637470
638414
  for (const dir of dirs) {
637471
- const objects = import_node_fs11.default.readdirSync(dir);
638415
+ const objects = import_node_fs13.default.readdirSync(dir);
637472
638416
  for (const object of objects) {
637473
- const content = import_node_path10.default.resolve(dir + "/" + object);
638417
+ const content = import_node_path11.default.resolve(dir + "/" + object);
637474
638418
  if (content.includes("node_modules"))
637475
638419
  continue;
637476
- const isFile2 = import_node_fs11.default.statSync(content).isFile();
637477
- const isDir2 = import_node_fs11.default.statSync(content).isDirectory();
638420
+ const isFile2 = import_node_fs13.default.statSync(content).isFile();
638421
+ const isDir2 = import_node_fs13.default.statSync(content).isDirectory();
637478
638422
  if (isFile2 && await isValidSourceFile({ config, files, source: content })) {
637479
- const resolved2 = import_node_path10.default.resolve(content);
638423
+ const resolved2 = import_node_path11.default.resolve(content);
637480
638424
  files.push(resolved2);
637481
638425
  if (!phaseByFile.has(resolved2))
637482
638426
  phaseByFile.set(resolved2, phase);
@@ -637493,12 +638437,12 @@ async function parseTests({ config, files }) {
637493
638437
  let specs = [];
637494
638438
  for (const file of files) {
637495
638439
  log(config, "debug", `file: ${file}`);
637496
- const extension = import_node_path10.default.extname(file).slice(1);
638440
+ const extension = import_node_path11.default.extname(file).slice(1);
637497
638441
  let content = "";
637498
638442
  let rawContent;
637499
638443
  if (extension === "json" || extension === "yaml" || extension === "yml") {
637500
638444
  try {
637501
- rawContent = await import_node_fs11.default.promises.readFile(file, "utf8");
638445
+ rawContent = await import_node_fs13.default.promises.readFile(file, "utf8");
637502
638446
  if (extension === "json") {
637503
638447
  content = JSON.parse(rawContent);
637504
638448
  } else {
@@ -637516,7 +638460,7 @@ async function parseTests({ config, files }) {
637516
638460
  content.specId = generateSpecId(file);
637517
638461
  if (!content.contentPath)
637518
638462
  content.contentPath = file;
637519
- const specPhase = config._phaseByFile?.get(import_node_path10.default.resolve(file)) ?? "main";
638463
+ const specPhase = config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main";
637520
638464
  content._phase = specPhase;
637521
638465
  if (Array.isArray(content.tests)) {
637522
638466
  const usedTestIds = new Set(content.tests.map((test) => test?.testId).filter((id) => id));
@@ -637684,7 +638628,7 @@ async function parseTests({ config, files }) {
637684
638628
  let spec = {
637685
638629
  specId: id,
637686
638630
  contentPath: file,
637687
- _phase: config._phaseByFile?.get(import_node_path10.default.resolve(file)) ?? "main",
638631
+ _phase: config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main",
637688
638632
  tests: []
637689
638633
  };
637690
638634
  const fileType = config.fileTypes.find((fileType2) => fileType2.extensions.includes(extension));
@@ -637722,7 +638666,7 @@ async function parseTests({ config, files }) {
637722
638666
  object: spec,
637723
638667
  filePath: file
637724
638668
  });
637725
- spec._phase = config._phaseByFile?.get(import_node_path10.default.resolve(file)) ?? "main";
638669
+ spec._phase = config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main";
637726
638670
  specs.push(spec);
637727
638671
  }
637728
638672
  continue;
@@ -637749,7 +638693,7 @@ async function parseTests({ config, files }) {
637749
638693
  object: spec,
637750
638694
  filePath: file
637751
638695
  });
637752
- spec._phase = config._phaseByFile?.get(import_node_path10.default.resolve(file)) ?? "main";
638696
+ spec._phase = config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main";
637753
638697
  specs.push(spec);
637754
638698
  }
637755
638699
  }
@@ -637758,7 +638702,7 @@ async function parseTests({ config, files }) {
637758
638702
  }
637759
638703
 
637760
638704
  // dist/core/resolveTests.js
637761
- var import_node_crypto4 = __toESM(require("node:crypto"), 1);
638705
+ var import_node_crypto5 = __toESM(require("node:crypto"), 1);
637762
638706
  init_utils();
637763
638707
  init_openapi();
637764
638708
  init_browserStepKeys();
@@ -637939,7 +638883,7 @@ ${JSON.stringify(resolvedTest, null, 2)}`);
637939
638883
  return resolvedTest;
637940
638884
  }
637941
638885
  async function resolveSpec({ config, spec }) {
637942
- const specId = spec.specId || (spec.contentPath ? generateSpecId(spec.contentPath) : import_node_crypto4.default.randomUUID());
638886
+ const specId = spec.specId || (spec.contentPath ? generateSpecId(spec.contentPath) : import_node_crypto5.default.randomUUID());
637943
638887
  log(config, "debug", `RESOLVING SPEC ID ${specId}:
637944
638888
  ${JSON.stringify(spec, null, 2)}`);
637945
638889
  const resolvedSpec = {
@@ -637968,7 +638912,7 @@ async function resolveTests({ config, detectedTests }) {
637968
638912
  log(config, "debug", `RESOLVING DETECTED TEST SPECS:
637969
638913
  ${JSON.stringify(detectedTests, null, 2)}`);
637970
638914
  const resolvedTests = {
637971
- resolvedTestsId: import_node_crypto4.default.randomUUID(),
638915
+ resolvedTestsId: import_node_crypto5.default.randomUUID(),
637972
638916
  config,
637973
638917
  specs: []
637974
638918
  };
@@ -637987,7 +638931,7 @@ init_utils();
637987
638931
 
637988
638932
  // dist/core/tests.js
637989
638933
  var import_tree_kill3 = __toESM(require("tree-kill"), 1);
637990
- var import_node_fs26 = __toESM(require("node:fs"), 1);
638934
+ var import_node_fs28 = __toESM(require("node:fs"), 1);
637991
638935
  init_loader();
637992
638936
  init_browsers();
637993
638937
  init_browserStepKeys();
@@ -638700,9 +639644,9 @@ async function resolveCloseTargets(driver, ref, opts = {}) {
638700
639644
  }
638701
639645
 
638702
639646
  // dist/core/tests/appSurface.js
638703
- var import_node_fs14 = __toESM(require("node:fs"), 1);
638704
- var import_node_path12 = __toESM(require("node:path"), 1);
638705
- var import_node_child_process7 = require("node:child_process");
639647
+ var import_node_fs16 = __toESM(require("node:fs"), 1);
639648
+ var import_node_path13 = __toESM(require("node:path"), 1);
639649
+ var import_node_child_process9 = require("node:child_process");
638706
639650
  init_loader();
638707
639651
  init_appium();
638708
639652
  init_cacheDir();
@@ -639144,18 +640088,17 @@ async function closeAppWindow({ entry, selector }) {
639144
640088
  }
639145
640089
 
639146
640090
  // dist/core/tests/androidEmulator.js
639147
- var import_node_child_process6 = require("node:child_process");
640091
+ var import_node_child_process8 = require("node:child_process");
639148
640092
 
639149
640093
  // dist/runtime/androidInstaller.js
639150
- var import_node_fs13 = __toESM(require("node:fs"), 1);
640094
+ var import_node_fs15 = __toESM(require("node:fs"), 1);
639151
640095
  var import_node_os6 = __toESM(require("node:os"), 1);
639152
- var import_node_path11 = __toESM(require("node:path"), 1);
639153
- var import_node_https2 = __toESM(require("node:https"), 1);
639154
- var import_node_child_process5 = require("node:child_process");
640096
+ var import_node_path12 = __toESM(require("node:path"), 1);
640097
+ var import_node_child_process7 = require("node:child_process");
639155
640098
  init_cacheDir();
639156
640099
 
639157
640100
  // dist/runtime/androidSdk.js
639158
- var import_node_fs12 = __toESM(require("node:fs"), 1);
640101
+ var import_node_fs14 = __toESM(require("node:fs"), 1);
639159
640102
  init_cacheDir();
639160
640103
  function trimTrailingSeparators(s) {
639161
640104
  let end = s.length;
@@ -639199,7 +640142,7 @@ function usable(tools) {
639199
640142
  }
639200
640143
  function detectAndroidSdk(ctx = {}, deps = {}) {
639201
640144
  const env = deps.env ?? process.env;
639202
- const existsSync2 = deps.existsSync ?? import_node_fs12.default.existsSync;
640145
+ const existsSync2 = deps.existsSync ?? import_node_fs14.default.existsSync;
639203
640146
  const platform = deps.platform ?? process.platform;
639204
640147
  const cacheRoot = safeCacheDir(ctx);
639205
640148
  const cacheAndroidSdk = deps.cacheAndroidSdk ?? (cacheRoot ? joinFor(platform, cacheRoot, "android-sdk") : void 0);
@@ -639264,6 +640207,7 @@ function parentDir(dir, platform) {
639264
640207
  }
639265
640208
 
639266
640209
  // dist/runtime/androidInstaller.js
640210
+ init_archiveUtils();
639267
640211
  var CMDLINE_TOOLS_BUILD = "11076708";
639268
640212
  var DEFAULT_AVD_NAME = "doc-detective";
639269
640213
  var DEVICE_TYPE_PROFILES = {
@@ -639304,11 +640248,11 @@ function resolveJavaHome(extractDir, entries, platform = process.platform) {
639304
640248
  const top = entries.find((e) => /jdk|jre/i.test(e));
639305
640249
  if (!top)
639306
640250
  return null;
639307
- const base = import_node_path11.default.join(extractDir, top);
639308
- return platform === "darwin" ? import_node_path11.default.join(base, "Contents", "Home") : base;
640251
+ const base = import_node_path12.default.join(extractDir, top);
640252
+ return platform === "darwin" ? import_node_path12.default.join(base, "Contents", "Home") : base;
639309
640253
  }
639310
640254
  function javaBinPath(javaHome, platform = process.platform) {
639311
- return import_node_path11.default.join(javaHome, "bin", platform === "win32" ? "java.exe" : "java");
640255
+ return import_node_path12.default.join(javaHome, "bin", platform === "win32" ? "java.exe" : "java");
639312
640256
  }
639313
640257
  function cmdlineToolsUrl(platform) {
639314
640258
  const token = platform === "win32" ? "win" : platform === "darwin" ? "mac" : "linux";
@@ -639349,9 +640293,9 @@ function pickSystemImage(images, { osVersion, abi }) {
639349
640293
  return candidates.length > 0 ? candidates[0].pkg : null;
639350
640294
  }
639351
640295
  function listInstalledSystemImages(sdkRoot, deps = {}) {
639352
- const existsSync2 = deps.existsSync ?? import_node_fs13.default.existsSync;
639353
- const readdirSync = deps.readdirSync ?? ((p) => import_node_fs13.default.readdirSync(p));
639354
- const base = import_node_path11.default.join(sdkRoot, "system-images");
640296
+ const existsSync2 = deps.existsSync ?? import_node_fs15.default.existsSync;
640297
+ const readdirSync = deps.readdirSync ?? ((p) => import_node_fs15.default.readdirSync(p));
640298
+ const base = import_node_path12.default.join(sdkRoot, "system-images");
639355
640299
  if (!existsSync2(base))
639356
640300
  return [];
639357
640301
  const out = [];
@@ -639364,14 +640308,14 @@ function listInstalledSystemImages(sdkRoot, deps = {}) {
639364
640308
  for (const api of apis) {
639365
640309
  let tags = [];
639366
640310
  try {
639367
- tags = readdirSync(import_node_path11.default.join(base, api));
640311
+ tags = readdirSync(import_node_path12.default.join(base, api));
639368
640312
  } catch {
639369
640313
  continue;
639370
640314
  }
639371
640315
  for (const tag of tags) {
639372
640316
  let abis = [];
639373
640317
  try {
639374
- abis = readdirSync(import_node_path11.default.join(base, api, tag));
640318
+ abis = readdirSync(import_node_path12.default.join(base, api, tag));
639375
640319
  } catch {
639376
640320
  continue;
639377
640321
  }
@@ -639387,22 +640331,22 @@ function systemImageDir(sdkRoot, pkg) {
639387
640331
  const parts = pkg.split(";");
639388
640332
  if (parts.length !== 4 || parts[0] !== "system-images")
639389
640333
  return null;
639390
- const base = import_node_path11.default.join(sdkRoot, "system-images");
639391
- const dir = import_node_path11.default.join(base, parts[1], parts[2], parts[3]);
639392
- const rel = import_node_path11.default.relative(base, dir);
639393
- if (rel === "" || rel.startsWith("..") || import_node_path11.default.isAbsolute(rel))
640334
+ const base = import_node_path12.default.join(sdkRoot, "system-images");
640335
+ const dir = import_node_path12.default.join(base, parts[1], parts[2], parts[3]);
640336
+ const rel = import_node_path12.default.relative(base, dir);
640337
+ if (rel === "" || rel.startsWith("..") || import_node_path12.default.isAbsolute(rel))
639394
640338
  return null;
639395
640339
  return dir;
639396
640340
  }
639397
640341
  function isSystemImageComplete(sdkRoot, pkg, deps = {}) {
639398
- const existsSync2 = deps.existsSync ?? import_node_fs13.default.existsSync;
640342
+ const existsSync2 = deps.existsSync ?? import_node_fs15.default.existsSync;
639399
640343
  const dir = systemImageDir(sdkRoot, pkg);
639400
640344
  if (!dir)
639401
640345
  return false;
639402
- return SYSTEM_IMAGE_MARKERS.every((marker) => existsSync2(import_node_path11.default.join(dir, marker)));
640346
+ return SYSTEM_IMAGE_MARKERS.every((marker) => existsSync2(import_node_path12.default.join(dir, marker)));
639403
640347
  }
639404
640348
  function wipeSystemImage(sdkRoot, pkg, deps = {}) {
639405
- const rmSync = deps.rmSync ?? import_node_fs13.default.rmSync;
640349
+ const rmSync = deps.rmSync ?? import_node_fs15.default.rmSync;
639406
640350
  const dir = systemImageDir(sdkRoot, pkg);
639407
640351
  if (!dir)
639408
640352
  return;
@@ -639480,14 +640424,14 @@ function realSleep(ms) {
639480
640424
  timer.unref();
639481
640425
  });
639482
640426
  }
639483
- async function runSdkInstallWithRetry(run, command, args, opts = {}, deps = {}) {
640427
+ async function runSdkInstallWithRetry(run2, command, args, opts = {}, deps = {}) {
639484
640428
  const logger = deps.logger ?? (() => {
639485
640429
  });
639486
640430
  const sleep4 = deps.sleep ?? realSleep;
639487
640431
  const maxAttempts = deps.maxAttempts ?? SDK_INSTALL_MAX_ATTEMPTS;
639488
640432
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
639489
640433
  try {
639490
- return await run(command, args, opts);
640434
+ return await run2(command, args, opts);
639491
640435
  } catch (error) {
639492
640436
  const message = error?.message ?? String(error);
639493
640437
  if (attempt >= maxAttempts || !isTransientSdkError(message))
@@ -639500,7 +640444,7 @@ async function runSdkInstallWithRetry(run, command, args, opts = {}, deps = {})
639500
640444
  }
639501
640445
  function applyJavaEnv(javaHome, platform) {
639502
640446
  process.env.JAVA_HOME = javaHome;
639503
- const bin = import_node_path11.default.join(javaHome, "bin");
640447
+ const bin = import_node_path12.default.join(javaHome, "bin");
639504
640448
  const sep = platform === "win32" ? ";" : ":";
639505
640449
  if (!(process.env.PATH ?? "").split(sep).includes(bin)) {
639506
640450
  process.env.PATH = `${bin}${sep}${process.env.PATH ?? ""}`;
@@ -639535,7 +640479,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639535
640479
  const abi = hostAbi(deps.arch);
639536
640480
  const detect = deps.detect ?? detectAndroidSdk;
639537
640481
  const fsDeps = deps.fs ?? {};
639538
- const cacheSdkRoot = import_node_path11.default.join(getCacheDir(ctx), "android-sdk");
640482
+ const cacheSdkRoot = import_node_path12.default.join(getCacheDir(ctx), "android-sdk");
639539
640483
  const detected = detect(ctx, {});
639540
640484
  const installedImages = detected ? listInstalledSystemImages(detected.sdkRoot, fsDeps) : [];
639541
640485
  const needAvailable = pickSystemImage(installedImages, { osVersion, abi }) === null;
@@ -639575,7 +640519,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639575
640519
  logger("Android SDK licenses: https://developer.android.com/studio/terms", "info");
639576
640520
  return [{ kind: "android", assetId: "confirmation", action: "declined" }];
639577
640521
  }
639578
- const cacheJreRoot = import_node_path11.default.join(getCacheDir(ctx), "jre");
640522
+ const cacheJreRoot = import_node_path12.default.join(getCacheDir(ctx), "jre");
639579
640523
  const java = await ensureJava({
639580
640524
  javaPresent: deps.javaPresent ?? realJavaPresent,
639581
640525
  cacheJreRoot,
@@ -639589,7 +640533,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639589
640533
  logger(`Android setup needs a Java runtime and Doc Detective couldn't provision one automatically: ${java.reason}. Install a JRE 17+ (e.g. Temurin) and rerun.`, "error");
639590
640534
  return [{ kind: "android", assetId: "java", action: "missing" }];
639591
640535
  }
639592
- const run = deps.run ?? realRun;
640536
+ const run2 = deps.run ?? realRun;
639593
640537
  const bootstrap = deps.bootstrap ?? realBootstrap;
639594
640538
  const reports = [];
639595
640539
  const sdkRoot = plan.sdkRoot;
@@ -639607,13 +640551,13 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639607
640551
  }
639608
640552
  const sdkmanager = toolPath(sdkRoot, "sdkmanager", platform);
639609
640553
  const avdmanager = toolPath(sdkRoot, "avdmanager", platform);
639610
- await run(sdkmanager, [sdkArg, "--licenses"], { input: "y\n".repeat(50) });
640554
+ await run2(sdkmanager, [sdkArg, "--licenses"], { input: "y\n".repeat(50) });
639611
640555
  reports.push({ kind: "android", assetId: "licenses", action: "accepted" });
639612
640556
  for (const pkg of ["platform-tools", "emulator"]) {
639613
640557
  const alreadyHave = pkg === "platform-tools" && detected?.adb || pkg === "emulator" && detected?.emulator;
639614
640558
  if (alreadyHave)
639615
640559
  continue;
639616
- await runSdkInstallWithRetry(run, sdkmanager, [sdkArg, pkg], {}, retryDeps);
640560
+ await runSdkInstallWithRetry(run2, sdkmanager, [sdkArg, pkg], {}, retryDeps);
639617
640561
  reports.push({ kind: "android", assetId: pkg, action: "installed" });
639618
640562
  }
639619
640563
  let systemImage = pickSystemImage(listInstalledSystemImages(sdkRoot, fsDeps), {
@@ -639623,7 +640567,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639623
640567
  if (!systemImage) {
639624
640568
  let listOut = "";
639625
640569
  try {
639626
- listOut = await run(sdkmanager, [sdkArg, "--list"]);
640570
+ listOut = await run2(sdkmanager, [sdkArg, "--list"]);
639627
640571
  } catch {
639628
640572
  }
639629
640573
  const available = parseSdkmanagerList(listOut).filter((p) => p.startsWith("system-images;"));
@@ -639632,11 +640576,11 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639632
640576
  logger(`No ${osVersion ? `Android ${osVersion} ` : ""}${abi} google_apis system image is available to install. Rerun with --os-version set to an available level.`, "error");
639633
640577
  return [...reports, { kind: "android", assetId: "system-image", action: "blocked" }];
639634
640578
  }
639635
- await runSdkInstallWithRetry(run, sdkmanager, [sdkArg, systemImage], {}, retryDeps);
640579
+ await runSdkInstallWithRetry(run2, sdkmanager, [sdkArg, systemImage], {}, retryDeps);
639636
640580
  if (!isSystemImageComplete(sdkRoot, systemImage, fsDeps)) {
639637
640581
  logger(`Installed system image ${systemImage} looks incomplete; wiping and reinstalling\u2026`, "warn");
639638
640582
  wipeSystemImage(sdkRoot, systemImage, fsDeps);
639639
- await runSdkInstallWithRetry(run, sdkmanager, [sdkArg, systemImage], {}, retryDeps);
640583
+ await runSdkInstallWithRetry(run2, sdkmanager, [sdkArg, systemImage], {}, retryDeps);
639640
640584
  if (!isSystemImageComplete(sdkRoot, systemImage, fsDeps)) {
639641
640585
  logger(`System image ${systemImage} is still incomplete after reinstalling; aborting before AVD creation.`, "error");
639642
640586
  return [
@@ -639651,11 +640595,11 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
639651
640595
  const device = DEVICE_TYPE_PROFILES[deviceType ?? "phone"] ?? DEVICE_TYPE_PROFILES.phone;
639652
640596
  if (force) {
639653
640597
  try {
639654
- await run(avdmanager, ["delete", "avd", "-n", avdName]);
640598
+ await run2(avdmanager, ["delete", "avd", "-n", avdName]);
639655
640599
  } catch {
639656
640600
  }
639657
640601
  }
639658
- await run(avdmanager, ["create", "avd", "-n", avdName, "-k", systemImage, "--device", device, "--force"], { input: "no\n" });
640602
+ await run2(avdmanager, ["create", "avd", "-n", avdName, "-k", systemImage, "--device", device, "--force"], { input: "no\n" });
639659
640603
  reports.push({ kind: "android", assetId: `avd:${avdName}`, action: "created" });
639660
640604
  recordAndroidInstall(ctx, {
639661
640605
  sdkRoot,
@@ -639691,7 +640635,7 @@ function actionAssetId(a) {
639691
640635
  }
639692
640636
  function toolPath(sdkRoot, tool, platform) {
639693
640637
  const suffix = platform === "win32" ? ".bat" : "";
639694
- return import_node_path11.default.join(sdkRoot, "cmdline-tools", "latest", "bin", tool + suffix);
640638
+ return import_node_path12.default.join(sdkRoot, "cmdline-tools", "latest", "bin", tool + suffix);
639695
640639
  }
639696
640640
  var SAFE_SHELL_TOKEN = /^[A-Za-z0-9 ._:;=\\/@+~()-]*$/;
639697
640641
  function winShellCommand(command, args) {
@@ -639726,16 +640670,16 @@ function nowIso() {
639726
640670
  }
639727
640671
  function realJavaPresent() {
639728
640672
  try {
639729
- const res = (0, import_node_child_process5.spawnSync)("java", ["-version"], { stdio: "ignore" });
640673
+ const res = (0, import_node_child_process7.spawnSync)("java", ["-version"], { stdio: "ignore" });
639730
640674
  return res.status === 0;
639731
640675
  } catch {
639732
640676
  return false;
639733
640677
  }
639734
640678
  }
639735
640679
  function androidAvdHome() {
639736
- const home = import_node_path11.default.join(import_node_os6.default.homedir(), ".android", "avd");
640680
+ const home = import_node_path12.default.join(import_node_os6.default.homedir(), ".android", "avd");
639737
640681
  try {
639738
- import_node_fs13.default.mkdirSync(home, { recursive: true });
640682
+ import_node_fs15.default.mkdirSync(home, { recursive: true });
639739
640683
  } catch {
639740
640684
  }
639741
640685
  return home;
@@ -639746,12 +640690,12 @@ async function realRun(command, args, opts = {}) {
639746
640690
  ANDROID_AVD_HOME: androidAvdHome()
639747
640691
  };
639748
640692
  const useShell = process.platform === "win32" && /\.(bat|cmd)$/i.test(command);
639749
- const child = useShell ? (0, import_node_child_process5.spawn)(winShellCommand(command, args), {
640693
+ const child = useShell ? (0, import_node_child_process7.spawn)(winShellCommand(command, args), {
639750
640694
  cwd: opts.cwd,
639751
640695
  stdio: ["pipe", "pipe", "pipe"],
639752
640696
  shell: true,
639753
640697
  env
639754
- }) : (0, import_node_child_process5.spawn)(command, args, {
640698
+ }) : (0, import_node_child_process7.spawn)(command, args, {
639755
640699
  cwd: opts.cwd,
639756
640700
  stdio: ["pipe", "pipe", "pipe"],
639757
640701
  env
@@ -639769,20 +640713,20 @@ async function realRun(command, args, opts = {}) {
639769
640713
  });
639770
640714
  }
639771
640715
  function realDetectCachedJavaHome(cacheJreRoot) {
639772
- if (!import_node_fs13.default.existsSync(cacheJreRoot))
640716
+ if (!import_node_fs15.default.existsSync(cacheJreRoot))
639773
640717
  return null;
639774
- const entries = import_node_fs13.default.readdirSync(cacheJreRoot);
640718
+ const entries = import_node_fs15.default.readdirSync(cacheJreRoot);
639775
640719
  const home = resolveJavaHome(cacheJreRoot, entries, process.platform);
639776
- return home && import_node_fs13.default.existsSync(javaBinPath(home)) ? home : null;
640720
+ return home && import_node_fs15.default.existsSync(javaBinPath(home)) ? home : null;
639777
640721
  }
639778
640722
  async function realBootstrapJava(cacheJreRoot) {
639779
640723
  const url = jreDownloadUrl();
639780
- const tmpDir = import_node_fs13.default.mkdtempSync(import_node_path11.default.join(import_node_os6.default.tmpdir(), "dd-jre-"));
640724
+ const tmpDir = import_node_fs15.default.mkdtempSync(import_node_path12.default.join(import_node_os6.default.tmpdir(), "dd-jre-"));
639781
640725
  try {
639782
- const archive = import_node_path11.default.join(tmpDir, jreArchiveFilename());
640726
+ const archive = import_node_path12.default.join(tmpDir, jreArchiveFilename());
639783
640727
  await downloadFile(url, archive);
639784
- import_node_fs13.default.rmSync(cacheJreRoot, { recursive: true, force: true });
639785
- import_node_fs13.default.mkdirSync(cacheJreRoot, { recursive: true });
640728
+ import_node_fs15.default.rmSync(cacheJreRoot, { recursive: true, force: true });
640729
+ import_node_fs15.default.mkdirSync(cacheJreRoot, { recursive: true });
639786
640730
  await extractZip(archive, cacheJreRoot);
639787
640731
  const home = realDetectCachedJavaHome(cacheJreRoot);
639788
640732
  if (!home) {
@@ -639790,85 +640734,33 @@ async function realBootstrapJava(cacheJreRoot) {
639790
640734
  }
639791
640735
  return home;
639792
640736
  } finally {
639793
- import_node_fs13.default.rmSync(tmpDir, { recursive: true, force: true });
640737
+ import_node_fs15.default.rmSync(tmpDir, { recursive: true, force: true });
639794
640738
  }
639795
640739
  }
639796
640740
  async function realBootstrap(url, destSdkRoot) {
639797
- const tmpDir = import_node_fs13.default.mkdtempSync(import_node_path11.default.join(import_node_os6.default.tmpdir(), "dd-android-cli-"));
640741
+ const tmpDir = import_node_fs15.default.mkdtempSync(import_node_path12.default.join(import_node_os6.default.tmpdir(), "dd-android-cli-"));
639798
640742
  try {
639799
- const zipPath = import_node_path11.default.join(tmpDir, "cmdline-tools.zip");
640743
+ const zipPath = import_node_path12.default.join(tmpDir, "cmdline-tools.zip");
639800
640744
  await downloadFile(url, zipPath);
639801
- const extractDir = import_node_path11.default.join(tmpDir, "extracted");
639802
- import_node_fs13.default.mkdirSync(extractDir, { recursive: true });
640745
+ const extractDir = import_node_path12.default.join(tmpDir, "extracted");
640746
+ import_node_fs15.default.mkdirSync(extractDir, { recursive: true });
639803
640747
  await extractZip(zipPath, extractDir);
639804
- const inner = import_node_path11.default.join(extractDir, "cmdline-tools");
639805
- if (!import_node_fs13.default.existsSync(inner)) {
640748
+ const inner = import_node_path12.default.join(extractDir, "cmdline-tools");
640749
+ if (!import_node_fs15.default.existsSync(inner)) {
639806
640750
  throw new Error("unexpected command-line tools archive layout (no top-level cmdline-tools/)");
639807
640751
  }
639808
- const dest = import_node_path11.default.join(destSdkRoot, "cmdline-tools", "latest");
639809
- import_node_fs13.default.mkdirSync(import_node_path11.default.dirname(dest), { recursive: true });
639810
- import_node_fs13.default.rmSync(dest, { recursive: true, force: true });
640752
+ const dest = import_node_path12.default.join(destSdkRoot, "cmdline-tools", "latest");
640753
+ import_node_fs15.default.mkdirSync(import_node_path12.default.dirname(dest), { recursive: true });
640754
+ import_node_fs15.default.rmSync(dest, { recursive: true, force: true });
639811
640755
  try {
639812
- import_node_fs13.default.renameSync(inner, dest);
640756
+ import_node_fs15.default.renameSync(inner, dest);
639813
640757
  } catch {
639814
- import_node_fs13.default.cpSync(inner, dest, { recursive: true });
640758
+ import_node_fs15.default.cpSync(inner, dest, { recursive: true });
639815
640759
  }
639816
640760
  } finally {
639817
- import_node_fs13.default.rmSync(tmpDir, { recursive: true, force: true });
640761
+ import_node_fs15.default.rmSync(tmpDir, { recursive: true, force: true });
639818
640762
  }
639819
640763
  }
639820
- async function downloadFile(url, dest, redirects = 0) {
639821
- if (redirects > 10)
639822
- throw new Error(`too many redirects fetching ${url}`);
639823
- await new Promise((resolve, reject) => {
639824
- const req = import_node_https2.default.get(url, (res) => {
639825
- const status = res.statusCode ?? 0;
639826
- if (status >= 300 && status < 400 && res.headers.location) {
639827
- res.resume();
639828
- downloadFile(res.headers.location, dest, redirects + 1).then(resolve, reject);
639829
- return;
639830
- }
639831
- if (status !== 200) {
639832
- res.resume();
639833
- reject(new Error(`download failed (HTTP ${status}) for ${url}`));
639834
- return;
639835
- }
639836
- const file = import_node_fs13.default.createWriteStream(dest);
639837
- res.pipe(file);
639838
- file.on("finish", () => file.close(() => resolve()));
639839
- file.on("error", reject);
639840
- });
639841
- req.setTimeout(6e4, () => req.destroy(new Error(`download timed out: ${url}`)));
639842
- req.on("error", reject);
639843
- });
639844
- }
639845
- async function extractZip(zipPath, destDir) {
639846
- const attempts = process.platform === "win32" ? [
639847
- ["tar", ["-xf", zipPath, "-C", destDir]],
639848
- [
639849
- "powershell",
639850
- [
639851
- "-NoProfile",
639852
- "-NonInteractive",
639853
- "-Command",
639854
- `Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${destDir}' -Force`
639855
- ]
639856
- ]
639857
- ] : [
639858
- ["unzip", ["-q", "-o", zipPath, "-d", destDir]],
639859
- ["tar", ["-xf", zipPath, "-C", destDir]]
639860
- ];
639861
- let lastError;
639862
- for (const [cmd, args] of attempts) {
639863
- try {
639864
- await realRun(cmd, args);
639865
- return;
639866
- } catch (error) {
639867
- lastError = error;
639868
- }
639869
- }
639870
- throw new Error(`couldn't extract ${zipPath}: no working zip extractor found (${lastError?.message ?? lastError})`);
639871
- }
639872
640764
 
639873
640765
  // dist/core/tests/mobileDevice.js
639874
640766
  function normalizeDeviceDescriptor({ contextDevice, stepDevice, platform }) {
@@ -640095,7 +640987,7 @@ async function teardownDeviceRegistry(registry, kill4) {
640095
640987
  }
640096
640988
  function runTool(command, args, timeout = 3e4, env) {
640097
640989
  return new Promise((resolve) => {
640098
- (0, import_node_child_process6.execFile)(command, args, { timeout, env }, (error, stdout) => {
640990
+ (0, import_node_child_process8.execFile)(command, args, { timeout, env }, (error, stdout) => {
640099
640991
  resolve({ code: error?.code ?? 0, stdout: String(stdout ?? "") });
640100
640992
  });
640101
640993
  });
@@ -640108,8 +641000,8 @@ async function hostHasKvm() {
640108
641000
  if (process.platform !== "linux")
640109
641001
  return false;
640110
641002
  try {
640111
- const fs26 = await import("node:fs");
640112
- fs26.accessSync("/dev/kvm", fs26.constants.R_OK | fs26.constants.W_OK);
641003
+ const fs28 = await import("node:fs");
641004
+ fs28.accessSync("/dev/kvm", fs28.constants.R_OK | fs28.constants.W_OK);
640113
641005
  return true;
640114
641006
  } catch {
640115
641007
  return false;
@@ -640139,11 +641031,11 @@ async function realCreateAvd(avdmanagerPath, { name, systemImage, device }, env)
640139
641031
  "--force"
640140
641032
  ];
640141
641033
  await new Promise((resolve, reject) => {
640142
- const child = useShell ? (0, import_node_child_process6.spawn)(winShellCommand(avdmanagerPath, args), {
641034
+ const child = useShell ? (0, import_node_child_process8.spawn)(winShellCommand(avdmanagerPath, args), {
640143
641035
  stdio: ["pipe", "ignore", "pipe"],
640144
641036
  shell: true,
640145
641037
  env
640146
- }) : (0, import_node_child_process6.spawn)(avdmanagerPath, args, { stdio: ["pipe", "ignore", "pipe"], env });
641038
+ }) : (0, import_node_child_process8.spawn)(avdmanagerPath, args, { stdio: ["pipe", "ignore", "pipe"], env });
640147
641039
  let err = "";
640148
641040
  child.stderr?.on("data", (d) => err += d.toString());
640149
641041
  child.on("error", reject);
@@ -640156,7 +641048,7 @@ async function realBootEmulator(emulatorPath, adbPath, desc, port, env, timeout
640156
641048
  const udid = udidForPort(port);
640157
641049
  const bootDesc = { ...desc, headless: effectiveHeadless(desc) };
640158
641050
  const bootArgs = emulatorBootArgs(bootDesc, port);
640159
- const child = (0, import_node_child_process6.spawn)(emulatorPath, bootArgs, {
641051
+ const child = (0, import_node_child_process8.spawn)(emulatorPath, bootArgs, {
640160
641052
  detached: false,
640161
641053
  stdio: ["ignore", "pipe", "pipe"],
640162
641054
  env
@@ -640196,7 +641088,7 @@ function buildAcquireDeviceDeps(sdk, abi, log3) {
640196
641088
  const emulator = sdk.emulator ?? "emulator";
640197
641089
  const avdmanager = sdk.avdmanager ?? "avdmanager";
640198
641090
  const javaPresent = () => {
640199
- const { status } = (0, import_node_child_process6.spawnSync)("java", ["-version"], { stdio: "ignore" });
641091
+ const { status } = (0, import_node_child_process8.spawnSync)("java", ["-version"], { stdio: "ignore" });
640200
641092
  return status === 0;
640201
641093
  };
640202
641094
  const env = {
@@ -640844,7 +641736,7 @@ var APP_DRIVER_PLATFORMS = {
640844
641736
  if (extras?.udid)
640845
641737
  capabilities["appium:udid"] = extras.udid;
640846
641738
  if (descriptor.install) {
640847
- capabilities["appium:app"] = import_node_path12.default.resolve(descriptor.install);
641739
+ capabilities["appium:app"] = import_node_path13.default.resolve(descriptor.install);
640848
641740
  }
640849
641741
  if (descriptor.activity) {
640850
641742
  capabilities["appium:appActivity"] = descriptor.activity;
@@ -640887,10 +641779,10 @@ var APP_DRIVER_PLATFORMS = {
640887
641779
  if (classifyAppIdentifier(appId) === "id") {
640888
641780
  capabilities["appium:bundleId"] = appId;
640889
641781
  } else {
640890
- capabilities["appium:app"] = import_node_path12.default.resolve(appId);
641782
+ capabilities["appium:app"] = import_node_path13.default.resolve(appId);
640891
641783
  }
640892
641784
  if (descriptor.install) {
640893
- capabilities["appium:app"] = import_node_path12.default.resolve(descriptor.install);
641785
+ capabilities["appium:app"] = import_node_path13.default.resolve(descriptor.install);
640894
641786
  }
640895
641787
  if (extras?.udid)
640896
641788
  capabilities["appium:udid"] = extras.udid;
@@ -640960,18 +641852,18 @@ function resolveAppSurfaceRef(surface, appSession) {
640960
641852
  return null;
640961
641853
  }
640962
641854
  function invalidateStaleAppiumManifest(home, driverPackage) {
640963
- const cacheDir = import_node_path12.default.join(home, "node_modules", ".cache", "appium");
641855
+ const cacheDir = import_node_path13.default.join(home, "node_modules", ".cache", "appium");
640964
641856
  try {
640965
- const manifest = import_node_fs14.default.readFileSync(import_node_path12.default.join(cacheDir, "extensions.yaml"), "utf8");
641857
+ const manifest = import_node_fs16.default.readFileSync(import_node_path13.default.join(cacheDir, "extensions.yaml"), "utf8");
640966
641858
  if (!manifest.includes(driverPackage)) {
640967
- import_node_fs14.default.rmSync(cacheDir, { recursive: true, force: true });
641859
+ import_node_fs16.default.rmSync(cacheDir, { recursive: true, force: true });
640968
641860
  }
640969
641861
  } catch {
640970
641862
  }
640971
641863
  }
640972
641864
  async function probeMacAccessibility() {
640973
641865
  return await new Promise((resolve) => {
640974
- (0, import_node_child_process7.execFile)("osascript", [
641866
+ (0, import_node_child_process9.execFile)("osascript", [
640975
641867
  "-l",
640976
641868
  "JavaScript",
640977
641869
  "-e",
@@ -640986,8 +641878,8 @@ async function probeMacAccessibility() {
640986
641878
  }
640987
641879
  function probeIosToolchain(deps = {}) {
640988
641880
  const platform = deps.platform ?? process.platform;
640989
- const run = deps.run ?? ((command, args) => {
640990
- const result = (0, import_node_child_process7.spawnSync)(command, args, {
641881
+ const run2 = deps.run ?? ((command, args) => {
641882
+ const result = (0, import_node_child_process9.spawnSync)(command, args, {
640991
641883
  encoding: "utf8",
640992
641884
  windowsHide: true,
640993
641885
  // xcrun/simctl gets 2 minutes for the cold CoreSimulator warm-up;
@@ -641007,7 +641899,7 @@ function probeIosToolchain(deps = {}) {
641007
641899
  reason: "Skipping context on 'ios': iOS app surfaces require a macOS host with Xcode and Simulator tooling."
641008
641900
  };
641009
641901
  }
641010
- const xcodeSelect = run("xcode-select", ["-p"]);
641902
+ const xcodeSelect = run2("xcode-select", ["-p"]);
641011
641903
  if (xcodeSelect.status !== 0) {
641012
641904
  return {
641013
641905
  ok: false,
@@ -641015,7 +641907,7 @@ function probeIosToolchain(deps = {}) {
641015
641907
  };
641016
641908
  }
641017
641909
  const developerDir = String(xcodeSelect.stdout ?? "").trim();
641018
- const simctl = run("xcrun", ["simctl", "list", "devices", "available"]);
641910
+ const simctl = run2("xcrun", ["simctl", "list", "devices", "available"]);
641019
641911
  if (simctl.status !== 0) {
641020
641912
  const detail = String(simctl.stderr ?? "").trim().split(/\r?\n/).filter(Boolean).pop() || (simctl.status === null ? "the command timed out" : `exit ${simctl.status}`);
641021
641913
  return {
@@ -641297,7 +642189,7 @@ async function startAppSurface({ config, step, appSession, platform, serverDeps
641297
642189
  driver = deviceSession.driver;
641298
642190
  try {
641299
642191
  if (descriptor.install)
641300
- await driver.installApp(import_node_path12.default.resolve(descriptor.install));
642192
+ await driver.installApp(import_node_path13.default.resolve(descriptor.install));
641301
642193
  if (descriptor.activity) {
641302
642194
  await driver.execute("mobile: startActivity", {
641303
642195
  appPackage: appId,
@@ -641463,7 +642355,7 @@ function defaultForceKill(pid) {
641463
642355
  function queryWindowsProcessTable() {
641464
642356
  return new Promise((resolve, reject) => {
641465
642357
  const script = 'Get-CimInstance Win32_Process | ForEach-Object { "$($_.ProcessId),$($_.ParentProcessId)" }';
641466
- (0, import_node_child_process7.execFile)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { windowsHide: true, timeout: 1e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
642358
+ (0, import_node_child_process9.execFile)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { windowsHide: true, timeout: 1e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
641467
642359
  if (error)
641468
642360
  return reject(error);
641469
642361
  const rows = [];
@@ -641938,11 +642830,11 @@ init_validate();
641938
642830
  init_loader();
641939
642831
 
641940
642832
  // dist/core/tests/ffmpegRecorder.js
641941
- var import_node_child_process8 = require("node:child_process");
642833
+ var import_node_child_process10 = require("node:child_process");
641942
642834
  var import_node_os7 = __toESM(require("node:os"), 1);
641943
- var import_node_path13 = __toESM(require("node:path"), 1);
641944
- var import_node_fs15 = __toESM(require("node:fs"), 1);
641945
- var import_node_crypto5 = __toESM(require("node:crypto"), 1);
642835
+ var import_node_path14 = __toESM(require("node:path"), 1);
642836
+ var import_node_fs17 = __toESM(require("node:fs"), 1);
642837
+ var import_node_crypto6 = __toESM(require("node:crypto"), 1);
641946
642838
  init_loader();
641947
642839
  init_utils();
641948
642840
  var XVFB_SCREEN_SIZE = "1920x1080";
@@ -642013,14 +642905,14 @@ function safeContextId(contextId) {
642013
642905
  const base = sanitizeFilesystemName(raw, "ctx");
642014
642906
  if (base === raw)
642015
642907
  return base;
642016
- const hash = import_node_crypto5.default.createHash("sha1").update(raw).digest("hex").slice(0, 8);
642908
+ const hash = import_node_crypto6.default.createHash("sha1").update(raw).digest("hex").slice(0, 8);
642017
642909
  return `${base}-${hash}`;
642018
642910
  }
642019
642911
  function browserCaptureTitle(contextId) {
642020
642912
  return `RECORD_ME_${safeContextId(contextId)}`;
642021
642913
  }
642022
642914
  function browserDownloadDir(contextId) {
642023
- return import_node_path13.default.join(import_node_os7.default.tmpdir(), "doc-detective", "recordings", safeContextId(contextId));
642915
+ return import_node_path14.default.join(import_node_os7.default.tmpdir(), "doc-detective", "recordings", safeContextId(contextId));
642024
642916
  }
642025
642917
  function engineFields(record) {
642026
642918
  const engine = record && typeof record === "object" ? record.engine : void 0;
@@ -642159,11 +643051,11 @@ async function resolveCropGeometry({ driver, target }) {
642159
643051
  return null;
642160
643052
  }
642161
643053
  function ffmpegPathEnv(ffmpegPath, baseEnv = process.env) {
642162
- const dir = import_node_path13.default.dirname(ffmpegPath);
643054
+ const dir = import_node_path14.default.dirname(ffmpegPath);
642163
643055
  const pathKey = Object.keys(baseEnv).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
642164
643056
  const existing = baseEnv[pathKey];
642165
643057
  return {
642166
- [pathKey]: existing ? `${dir}${import_node_path13.default.delimiter}${existing}` : dir
643058
+ [pathKey]: existing ? `${dir}${import_node_path14.default.delimiter}${existing}` : dir
642167
643059
  };
642168
643060
  }
642169
643061
  function parseCaptureFrameSize(stderr) {
@@ -642187,7 +643079,7 @@ async function detectDisplayPointSize() {
642187
643079
  if (process.platform !== "darwin")
642188
643080
  return null;
642189
643081
  return await new Promise((resolve) => {
642190
- (0, import_node_child_process8.execFile)("osascript", [
643082
+ (0, import_node_child_process10.execFile)("osascript", [
642191
643083
  "-l",
642192
643084
  "JavaScript",
642193
643085
  "-e",
@@ -642333,7 +643225,7 @@ async function detectMacScreenIndex(ffmpegPath) {
642333
643225
  resolve(v);
642334
643226
  };
642335
643227
  try {
642336
- proc = (0, import_node_child_process8.spawn)(ffmpegPath, ["-f", "avfoundation", "-list_devices", "true", "-i", ""], { stdio: ["ignore", "ignore", "pipe"] });
643228
+ proc = (0, import_node_child_process10.spawn)(ffmpegPath, ["-f", "avfoundation", "-list_devices", "true", "-i", ""], { stdio: ["ignore", "ignore", "pipe"] });
642337
643229
  proc.stderr?.on("data", (d) => {
642338
643230
  out += d.toString();
642339
643231
  });
@@ -642362,7 +643254,7 @@ async function detectX11ScreenSize(display) {
642362
643254
  };
642363
643255
  try {
642364
643256
  const env = display ? { ...process.env, DISPLAY: display } : process.env;
642365
- proc = (0, import_node_child_process8.spawn)("xdpyinfo", [], { env, stdio: ["ignore", "pipe", "ignore"] });
643257
+ proc = (0, import_node_child_process10.spawn)("xdpyinfo", [], { env, stdio: ["ignore", "pipe", "ignore"] });
642366
643258
  proc.stdout?.on("data", (d) => {
642367
643259
  out += d.toString();
642368
643260
  });
@@ -642380,7 +643272,7 @@ async function detectX11ScreenSize(display) {
642380
643272
  async function checkSystemBinary(name) {
642381
643273
  return new Promise((resolve) => {
642382
643274
  try {
642383
- const proc = (0, import_node_child_process8.spawn)(name, ["-help"], { stdio: "ignore" });
643275
+ const proc = (0, import_node_child_process10.spawn)(name, ["-help"], { stdio: "ignore" });
642384
643276
  proc.on("error", () => resolve(false));
642385
643277
  proc.on("close", () => resolve(true));
642386
643278
  } catch {
@@ -642397,7 +643289,7 @@ async function startXvfb(display, opts = {}) {
642397
643289
  const w = opts.width ?? defW;
642398
643290
  const h = opts.height ?? defH;
642399
643291
  const startMs = Date.now();
642400
- const proc = (0, import_node_child_process8.spawn)("Xvfb", [display, "-screen", "0", `${w}x${h}x24`, "-nolisten", "tcp"], { stdio: "ignore" });
643292
+ const proc = (0, import_node_child_process10.spawn)("Xvfb", [display, "-screen", "0", `${w}x${h}x24`, "-nolisten", "tcp"], { stdio: "ignore" });
642401
643293
  let spawnErr = null;
642402
643294
  proc.on("error", (e) => {
642403
643295
  spawnErr = e;
@@ -642409,7 +643301,7 @@ async function startXvfb(display, opts = {}) {
642409
643301
  if (proc.exitCode !== null)
642410
643302
  throw new Error(`Xvfb exited early on ${display} (code ${proc.exitCode})`);
642411
643303
  try {
642412
- if (import_node_fs15.default.statSync(lock).mtimeMs >= startMs)
643304
+ if (import_node_fs17.default.statSync(lock).mtimeMs >= startMs)
642413
643305
  return proc;
642414
643306
  } catch {
642415
643307
  }
@@ -642681,11 +643573,11 @@ function hasUnresolvedMetaReference(expression, context) {
642681
643573
  }
642682
643574
  return false;
642683
643575
  }
642684
- function getMetaValue(path25, context) {
643576
+ function getMetaValue(path26, context) {
642685
643577
  if (!context) {
642686
643578
  return void 0;
642687
643579
  }
642688
- const [basePath, jsonPointer] = path25.split("#");
643580
+ const [basePath, jsonPointer] = path26.split("#");
642689
643581
  const resolvedPath = resolvePathTemplateVariables(basePath, context);
642690
643582
  let value = getNestedProperty(context, resolvedPath);
642691
643583
  if (jsonPointer && value) {
@@ -642702,9 +643594,9 @@ function getMetaValue(path25, context) {
642702
643594
  }
642703
643595
  return value;
642704
643596
  }
642705
- function resolvePathTemplateVariables(path25, context) {
643597
+ function resolvePathTemplateVariables(path26, context) {
642706
643598
  const templateRegex = /\{\{(\w+)\}\}/g;
642707
- return path25.replace(templateRegex, (match, varName) => {
643599
+ return path26.replace(templateRegex, (match, varName) => {
642708
643600
  if (context && context.id && varName === "id") {
642709
643601
  return context.id;
642710
643602
  }
@@ -642741,10 +643633,10 @@ async function resolveEmbeddedExpressions(str, context) {
642741
643633
  parts.push(str.slice(lastIdx));
642742
643634
  return parts.join("");
642743
643635
  }
642744
- function getNestedProperty(obj, path25) {
642745
- if (!obj || !path25)
643636
+ function getNestedProperty(obj, path26) {
643637
+ if (!obj || !path26)
642746
643638
  return void 0;
642747
- const parts = path25.split(".");
643639
+ const parts = path26.split(".");
642748
643640
  let current = obj;
642749
643641
  for (const part of parts) {
642750
643642
  if (current === null || current === void 0)
@@ -643456,7 +644348,7 @@ async function typeKeys({ config, step, driver, processRegistry, appSession }) {
643456
644348
  return result;
643457
644349
  }
643458
644350
  const runs = isMobile ? splitKeyRuns(step.type.keys, platform) : [{ kind: "text", text: step.type.keys.join("") }];
643459
- const textRuns = runs.filter((run) => run.kind === "text");
644351
+ const textRuns = runs.filter((run2) => run2.kind === "text");
643460
644352
  const hasAppElementCriteria = step.type.selector || step.type.elementText || step.type.elementId || step.type.elementTestId || step.type.elementAria;
643461
644353
  if (!hasAppElementCriteria && textRuns.length) {
643462
644354
  if (platform === "ios") {
@@ -643499,15 +644391,15 @@ async function typeKeys({ config, step, driver, processRegistry, appSession }) {
643499
644391
  try {
643500
644392
  if (element2)
643501
644393
  await element2.click();
643502
- for (const run of runs) {
643503
- if (run.kind === "text") {
644394
+ for (const run2 of runs) {
644395
+ if (run2.kind === "text") {
643504
644396
  if (element2) {
643505
- await element2.addValue(run.text);
644397
+ await element2.addValue(run2.text);
643506
644398
  } else {
643507
- await gestures.typeFocused(appDriver, run.text);
644399
+ await gestures.typeFocused(appDriver, run2.text);
643508
644400
  }
643509
644401
  } else {
643510
- const pressed = await gestures.pressKey(appDriver, run.token);
644402
+ const pressed = await gestures.pressKey(appDriver, run2.token);
643511
644403
  if (pressed.error) {
643512
644404
  result.status = "FAIL";
643513
644405
  result.description = pressed.error;
@@ -644351,6 +645243,8 @@ async function startBackgroundProcessSurface({ config, descriptor, processRegist
644351
645243
  const bgOptions = {};
644352
645244
  if (descriptor.workingDirectory)
644353
645245
  bgOptions.cwd = descriptor.workingDirectory;
645246
+ if (descriptor.shell)
645247
+ bgOptions.shell = descriptor.shell;
644354
645248
  const args = descriptor.args ?? [];
644355
645249
  const timeoutMs = descriptor.timeout ?? 6e4;
644356
645250
  async function teardown(bg) {
@@ -644423,8 +645317,8 @@ async function startBackgroundProcessSurface({ config, descriptor, processRegist
644423
645317
  }
644424
645318
 
644425
645319
  // dist/core/tests/runShell.js
644426
- var import_node_fs16 = __toESM(require("node:fs"), 1);
644427
- var import_node_path14 = __toESM(require("node:path"), 1);
645320
+ var import_node_fs18 = __toESM(require("node:fs"), 1);
645321
+ var import_node_path15 = __toESM(require("node:path"), 1);
644428
645322
  async function runShell({ config, step, driver, processRegistry }) {
644429
645323
  const result = {
644430
645324
  status: "PASS",
@@ -644456,6 +645350,18 @@ async function runShell({ config, step, driver, processRegistry }) {
644456
645350
  overwrite: step.runShell.overwrite || "aboveVariation",
644457
645351
  timeout: step.runShell.timeout || 6e4
644458
645352
  };
645353
+ const shellName = resolveShellName({ config, step });
645354
+ let shellExecutable;
645355
+ try {
645356
+ shellExecutable = await resolveShellExecutable(shellName, {
645357
+ cacheDir: config?.cacheDir
645358
+ });
645359
+ } catch (error) {
645360
+ result.status = "FAIL";
645361
+ result.description = error.message;
645362
+ return result;
645363
+ }
645364
+ log(config, "debug", `runShell shell: ${shellName} (${shellExecutable})`);
644459
645365
  if (step.runShell.background) {
644460
645366
  const background = step.runShell.background;
644461
645367
  const launched = await startBackgroundProcessSurface({
@@ -644465,6 +645371,7 @@ async function runShell({ config, step, driver, processRegistry }) {
644465
645371
  name: background.name,
644466
645372
  args: step.runShell.args,
644467
645373
  workingDirectory: step.runShell.workingDirectory,
645374
+ shell: shellExecutable,
644468
645375
  tty: background.tty,
644469
645376
  waitUntil: background.waitUntil,
644470
645377
  timeout: step.runShell.timeout
@@ -644479,7 +645386,7 @@ async function runShell({ config, step, driver, processRegistry }) {
644479
645386
  return result;
644480
645387
  }
644481
645388
  const timeout = step.runShell.timeout;
644482
- const options = {};
645389
+ const options = { shell: shellExecutable };
644483
645390
  if (step.runShell.workingDirectory)
644484
645391
  options.cwd = step.runShell.workingDirectory;
644485
645392
  const commandPromise = spawnCommand(step.runShell.command, step.runShell.args, options);
@@ -644524,19 +645431,19 @@ async function runShell({ config, step, driver, processRegistry }) {
644524
645431
  descriptions.push(stdioMatched ? `Found expected output (${step.runShell.stdio}) in stdio.` : isRegex ? `Couldn't find expected output (${step.runShell.stdio}) in actual output (stdout or stderr).` : `Couldn't find expected output (${step.runShell.stdio}) in stdio (stdout or stderr).`);
644525
645432
  }
644526
645433
  if (step.runShell.path) {
644527
- const dir = import_node_path14.default.dirname(step.runShell.path);
644528
- if (!import_node_fs16.default.existsSync(dir)) {
644529
- import_node_fs16.default.mkdirSync(dir, { recursive: true });
645434
+ const dir = import_node_path15.default.dirname(step.runShell.path);
645435
+ if (!import_node_fs18.default.existsSync(dir)) {
645436
+ import_node_fs18.default.mkdirSync(dir, { recursive: true });
644530
645437
  }
644531
645438
  let filePath = step.runShell.path;
644532
645439
  log(config, "debug", `Saving stdio to file: ${filePath}`);
644533
- if (!import_node_fs16.default.existsSync(filePath)) {
644534
- import_node_fs16.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645440
+ if (!import_node_fs18.default.existsSync(filePath)) {
645441
+ import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
644535
645442
  } else {
644536
645443
  if (step.runShell.overwrite == "false") {
644537
645444
  descriptions.push(`Didn't save output. File already exists.`);
644538
645445
  }
644539
- const existingFile = import_node_fs16.default.readFileSync(filePath, "utf8");
645446
+ const existingFile = import_node_fs18.default.readFileSync(filePath, "utf8");
644540
645447
  const fractionalDiff = calculateFractionalDifference(existingFile, result.outputs.stdio.stdout);
644541
645448
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
644542
645449
  result.outputs.variation = fractionalDiff;
@@ -644546,13 +645453,13 @@ async function runShell({ config, step, driver, processRegistry }) {
644546
645453
  });
644547
645454
  if (fractionalDiff > step.runShell.maxVariation) {
644548
645455
  if (step.runShell.overwrite == "aboveVariation") {
644549
- import_node_fs16.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645456
+ import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
644550
645457
  descriptions.push(`Saved output to file.`);
644551
645458
  }
644552
645459
  descriptions.push(`The difference between the existing output and the new output (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.runShell.maxVariation}).`);
644553
645460
  } else {
644554
645461
  if (step.runShell.overwrite == "true") {
644555
- import_node_fs16.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645462
+ import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
644556
645463
  descriptions.push(`Saved output to file.`);
644557
645464
  }
644558
645465
  descriptions.push(`Saved-file variation (${fractionalDiff.toFixed(2)}) is within the max accepted variation (${step.runShell.maxVariation}).`);
@@ -644899,8 +645806,8 @@ async function swipeSurface({ config, step, driver, appSession }) {
644899
645806
  // dist/core/tests/saveScreenshot.js
644900
645807
  init_validate();
644901
645808
  init_utils();
644902
- var import_node_path15 = __toESM(require("node:path"), 1);
644903
- var import_node_fs17 = __toESM(require("node:fs"), 1);
645809
+ var import_node_path16 = __toESM(require("node:path"), 1);
645810
+ var import_node_fs19 = __toESM(require("node:fs"), 1);
644904
645811
  init_loader();
644905
645812
  var _pngjs = null;
644906
645813
  var _sharp = null;
@@ -645051,7 +645958,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645051
645958
  if (typeof step.screenshot.path === "undefined") {
645052
645959
  step.screenshot.path = `${step.stepId}.png`;
645053
645960
  if (step.screenshot.directory) {
645054
- step.screenshot.path = import_node_path15.default.resolve(step.screenshot.directory, step.screenshot.path);
645961
+ step.screenshot.path = import_node_path16.default.resolve(step.screenshot.directory, step.screenshot.path);
645055
645962
  }
645056
645963
  }
645057
645964
  step.screenshot = {
@@ -645087,17 +645994,17 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645087
645994
  } catch {
645088
645995
  urlPathname = originalUrlPath;
645089
645996
  }
645090
- const rawBase = import_node_path15.default.basename(urlPathname.split("?")[0].split("#")[0].replace(/\\/g, "/"));
645997
+ const rawBase = import_node_path16.default.basename(urlPathname.split("?")[0].split("#")[0].replace(/\\/g, "/"));
645091
645998
  const safeBase = sanitizeFilesystemName(rawBase, `${step.stepId}.png`);
645092
- dir = import_node_path15.default.join(process.cwd(), "doc-detective-runs", getOrInitRunTimestamp(config));
645093
- if (!import_node_fs17.default.existsSync(dir)) {
645094
- import_node_fs17.default.mkdirSync(dir, { recursive: true });
645999
+ dir = import_node_path16.default.join(process.cwd(), "doc-detective-runs", getOrInitRunTimestamp(config));
646000
+ if (!import_node_fs19.default.existsSync(dir)) {
646001
+ import_node_fs19.default.mkdirSync(dir, { recursive: true });
645095
646002
  }
645096
646003
  const captureId = `${step.stepId || "screenshot"}_${Date.now()}`;
645097
- filePath = import_node_path15.default.join(dir, `${captureId}_${safeBase}`);
645098
- const resolvedDir = import_node_path15.default.resolve(dir);
645099
- const resolvedFile = import_node_path15.default.resolve(filePath);
645100
- if (!resolvedFile.startsWith(resolvedDir + import_node_path15.default.sep)) {
646004
+ filePath = import_node_path16.default.join(dir, `${captureId}_${safeBase}`);
646005
+ const resolvedDir = import_node_path16.default.resolve(dir);
646006
+ const resolvedFile = import_node_path16.default.resolve(filePath);
646007
+ if (!resolvedFile.startsWith(resolvedDir + import_node_path16.default.sep)) {
645101
646008
  result.status = "FAIL";
645102
646009
  result.description = `Refusing to write screenshot outside run folder: ${resolvedFile}`;
645103
646010
  return result;
@@ -645106,11 +646013,11 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645106
646013
  log(config, "debug", `Screenshot path is a URL (${redactedUrl}); overwrite is ignored, running comparison only.`);
645107
646014
  }
645108
646015
  } else {
645109
- dir = import_node_path15.default.dirname(step.screenshot.path);
645110
- if (!import_node_fs17.default.existsSync(dir)) {
645111
- import_node_fs17.default.mkdirSync(dir, { recursive: true });
646016
+ dir = import_node_path16.default.dirname(step.screenshot.path);
646017
+ if (!import_node_fs19.default.existsSync(dir)) {
646018
+ import_node_fs19.default.mkdirSync(dir, { recursive: true });
645112
646019
  }
645113
- if (import_node_fs17.default.existsSync(filePath)) {
646020
+ if (import_node_fs19.default.existsSync(filePath)) {
645114
646021
  if (step.screenshot.overwrite == "false") {
645115
646022
  result.status = "SKIPPED";
645116
646023
  result.description = `File already exists: ${filePath}`;
@@ -645118,7 +646025,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645118
646025
  return result;
645119
646026
  } else {
645120
646027
  existFilePath = filePath;
645121
- filePath = import_node_path15.default.join(dir, `${step.stepId}_${Date.now()}.png`);
646028
+ filePath = import_node_path16.default.join(dir, `${step.stepId}_${Date.now()}.png`);
645122
646029
  }
645123
646030
  }
645124
646031
  }
@@ -645220,8 +646127,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645220
646127
  } catch (error) {
645221
646128
  result.status = "FAIL";
645222
646129
  result.description = `Couldn't save screenshot. ${error}`;
645223
- if (existFilePath && filePath !== existFilePath && import_node_fs17.default.existsSync(filePath)) {
645224
- import_node_fs17.default.unlinkSync(filePath);
646130
+ if (existFilePath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646131
+ import_node_fs19.default.unlinkSync(filePath);
645225
646132
  }
645226
646133
  return result;
645227
646134
  } finally {
@@ -645276,7 +646183,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645276
646183
  rect.width = clamped.width;
645277
646184
  rect.height = clamped.height;
645278
646185
  log(config, "debug", { padded_rect: rect });
645279
- const croppedPath = import_node_path15.default.join(dir, `cropped_${step.stepId || Date.now()}.png`);
646186
+ const croppedPath = import_node_path16.default.join(dir, `cropped_${step.stepId || Date.now()}.png`);
645280
646187
  try {
645281
646188
  await sharp(filePath).extract({
645282
646189
  left: rect.x,
@@ -645284,12 +646191,12 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645284
646191
  width: rect.width,
645285
646192
  height: rect.height
645286
646193
  }).toFile(croppedPath);
645287
- import_node_fs17.default.renameSync(croppedPath, filePath);
646194
+ import_node_fs19.default.renameSync(croppedPath, filePath);
645288
646195
  } catch (error) {
645289
646196
  result.status = "FAIL";
645290
646197
  result.description = `Couldn't crop image. ${error}`;
645291
- if (existFilePath && filePath !== existFilePath && import_node_fs17.default.existsSync(filePath)) {
645292
- import_node_fs17.default.unlinkSync(filePath);
646198
+ if (existFilePath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646199
+ import_node_fs19.default.unlinkSync(filePath);
645293
646200
  }
645294
646201
  return result;
645295
646202
  }
@@ -645297,7 +646204,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645297
646204
  if (existFilePath) {
645298
646205
  if (step.screenshot.overwrite == "true" && !isUrlPath) {
645299
646206
  result.description += ` Overwrote existing file.`;
645300
- import_node_fs17.default.renameSync(filePath, existFilePath);
646207
+ import_node_fs19.default.renameSync(filePath, existFilePath);
645301
646208
  result.outputs.screenshotPath = existFilePath;
645302
646209
  result.outputs.changed = true;
645303
646210
  if (step.screenshot.sourceIntegration) {
@@ -645310,13 +646217,13 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645310
646217
  let img1;
645311
646218
  let img2;
645312
646219
  try {
645313
- img1 = PNG.sync.read(import_node_fs17.default.readFileSync(existFilePath));
645314
- img2 = PNG.sync.read(import_node_fs17.default.readFileSync(filePath));
646220
+ img1 = PNG.sync.read(import_node_fs19.default.readFileSync(existFilePath));
646221
+ img2 = PNG.sync.read(import_node_fs19.default.readFileSync(filePath));
645315
646222
  } catch (error) {
645316
646223
  result.status = "FAIL";
645317
646224
  result.description = isUrlPath ? `Couldn't decode PNG for comparison. The URL reference (${redactedUrl}) may not be a valid PNG. ${error}` : `Couldn't decode PNG for comparison. ${error}`;
645318
- if (!isUrlPath && filePath !== existFilePath && import_node_fs17.default.existsSync(filePath)) {
645319
- import_node_fs17.default.unlinkSync(filePath);
646225
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646226
+ import_node_fs19.default.unlinkSync(filePath);
645320
646227
  }
645321
646228
  return result;
645322
646229
  }
@@ -645328,8 +646235,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645328
646235
  });
645329
646236
  if (!aspectRatioMatch) {
645330
646237
  result.description = `Couldn't compare images. Images have different aspect ratios.`;
645331
- if (!isUrlPath && filePath !== existFilePath && import_node_fs17.default.existsSync(filePath)) {
645332
- import_node_fs17.default.unlinkSync(filePath);
646238
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646239
+ import_node_fs19.default.unlinkSync(filePath);
645333
646240
  }
645334
646241
  return await evaluateApplicable();
645335
646242
  }
@@ -645356,8 +646263,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645356
646263
  } catch (error) {
645357
646264
  result.status = "FAIL";
645358
646265
  result.description = `Couldn't load screenshot comparison dependency (pixelmatch). ${error?.message ?? error}`;
645359
- if (!isUrlPath && filePath !== existFilePath && import_node_fs17.default.existsSync(filePath)) {
645360
- import_node_fs17.default.unlinkSync(filePath);
646266
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646267
+ import_node_fs19.default.unlinkSync(filePath);
645361
646268
  }
645362
646269
  return result;
645363
646270
  }
@@ -645375,7 +646282,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645375
646282
  });
645376
646283
  if (fractionalDiff > step.screenshot.maxVariation) {
645377
646284
  if (step.screenshot.overwrite == "aboveVariation" && !isUrlPath) {
645378
- import_node_fs17.default.renameSync(filePath, existFilePath);
646285
+ import_node_fs19.default.renameSync(filePath, existFilePath);
645379
646286
  }
645380
646287
  result.description += ` The difference between the existing screenshot and new screenshot (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.screenshot.maxVariation}).`;
645381
646288
  if (isUrlPath) {
@@ -645400,7 +646307,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645400
646307
  result.outputs.sourceIntegration = step.screenshot.sourceIntegration;
645401
646308
  }
645402
646309
  if (step.screenshot.overwrite != "true") {
645403
- import_node_fs17.default.unlinkSync(filePath);
646310
+ import_node_fs19.default.unlinkSync(filePath);
645404
646311
  }
645405
646312
  }
645406
646313
  }
@@ -645419,10 +646326,10 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645419
646326
  // dist/core/tests/startRecording.js
645420
646327
  init_validate();
645421
646328
  init_utils();
645422
- var import_node_child_process9 = require("node:child_process");
645423
- var import_node_crypto6 = require("node:crypto");
645424
- var import_node_path16 = __toESM(require("node:path"), 1);
645425
- var import_node_fs18 = __toESM(require("node:fs"), 1);
646329
+ var import_node_child_process11 = require("node:child_process");
646330
+ var import_node_crypto7 = require("node:crypto");
646331
+ var import_node_path17 = __toESM(require("node:path"), 1);
646332
+ var import_node_fs20 = __toESM(require("node:fs"), 1);
645426
646333
  var import_node_os8 = __toESM(require("node:os"), 1);
645427
646334
  async function startRecording({ config, context, step, driver, recordingHost, appSession, deps = {} }) {
645428
646335
  let result = {
@@ -645491,7 +646398,7 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645491
646398
  if (typeof step.record.path === "undefined") {
645492
646399
  step.record.path = `${step.stepId}.mp4`;
645493
646400
  if (step.record.directory) {
645494
- step.record.path = import_node_path16.default.resolve(step.record.directory, step.record.path);
646401
+ step.record.path = import_node_path17.default.resolve(step.record.directory, step.record.path);
645495
646402
  }
645496
646403
  }
645497
646404
  step.record = {
@@ -645499,18 +646406,18 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645499
646406
  overwrite: step.record.overwrite || "false"
645500
646407
  };
645501
646408
  let filePath = step.record.path;
645502
- const baseName = import_node_path16.default.basename(filePath, import_node_path16.default.extname(filePath));
645503
- const dir = import_node_path16.default.dirname(step.record.path);
645504
- if (!import_node_fs18.default.existsSync(dir)) {
645505
- import_node_fs18.default.mkdirSync(dir, { recursive: true });
646409
+ const baseName = import_node_path17.default.basename(filePath, import_node_path17.default.extname(filePath));
646410
+ const dir = import_node_path17.default.dirname(step.record.path);
646411
+ if (!import_node_fs20.default.existsSync(dir)) {
646412
+ import_node_fs20.default.mkdirSync(dir, { recursive: true });
645506
646413
  }
645507
- if (import_node_fs18.default.existsSync(filePath) && step.record.overwrite == "false") {
646414
+ if (import_node_fs20.default.existsSync(filePath) && step.record.overwrite == "false") {
645508
646415
  result.status = "SKIPPED";
645509
646416
  result.description = `File already exists: ${filePath}`;
645510
646417
  return result;
645511
646418
  }
645512
646419
  const normalizeActiveTarget = (p) => {
645513
- const resolved = import_node_path16.default.resolve(p);
646420
+ const resolved = import_node_path17.default.resolve(p);
645514
646421
  return process.platform === "win32" || process.platform === "darwin" ? resolved.toLowerCase() : resolved;
645515
646422
  };
645516
646423
  const normalizedTarget = normalizeActiveTarget(filePath);
@@ -645598,13 +646505,13 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645598
646505
  }
645599
646506
  const captureTitle = browserCaptureTitle(context.contextId);
645600
646507
  const downloadDir = browserDownloadDir(context.contextId);
645601
- if (!import_node_fs18.default.existsSync(downloadDir)) {
645602
- import_node_fs18.default.mkdirSync(downloadDir, { recursive: true });
646508
+ if (!import_node_fs20.default.existsSync(downloadDir)) {
646509
+ import_node_fs20.default.mkdirSync(downloadDir, { recursive: true });
645603
646510
  }
645604
- const downloadPath = import_node_path16.default.join(downloadDir, `${baseName}.webm`);
645605
- if (import_node_fs18.default.existsSync(downloadPath)) {
646511
+ const downloadPath = import_node_path17.default.join(downloadDir, `${baseName}.webm`);
646512
+ if (import_node_fs20.default.existsSync(downloadPath)) {
645606
646513
  try {
645607
- import_node_fs18.default.unlinkSync(downloadPath);
646514
+ import_node_fs20.default.unlinkSync(downloadPath);
645608
646515
  } catch {
645609
646516
  }
645610
646517
  }
@@ -645744,10 +646651,10 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645744
646651
  } catch {
645745
646652
  }
645746
646653
  }
645747
- const tempDir = import_node_path16.default.join(import_node_os8.default.tmpdir(), "doc-detective", "recordings");
645748
- if (!import_node_fs18.default.existsSync(tempDir))
645749
- import_node_fs18.default.mkdirSync(tempDir, { recursive: true });
645750
- const tempPath = import_node_path16.default.join(tempDir, `${safeContextId(context.contextId)}-${baseName}-${(0, import_node_crypto6.randomUUID)().slice(0, 8)}.mkv`);
646654
+ const tempDir = import_node_path17.default.join(import_node_os8.default.tmpdir(), "doc-detective", "recordings");
646655
+ if (!import_node_fs20.default.existsSync(tempDir))
646656
+ import_node_fs20.default.mkdirSync(tempDir, { recursive: true });
646657
+ const tempPath = import_node_path17.default.join(tempDir, `${safeContextId(context.contextId)}-${baseName}-${(0, import_node_crypto7.randomUUID)().slice(0, 8)}.mkv`);
645751
646658
  let ffmpegPath;
645752
646659
  try {
645753
646660
  ffmpegPath = await (deps.getFfmpegPath ?? getFfmpegPath)({
@@ -645778,7 +646685,7 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645778
646685
  screenSize
645779
646686
  });
645780
646687
  log(config, "debug", `ffmpeg recording: platform=${process.platform} target=${plan.target}${screenIndex !== void 0 ? ` screen=${screenIndex}` : ""}${context.__display ? ` display=${context.__display}` : ""} -> ${tempPath}`);
645781
- const proc = (deps.spawn ?? import_node_child_process9.spawn)(ffmpegPath, args, {
646688
+ const proc = (deps.spawn ?? import_node_child_process11.spawn)(ffmpegPath, args, {
645782
646689
  stdio: ["pipe", "ignore", "pipe"]
645783
646690
  });
645784
646691
  let spawnError = null;
@@ -645817,10 +646724,10 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
645817
646724
  // dist/core/tests/stopRecording.js
645818
646725
  init_validate();
645819
646726
  init_utils();
645820
- var import_node_child_process10 = require("node:child_process");
645821
- var import_node_crypto7 = require("node:crypto");
645822
- var import_node_path17 = __toESM(require("node:path"), 1);
645823
- var import_node_fs19 = __toESM(require("node:fs"), 1);
646727
+ var import_node_child_process12 = require("node:child_process");
646728
+ var import_node_crypto8 = require("node:crypto");
646729
+ var import_node_path18 = __toESM(require("node:path"), 1);
646730
+ var import_node_fs21 = __toESM(require("node:fs"), 1);
645824
646731
  var import_node_os9 = __toESM(require("node:os"), 1);
645825
646732
  async function stopRecording({ config, step, driver, deps = {} }) {
645826
646733
  let result = {
@@ -646015,14 +646922,14 @@ async function stopRecording({ config, step, driver, deps = {} }) {
646015
646922
  dropHandle();
646016
646923
  return result;
646017
646924
  }
646018
- if (import_node_path17.default.extname(recording.targetPath) === ".mp4") {
646019
- import_node_fs19.default.writeFileSync(recording.targetPath, buffer);
646925
+ if (import_node_path18.default.extname(recording.targetPath) === ".mp4") {
646926
+ import_node_fs21.default.writeFileSync(recording.targetPath, buffer);
646020
646927
  } else {
646021
- const tempDir = import_node_path17.default.join(import_node_os9.default.tmpdir(), "doc-detective", "recordings");
646022
- if (!import_node_fs19.default.existsSync(tempDir))
646023
- import_node_fs19.default.mkdirSync(tempDir, { recursive: true });
646024
- const tempPath = import_node_path17.default.join(tempDir, `device-${(0, import_node_crypto7.randomUUID)().slice(0, 8)}.mp4`);
646025
- import_node_fs19.default.writeFileSync(tempPath, buffer);
646928
+ const tempDir = import_node_path18.default.join(import_node_os9.default.tmpdir(), "doc-detective", "recordings");
646929
+ if (!import_node_fs21.default.existsSync(tempDir))
646930
+ import_node_fs21.default.mkdirSync(tempDir, { recursive: true });
646931
+ const tempPath = import_node_path18.default.join(tempDir, `device-${(0, import_node_crypto8.randomUUID)().slice(0, 8)}.mp4`);
646932
+ import_node_fs21.default.writeFileSync(tempPath, buffer);
646026
646933
  await transcode({
646027
646934
  config,
646028
646935
  sourcePath: tempPath,
@@ -646050,7 +646957,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646050
646957
  const cy = `max(0\\,min(${crop.y}\\,ih-${ch}))`;
646051
646958
  filters.push(`crop=w=${cw}:h=${ch}:x=${cx}:y=${cy}`);
646052
646959
  }
646053
- if (import_node_path17.default.extname(targetPath) === ".gif") {
646960
+ if (import_node_path18.default.extname(targetPath) === ".gif") {
646054
646961
  filters.push("scale=iw:-1:flags=lanczos");
646055
646962
  }
646056
646963
  if (filters.length > 0) {
@@ -646059,7 +646966,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646059
646966
  ffmpegArgs.push(`${targetPath}`);
646060
646967
  const ffmpegPath = await getFfmpegPath({ cacheDir: config?.cacheDir });
646061
646968
  await new Promise((resolve, reject) => {
646062
- const child = (0, import_node_child_process10.spawn)(ffmpegPath, ffmpegArgs);
646969
+ const child = (0, import_node_child_process12.spawn)(ffmpegPath, ffmpegArgs);
646063
646970
  let stderr = "";
646064
646971
  child.stderr?.on("data", (d) => {
646065
646972
  stderr = (stderr + d.toString()).slice(-2e3);
@@ -646068,7 +646975,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646068
646975
  if (code === 0) {
646069
646976
  if (deleteSource && sourcePath !== targetPath) {
646070
646977
  try {
646071
- import_node_fs19.default.unlinkSync(sourcePath);
646978
+ import_node_fs21.default.unlinkSync(sourcePath);
646072
646979
  } catch {
646073
646980
  }
646074
646981
  }
@@ -646087,7 +646994,7 @@ async function waitForStableFile(filePath, maxSeconds) {
646087
646994
  for (let i = 0; i < deadline; i++) {
646088
646995
  let size = -1;
646089
646996
  try {
646090
- size = import_node_fs19.default.statSync(filePath).size;
646997
+ size = import_node_fs21.default.statSync(filePath).size;
646091
646998
  } catch {
646092
646999
  size = -1;
646093
647000
  }
@@ -646127,8 +647034,8 @@ async function loadVariables({ step }) {
646127
647034
  // dist/core/tests/saveCookie.js
646128
647035
  init_validate();
646129
647036
  init_utils();
646130
- var import_node_path18 = __toESM(require("node:path"), 1);
646131
- var import_node_fs20 = __toESM(require("node:fs"), 1);
647037
+ var import_node_path19 = __toESM(require("node:path"), 1);
647038
+ var import_node_fs22 = __toESM(require("node:fs"), 1);
646132
647039
  async function saveCookie({ config, step, driver }) {
646133
647040
  let result = {
646134
647041
  status: "PASS",
@@ -646145,7 +647052,7 @@ async function saveCookie({ config, step, driver }) {
646145
647052
  let cookieName, filePath, directory, overwrite, domain, variable;
646146
647053
  if (typeof step.saveCookie === "string") {
646147
647054
  if (step.saveCookie.endsWith(".txt")) {
646148
- cookieName = import_node_path18.default.basename(step.saveCookie, ".txt");
647055
+ cookieName = import_node_path19.default.basename(step.saveCookie, ".txt");
646149
647056
  filePath = step.saveCookie;
646150
647057
  } else {
646151
647058
  cookieName = step.saveCookie;
@@ -646194,15 +647101,15 @@ async function saveCookie({ config, step, driver }) {
646194
647101
  }
646195
647102
  if (filePath) {
646196
647103
  const outputDirectory = directory || config.output || process.cwd();
646197
- const fullPath = import_node_path18.default.resolve(outputDirectory, filePath);
646198
- if (import_node_fs20.default.existsSync(fullPath) && !(overwrite === true || overwrite === "true")) {
647104
+ const fullPath = import_node_path19.default.resolve(outputDirectory, filePath);
647105
+ if (import_node_fs22.default.existsSync(fullPath) && !(overwrite === true || overwrite === "true")) {
646199
647106
  result.status = "FAIL";
646200
647107
  result.description = `File '${fullPath}' already exists and overwrite is not enabled.`;
646201
647108
  return result;
646202
647109
  }
646203
- const dir = import_node_path18.default.dirname(fullPath);
646204
- if (!import_node_fs20.default.existsSync(dir)) {
646205
- import_node_fs20.default.mkdirSync(dir, { recursive: true });
647110
+ const dir = import_node_path19.default.dirname(fullPath);
647111
+ if (!import_node_fs22.default.existsSync(dir)) {
647112
+ import_node_fs22.default.mkdirSync(dir, { recursive: true });
646206
647113
  }
646207
647114
  if (targetCookie) {
646208
647115
  const netscapeCookie = formatCookieForNetscape(targetCookie);
@@ -646210,11 +647117,11 @@ async function saveCookie({ config, step, driver }) {
646210
647117
  # This is a cookie file saved by Doc Detective
646211
647118
  ${netscapeCookie}
646212
647119
  `;
646213
- import_node_fs20.default.writeFileSync(fullPath, content, "utf8");
647120
+ import_node_fs22.default.writeFileSync(fullPath, content, "utf8");
646214
647121
  result.description = `Saved cookie '${cookieName}' to '${fullPath}'.`;
646215
647122
  log(config, "debug", `Saved cookie '${cookieName}' to file: ${fullPath}`);
646216
647123
  } else {
646217
- import_node_fs20.default.writeFileSync(fullPath, "# No cookie data\n", "utf8");
647124
+ import_node_fs22.default.writeFileSync(fullPath, "# No cookie data\n", "utf8");
646218
647125
  result.description = `Created empty cookie file at '${fullPath}'.`;
646219
647126
  log(config, "debug", `Created empty cookie file: ${fullPath}`);
646220
647127
  }
@@ -646241,8 +647148,8 @@ function formatCookieForNetscape(cookie) {
646241
647148
  // dist/core/tests/loadCookie.js
646242
647149
  init_validate();
646243
647150
  init_utils();
646244
- var import_node_path19 = __toESM(require("node:path"), 1);
646245
- var import_node_fs21 = __toESM(require("node:fs"), 1);
647151
+ var import_node_path20 = __toESM(require("node:path"), 1);
647152
+ var import_node_fs23 = __toESM(require("node:fs"), 1);
646246
647153
  async function loadCookie({ config, step, driver }) {
646247
647154
  let result = {
646248
647155
  status: "PASS",
@@ -646259,7 +647166,7 @@ async function loadCookie({ config, step, driver }) {
646259
647166
  let cookieName, filePath, directory, domain, variable;
646260
647167
  if (typeof step.loadCookie === "string") {
646261
647168
  if (step.loadCookie.endsWith(".txt")) {
646262
- cookieName = import_node_path19.default.basename(step.loadCookie, ".txt");
647169
+ cookieName = import_node_path20.default.basename(step.loadCookie, ".txt");
646263
647170
  filePath = step.loadCookie;
646264
647171
  } else {
646265
647172
  cookieName = step.loadCookie;
@@ -646272,9 +647179,9 @@ async function loadCookie({ config, step, driver }) {
646272
647179
  domain = step.loadCookie.domain;
646273
647180
  variable = step.loadCookie.variable;
646274
647181
  if (filePath && !cookieName) {
646275
- const ext = import_node_path19.default.extname(filePath).toLowerCase();
647182
+ const ext = import_node_path20.default.extname(filePath).toLowerCase();
646276
647183
  if (ext === ".txt") {
646277
- cookieName = import_node_path19.default.basename(filePath, ext);
647184
+ cookieName = import_node_path20.default.basename(filePath, ext);
646278
647185
  }
646279
647186
  }
646280
647187
  }
@@ -646297,14 +647204,14 @@ async function loadCookie({ config, step, driver }) {
646297
647204
  }
646298
647205
  } else if (filePath) {
646299
647206
  const inputDirectory = directory || config.output || process.cwd();
646300
- const fullPath = import_node_path19.default.resolve(inputDirectory, filePath);
646301
- if (!import_node_fs21.default.existsSync(fullPath)) {
647207
+ const fullPath = import_node_path20.default.resolve(inputDirectory, filePath);
647208
+ if (!import_node_fs23.default.existsSync(fullPath)) {
646302
647209
  result.status = "FAIL";
646303
647210
  result.description = `Cookie file '${fullPath}' not found`;
646304
647211
  return result;
646305
647212
  }
646306
647213
  try {
646307
- const fileContent = import_node_fs21.default.readFileSync(fullPath, "utf8");
647214
+ const fileContent = import_node_fs23.default.readFileSync(fullPath, "utf8");
646308
647215
  const cookies = parseNetscapeCookieFile(fileContent);
646309
647216
  if (cookies.length === 0) {
646310
647217
  result.status = "FAIL";
@@ -646470,8 +647377,8 @@ function isDomainCompatible(currentDomain, cookieDomain) {
646470
647377
  // dist/core/tests/httpRequest.js
646471
647378
  init_validate();
646472
647379
  var import_axios5 = __toESM(require("axios"), 1);
646473
- var import_node_fs22 = __toESM(require("node:fs"), 1);
646474
- var import_node_path20 = __toESM(require("node:path"), 1);
647380
+ var import_node_fs24 = __toESM(require("node:fs"), 1);
647381
+ var import_node_path21 = __toESM(require("node:path"), 1);
646475
647382
  var import_ajv2 = __toESM(require("ajv"), 1);
646476
647383
  init_openapi();
646477
647384
  init_utils();
@@ -646501,9 +647408,9 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
646501
647408
  delete step.httpRequest.openApi.definition;
646502
647409
  } else if (openApiDefinitions.length > 0) {
646503
647410
  findOperation: for (const openApiConfig of openApiDefinitions) {
646504
- for (const path25 in openApiConfig.definition.paths) {
646505
- for (const method in openApiConfig.definition.paths[path25]) {
646506
- if (openApiConfig.definition.paths[path25][method].operationId === step.httpRequest.openApi.operationId) {
647411
+ for (const path26 in openApiConfig.definition.paths) {
647412
+ for (const method in openApiConfig.definition.paths[path26]) {
647413
+ if (openApiConfig.definition.paths[path26][method].operationId === step.httpRequest.openApi.operationId) {
646507
647414
  openApiDefinition = openApiConfig.definition;
646508
647415
  step.httpRequest.openApi = {
646509
647416
  ...openApiConfig,
@@ -646817,20 +647724,20 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
646817
647724
  }
646818
647725
  }
646819
647726
  if (step.httpRequest.path) {
646820
- const dir = import_node_path20.default.dirname(step.httpRequest.path);
646821
- if (!import_node_fs22.default.existsSync(dir)) {
646822
- import_node_fs22.default.mkdirSync(dir, { recursive: true });
647727
+ const dir = import_node_path21.default.dirname(step.httpRequest.path);
647728
+ if (!import_node_fs24.default.existsSync(dir)) {
647729
+ import_node_fs24.default.mkdirSync(dir, { recursive: true });
646823
647730
  }
646824
647731
  let filePath = step.httpRequest.path;
646825
647732
  log(config, "debug", `Saving output to file: ${filePath}`);
646826
- if (!import_node_fs22.default.existsSync(filePath)) {
646827
- await import_node_fs22.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647733
+ if (!import_node_fs24.default.existsSync(filePath)) {
647734
+ await import_node_fs24.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
646828
647735
  descriptions.push(`Saved output to file.`);
646829
647736
  } else {
646830
647737
  if (step.httpRequest.overwrite == "false") {
646831
647738
  descriptions.push(`Didn't save output. File already exists.`);
646832
647739
  }
646833
- const existingFile = import_node_fs22.default.readFileSync(filePath, "utf8");
647740
+ const existingFile = import_node_fs24.default.readFileSync(filePath, "utf8");
646834
647741
  const fractionalDiff = calculateFractionalDifference(existingFile, JSON.stringify(response.data, null, 2));
646835
647742
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
646836
647743
  result.outputs.variation = fractionalDiff;
@@ -646840,13 +647747,13 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
646840
647747
  });
646841
647748
  if (fractionalDiff > step.httpRequest.maxVariation) {
646842
647749
  if (step.httpRequest.overwrite == "aboveVariation") {
646843
- await import_node_fs22.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647750
+ await import_node_fs24.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
646844
647751
  descriptions.push(`Saved response to file.`);
646845
647752
  }
646846
647753
  descriptions.push(`The difference between the existing saved response and the new response (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.httpRequest.maxVariation}).`);
646847
647754
  } else {
646848
647755
  if (step.httpRequest.overwrite == "true") {
646849
- import_node_fs22.default.writeFileSync(filePath, JSON.stringify(response.data, null, 2));
647756
+ import_node_fs24.default.writeFileSync(filePath, JSON.stringify(response.data, null, 2));
646850
647757
  descriptions.push(`Saved response to file.`);
646851
647758
  }
646852
647759
  }
@@ -646859,8 +647766,8 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
646859
647766
  result.description = descriptions.join(" ").trim();
646860
647767
  return result;
646861
647768
  }
646862
- function fieldExistsAtPath(obj, path25) {
646863
- const segments = path25.match(/[^.[\]]+/g);
647769
+ function fieldExistsAtPath(obj, path26) {
647770
+ const segments = path26.match(/[^.[\]]+/g);
646864
647771
  if (!segments) {
646865
647772
  return false;
646866
647773
  }
@@ -647050,8 +647957,8 @@ async function clickElement({ config, step, driver, appSession }) {
647050
647957
  // dist/core/tests/runCode.js
647051
647958
  init_validate();
647052
647959
  init_utils();
647053
- var import_node_fs23 = __toESM(require("node:fs"), 1);
647054
- var import_node_path21 = __toESM(require("node:path"), 1);
647960
+ var import_node_fs25 = __toESM(require("node:fs"), 1);
647961
+ var import_node_path22 = __toESM(require("node:path"), 1);
647055
647962
  var import_node_os10 = __toESM(require("node:os"), 1);
647056
647963
  function createTempScript(code, language) {
647057
647964
  let extension;
@@ -647076,9 +647983,9 @@ function createTempScript(code, language) {
647076
647983
  extension = "";
647077
647984
  }
647078
647985
  const tmpDir = import_node_os10.default.tmpdir();
647079
- const tmpFile = import_node_path21.default.join(tmpDir, `doc-detective-${Date.now()}${extension}`);
647986
+ const tmpFile = import_node_path22.default.join(tmpDir, `doc-detective-${Date.now()}${extension}`);
647080
647987
  try {
647081
- import_node_fs23.default.writeFileSync(tmpFile, code);
647988
+ import_node_fs25.default.writeFileSync(tmpFile, code);
647082
647989
  } catch (error) {
647083
647990
  throw new Error(`Failed to create temporary script: ${error.message}`);
647084
647991
  }
@@ -647135,21 +648042,45 @@ async function runCode({ config, step, driver, processRegistry }) {
647135
648042
  break;
647136
648043
  }
647137
648044
  }
647138
- const command = step.runCode.command;
647139
- const commandExists = await spawnCommand(command, ["--version"]);
647140
- if (commandExists.exitCode !== 0) {
647141
- result.status = "FAIL";
647142
- result.description = `Command ${command} is unavailable. Make sure it's installed and in your PATH.`;
647143
- return result;
647144
- }
648045
+ let command = step.runCode.command;
648046
+ const wantsBash = command === "bash" || step.runCode.language?.toLowerCase() === "bash";
648047
+ const interpreterShell = wantsBash ? "bash" : import_node_os10.default.platform() === "win32" ? "cmd" : "bash";
648048
+ let commandPreverified = false;
647145
648049
  if (import_node_os10.default.platform() === "win32" && command === "bash") {
647146
- result.status = "FAIL";
647147
- result.description = `runCode currently doesn't support bash on Windows. Use a different command, a different language, or a runShell step.`;
647148
- return result;
648050
+ try {
648051
+ command = await resolveShellExecutable("bash", {
648052
+ cacheDir: config?.cacheDir
648053
+ });
648054
+ commandPreverified = true;
648055
+ } catch (error) {
648056
+ result.status = "FAIL";
648057
+ result.description = `Couldn't resolve bash on Windows: ${error.message}`;
648058
+ return result;
648059
+ }
648060
+ }
648061
+ if (import_node_os10.default.platform() === "win32" && interpreterShell === "bash") {
648062
+ command = command.replace(/\\/g, "/");
648063
+ if (/\s/.test(command) && !command.startsWith('"')) {
648064
+ command = `"${command}"`;
648065
+ }
647149
648066
  }
648067
+ if (!commandPreverified) {
648068
+ const commandExists = await spawnCommand(command, ["--version"]);
648069
+ if (commandExists.exitCode !== 0) {
648070
+ result.status = "FAIL";
648071
+ result.description = `Command ${command} is unavailable. Make sure it's installed and in your PATH.`;
648072
+ return result;
648073
+ }
648074
+ }
648075
+ let scriptArg = scriptPath;
648076
+ if (import_node_os10.default.platform() === "win32")
648077
+ scriptArg = scriptArg.replace(/\\/g, "/");
648078
+ if (/\s/.test(scriptArg))
648079
+ scriptArg = `"${scriptArg}"`;
647150
648080
  const runShellOptions = {
647151
648081
  command,
647152
- args: [scriptPath, ...step.runCode.args],
648082
+ args: [scriptArg, ...step.runCode.args],
648083
+ shell: interpreterShell,
647153
648084
  exitCodes: step.runCode.exitCodes,
647154
648085
  workingDirectory: step.runCode.workingDirectory,
647155
648086
  maxVariation: step.runCode.maxVariation,
@@ -647159,7 +648090,7 @@ async function runCode({ config, step, driver, processRegistry }) {
647159
648090
  if (typeof step.runCode.stdio !== "undefined")
647160
648091
  runShellOptions.stdio = step.runCode.stdio;
647161
648092
  if (typeof step.runCode.path !== "undefined") {
647162
- runShellOptions.path = step.runCode.directory ? import_node_path21.default.join(step.runCode.directory, step.runCode.path) : step.runCode.path;
648093
+ runShellOptions.path = step.runCode.directory ? import_node_path22.default.join(step.runCode.directory, step.runCode.path) : step.runCode.path;
647163
648094
  }
647164
648095
  if (step.runCode.background) {
647165
648096
  runShellOptions.background = step.runCode.background;
@@ -647188,7 +648119,7 @@ async function runCode({ config, step, driver, processRegistry }) {
647188
648119
  } finally {
647189
648120
  if (!deferTempCleanup) {
647190
648121
  try {
647191
- import_node_fs23.default.unlinkSync(scriptPath);
648122
+ import_node_fs25.default.unlinkSync(scriptPath);
647192
648123
  log(config, "debug", `Removed temporary script: ${scriptPath}`);
647193
648124
  } catch (error) {
647194
648125
  log(config, "warning", `Failed to remove temporary script: ${scriptPath}`);
@@ -647202,7 +648133,7 @@ async function runCode({ config, step, driver, processRegistry }) {
647202
648133
  init_validate();
647203
648134
  init_utils();
647204
648135
  var import_tree_kill2 = __toESM(require("tree-kill"), 1);
647205
- var import_node_fs24 = __toESM(require("node:fs"), 1);
648136
+ var import_node_fs26 = __toESM(require("node:fs"), 1);
647206
648137
  async function closeSurface({ config, step, driver, processRegistry, appSession }) {
647207
648138
  const result = {
647208
648139
  status: "PASS",
@@ -647351,7 +648282,7 @@ async function closeSurface({ config, step, driver, processRegistry, appSession
647351
648282
  }
647352
648283
  if (entry.tempPath) {
647353
648284
  try {
647354
- import_node_fs24.default.unlinkSync(entry.tempPath);
648285
+ import_node_fs26.default.unlinkSync(entry.tempPath);
647355
648286
  } catch {
647356
648287
  }
647357
648288
  }
@@ -647377,6 +648308,7 @@ async function closeSurface({ config, step, driver, processRegistry, appSession
647377
648308
  // dist/core/tests/startSurface.js
647378
648309
  init_validate();
647379
648310
  init_browserStepKeys();
648311
+ init_utils();
647380
648312
  function descriptorKind(d) {
647381
648313
  if (d && typeof d === "object") {
647382
648314
  if (typeof d.app === "string")
@@ -647482,20 +648414,29 @@ async function startSurfaceStep({ config, step, platform, driver, processRegistr
647482
648414
  outputs: { name: opened.name, engine }
647483
648415
  };
647484
648416
  };
647485
- const runProcessDescriptor = async (d) => startProcess({
647486
- config,
647487
- descriptor: {
647488
- command: d.process,
647489
- name: d.name,
647490
- args: d.args,
647491
- workingDirectory: d.workingDirectory,
647492
- tty: d.tty,
647493
- waitUntil: d.waitUntil,
647494
- timeout: d.timeout
647495
- },
647496
- processRegistry,
647497
- driver
647498
- });
648417
+ const runProcessDescriptor = async (d) => {
648418
+ let shellExecutable;
648419
+ try {
648420
+ shellExecutable = await resolveShellExecutable(resolveShellName({ config }), { cacheDir: config?.cacheDir });
648421
+ } catch (error) {
648422
+ return { status: "FAIL", description: error.message };
648423
+ }
648424
+ return startProcess({
648425
+ config,
648426
+ descriptor: {
648427
+ command: d.process,
648428
+ name: d.name,
648429
+ args: d.args,
648430
+ workingDirectory: d.workingDirectory,
648431
+ shell: shellExecutable,
648432
+ tty: d.tty,
648433
+ waitUntil: d.waitUntil,
648434
+ timeout: d.timeout
648435
+ },
648436
+ processRegistry,
648437
+ driver
648438
+ });
648439
+ };
647499
648440
  if (!isArrayForm) {
647500
648441
  const d = descriptors[0];
647501
648442
  const kind = descriptorKind(d);
@@ -647594,7 +648535,7 @@ async function applyViewport(driver, viewport) {
647594
648535
  }
647595
648536
 
647596
648537
  // dist/core/tests/mobileBrowser.js
647597
- var import_node_path22 = __toESM(require("node:path"), 1);
648538
+ var import_node_path23 = __toESM(require("node:path"), 1);
647598
648539
  var SUPPORTED_MOBILE_BROWSER = {
647599
648540
  android: "chrome",
647600
648541
  ios: "safari"
@@ -647669,7 +648610,7 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
647669
648610
  // --allow-insecure=uiautomator2:chromedriver_autodownload. The
647670
648611
  // download lands in the Doc Detective cache so later runs reuse it.
647671
648612
  "appium:chromedriverAutodownload": true,
647672
- "appium:chromedriverExecutableDir": import_node_path22.default.join(cacheDir, MOBILE_CHROMEDRIVER_DIR)
648613
+ "appium:chromedriverExecutableDir": import_node_path23.default.join(cacheDir, MOBILE_CHROMEDRIVER_DIR)
647673
648614
  };
647674
648615
  }
647675
648616
  const capabilities = {
@@ -647694,7 +648635,7 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
647694
648635
  init_cacheDir();
647695
648636
 
647696
648637
  // dist/core/tests/iosSimulator.js
647697
- var import_node_child_process11 = require("node:child_process");
648638
+ var import_node_child_process13 = require("node:child_process");
647698
648639
  function parseSimctlDevices(text) {
647699
648640
  let data;
647700
648641
  try {
@@ -647968,7 +648909,7 @@ async function teardownSimulatorRegistry(registry, shutdown) {
647968
648909
  }
647969
648910
  function runSimctl(args, timeout = 6e4) {
647970
648911
  return new Promise((resolve) => {
647971
- (0, import_node_child_process11.execFile)("xcrun", ["simctl", ...args], { timeout, maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
648912
+ (0, import_node_child_process13.execFile)("xcrun", ["simctl", ...args], { timeout, maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
647972
648913
  resolve({
647973
648914
  // A timeout or spawn error sets no numeric `code` (it's null) — treat
647974
648915
  // that as a failure, not success, so a hung `simctl` doesn't look like
@@ -648025,8 +648966,8 @@ function buildAcquireSimulatorDeps(log3) {
648025
648966
  // dist/core/tests/runBrowserScript.js
648026
648967
  init_validate();
648027
648968
  init_utils();
648028
- var import_node_fs25 = __toESM(require("node:fs"), 1);
648029
- var import_node_path23 = __toESM(require("node:path"), 1);
648969
+ var import_node_fs27 = __toESM(require("node:fs"), 1);
648970
+ var import_node_path24 = __toESM(require("node:path"), 1);
648030
648971
  async function runBrowserScript({ config, step, driver }) {
648031
648972
  const result = {
648032
648973
  status: "PASS",
@@ -648101,16 +649042,16 @@ async function runBrowserScript({ config, step, driver }) {
648101
649042
  }
648102
649043
  if (step.runBrowserScript.path) {
648103
649044
  try {
648104
- const dir = import_node_path23.default.dirname(step.runBrowserScript.path);
648105
- if (!import_node_fs25.default.existsSync(dir)) {
648106
- import_node_fs25.default.mkdirSync(dir, { recursive: true });
649045
+ const dir = import_node_path24.default.dirname(step.runBrowserScript.path);
649046
+ if (!import_node_fs27.default.existsSync(dir)) {
649047
+ import_node_fs27.default.mkdirSync(dir, { recursive: true });
648107
649048
  }
648108
649049
  const filePath = step.runBrowserScript.path;
648109
649050
  log(config, "debug", `Saving script result to file: ${filePath}`);
648110
- if (!import_node_fs25.default.existsSync(filePath)) {
648111
- import_node_fs25.default.writeFileSync(filePath, serialized);
649051
+ if (!import_node_fs27.default.existsSync(filePath)) {
649052
+ import_node_fs27.default.writeFileSync(filePath, serialized);
648112
649053
  } else {
648113
- const existingFile = import_node_fs25.default.readFileSync(filePath, "utf8");
649054
+ const existingFile = import_node_fs27.default.readFileSync(filePath, "utf8");
648114
649055
  const fractionalDiff = calculateFractionalDifference(existingFile, serialized);
648115
649056
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
648116
649057
  result.outputs.variation = fractionalDiff;
@@ -648120,7 +649061,7 @@ async function runBrowserScript({ config, step, driver }) {
648120
649061
  });
648121
649062
  if (fractionalDiff > step.runBrowserScript.maxVariation) {
648122
649063
  if (step.runBrowserScript.overwrite == "aboveVariation" || step.runBrowserScript.overwrite == "true") {
648123
- import_node_fs25.default.writeFileSync(filePath, serialized);
649064
+ import_node_fs27.default.writeFileSync(filePath, serialized);
648124
649065
  descriptions.push(`Saved output to file.`);
648125
649066
  } else {
648126
649067
  descriptions.push(`Didn't overwrite the existing file.`);
@@ -648128,7 +649069,7 @@ async function runBrowserScript({ config, step, driver }) {
648128
649069
  descriptions.push(`The difference between the existing output and the new output (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.runBrowserScript.maxVariation}).`);
648129
649070
  } else {
648130
649071
  if (step.runBrowserScript.overwrite == "true") {
648131
- import_node_fs25.default.writeFileSync(filePath, serialized);
649072
+ import_node_fs27.default.writeFileSync(filePath, serialized);
648132
649073
  descriptions.push(`Saved output to file.`);
648133
649074
  }
648134
649075
  }
@@ -648296,9 +649237,9 @@ async function dragAndDropElement({ config, step, driver }) {
648296
649237
  }
648297
649238
 
648298
649239
  // dist/core/tests.js
648299
- var import_node_path24 = __toESM(require("node:path"), 1);
648300
- var import_node_child_process12 = require("node:child_process");
648301
- var import_node_crypto8 = require("node:crypto");
649240
+ var import_node_path25 = __toESM(require("node:path"), 1);
649241
+ var import_node_child_process14 = require("node:child_process");
649242
+ var import_node_crypto9 = require("node:crypto");
648302
649243
  init_appium();
648303
649244
  init_config();
648304
649245
 
@@ -648450,7 +649391,7 @@ function getIntegrationConfig(config, sourceIntegration) {
648450
649391
  var import_node_http2 = __toESM(require("node:http"), 1);
648451
649392
  var import_node_https3 = __toESM(require("node:https"), 1);
648452
649393
  var import_node_url6 = require("node:url");
648453
- var __dirname5 = import_node_path24.default.dirname((0, import_node_url6.fileURLToPath)(importMetaUrl));
649394
+ var __dirname5 = import_node_path25.default.dirname((0, import_node_url6.fileURLToPath)(importMetaUrl));
648454
649395
  var KNOWN_BROWSERS = ["firefox", "chrome", "safari", "webkit"];
648455
649396
  function killTree(pid, timeoutMs = 5e3) {
648456
649397
  return new Promise((resolve) => {
@@ -649074,7 +650015,7 @@ async function runSpecs({ resolvedTests }) {
649074
650015
  const runDir = getRunOutputDir(config, {
649075
650016
  create: runArchivesArtifacts(config, specs)
649076
650017
  });
649077
- const runId = import_node_path24.default.basename(runDir);
650018
+ const runId = import_node_path25.default.basename(runDir);
649078
650019
  const report = {
649079
650020
  runId,
649080
650021
  runDir,
@@ -649300,7 +650241,7 @@ async function runSpecs({ resolvedTests }) {
649300
650241
  }
649301
650242
  if (entry?.tempPath) {
649302
650243
  try {
649303
- import_node_fs26.default.unlinkSync(entry.tempPath);
650244
+ import_node_fs28.default.unlinkSync(entry.tempPath);
649304
650245
  } catch {
649305
650246
  }
649306
650247
  }
@@ -649877,7 +650818,7 @@ function buildAutoRecordStep({ config, spec, test, context }) {
649877
650818
  return null;
649878
650819
  const runDir = getRunOutputDir(config, { create: false });
649879
650820
  const contextSegment = capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context"));
649880
- const recordPath = import_node_path24.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizeFilesystemName(String(test.testId ?? ""), "test")), "contexts", contextSegment, "recordings", `${contextSegment}.mp4`);
650821
+ const recordPath = import_node_path25.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizeFilesystemName(String(test.testId ?? ""), "test")), "contexts", contextSegment, "recordings", `${contextSegment}.mp4`);
649881
650822
  return {
649882
650823
  // Mobile-target contexts record the device screen through the app driver
649883
650824
  // (the internal device plan, resolved from the platform) — pinning ffmpeg
@@ -649897,7 +650838,7 @@ function buildAutoRecordStep({ config, spec, test, context }) {
649897
650838
  function capPathSegment(segment, max = 32) {
649898
650839
  if (segment.length <= max)
649899
650840
  return segment;
649900
- const hash = (0, import_node_crypto8.createHash)("sha1").update(segment).digest("hex").slice(0, 8);
650841
+ const hash = (0, import_node_crypto9.createHash)("sha1").update(segment).digest("hex").slice(0, 8);
649901
650842
  const tail = segment.slice(segment.length - (max - hash.length - 1));
649902
650843
  return `${hash}-${tail}`;
649903
650844
  }
@@ -649906,7 +650847,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
649906
650847
  const action = BROWSER_STEP_KEYS.find((key) => typeof step[key] !== "undefined") || "step";
649907
650848
  const sanitizedTestId = sanitizeFilesystemName(String(test.testId ?? ""), "test");
649908
650849
  const runDir = getRunOutputDir(config);
649909
- const dir = import_node_path24.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizedTestId), "contexts", capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context")), "screenshots");
650850
+ const dir = import_node_path25.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizedTestId), "contexts", capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context")), "screenshots");
649910
650851
  const stepIdString = sanitizeFilesystemName(String(step.stepId ?? ""), "step");
649911
650852
  const stepRef = capPathSegment(stepIdString.startsWith(`${sanitizedTestId}~`) ? stepIdString.slice(sanitizedTestId.length + 1) : stepIdString);
649912
650853
  const pad = Math.max(2, String(stepCount).length);
@@ -649915,7 +650856,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
649915
650856
  stepId: `${step.stepId}_auto`,
649916
650857
  description: "Automatic post-step screenshot",
649917
650858
  screenshot: {
649918
- path: import_node_path24.default.join(dir, fileName),
650859
+ path: import_node_path25.default.join(dir, fileName),
649919
650860
  overwrite: "true"
649920
650861
  }
649921
650862
  };
@@ -649928,7 +650869,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
649928
650869
  log(config, "warning", `Auto screenshot failed after step ${step.stepId}: ${captureResult.description}`);
649929
650870
  return null;
649930
650871
  }
649931
- return import_node_path24.default.relative(runDir, screenshotStep.screenshot.path).split(import_node_path24.default.sep).join("/");
650872
+ return import_node_path25.default.relative(runDir, screenshotStep.screenshot.path).split(import_node_path25.default.sep).join("/");
649932
650873
  } catch (error) {
649933
650874
  log(config, "warning", `Auto screenshot failed after step ${step.stepId}: ${error?.message ?? error}`);
649934
650875
  return null;
@@ -650353,7 +651294,7 @@ ${JSON.stringify(context, null, 2)}`);
650353
651294
  const usedStepIds = new Set(context.steps.map((s) => s.stepId).filter(Boolean));
650354
651295
  for (const step of context.steps) {
650355
651296
  if (!step.stepId) {
650356
- const baseId = sanitizeFilesystemName(`${test.testId}~s${contentHash(step)}`, `step-${(0, import_node_crypto8.randomUUID)()}`);
651297
+ const baseId = sanitizeFilesystemName(`${test.testId}~s${contentHash(step)}`, `step-${(0, import_node_crypto9.randomUUID)()}`);
650357
651298
  let stepId = baseId;
650358
651299
  let suffix = 2;
650359
651300
  while (usedStepIds.has(stepId)) {
@@ -650651,7 +651592,7 @@ async function stopAllRecordings({ config, context, driver, contextReport }) {
650651
651592
  stopRecord: true,
650652
651593
  __stopAny: true,
650653
651594
  description: "Stopping recording",
650654
- stepId: (0, import_node_crypto8.randomUUID)()
651595
+ stepId: (0, import_node_crypto9.randomUUID)()
650655
651596
  };
650656
651597
  try {
650657
651598
  const stepResult = await runStep({
@@ -650749,7 +651690,7 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
650749
651690
  if (!Array.isArray(recordingHost.state.recordings))
650750
651691
  recordingHost.state.recordings = [];
650751
651692
  const handle = actionResult.recording;
650752
- handle.id = handle.id ?? (0, import_node_crypto8.randomUUID)();
651693
+ handle.id = handle.id ?? (0, import_node_crypto9.randomUUID)();
650753
651694
  handle.name = handle.name ?? recordStepName(step.record);
650754
651695
  if (step.__autoRecord) {
650755
651696
  handle.synthetic = true;
@@ -650891,9 +651832,9 @@ async function startAppiumServer(appiumEntry, config, display, extraEnv, extraAr
650891
651832
  ...display ? { DISPLAY: display } : {},
650892
651833
  ...extraEnv ?? {}
650893
651834
  } : process.env;
650894
- const proc = (0, import_node_child_process12.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(port), ...extraArgs ?? []], {
651835
+ const proc = (0, import_node_child_process14.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(port), ...extraArgs ?? []], {
650895
651836
  windowsHide: true,
650896
- cwd: import_node_path24.default.join(__dirname5, "../.."),
651837
+ cwd: import_node_path25.default.join(__dirname5, "../.."),
650897
651838
  env
650898
651839
  });
650899
651840
  proc.on("error", (err) => {
@@ -651039,9 +651980,9 @@ async function getRunner(options = {}) {
651039
651980
  if (!appiumEntry) {
651040
651981
  throw new Error("appium is not installed. Run `doc-detective install runtime appium` to install it.");
651041
651982
  }
651042
- const appium = (0, import_node_child_process12.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(appiumPort)], {
651983
+ const appium = (0, import_node_child_process14.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(appiumPort)], {
651043
651984
  windowsHide: true,
651044
- cwd: import_node_path24.default.join(__dirname5, "../..")
651985
+ cwd: import_node_path25.default.join(__dirname5, "../..")
651045
651986
  });
651046
651987
  appium.on("error", (err) => {
651047
651988
  log(config, "warning", `Appium process error: ${err?.stack ?? err?.message ?? String(err)}`);
@@ -651216,7 +652157,9 @@ async function runTests(config, options = {}) {
651216
652157
  try {
651217
652158
  const { inferRuntimeNeeds: inferRuntimeNeeds2 } = await Promise.resolve().then(() => (init_inferRuntimeNeeds(), inferRuntimeNeeds_exports));
651218
652159
  const { ensureRuntimeInstalled: ensureRuntimeInstalled2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
651219
- const needs = inferRuntimeNeeds2(resolvedTests);
652160
+ const needs = inferRuntimeNeeds2(resolvedTests, {
652161
+ configShell: config.shell
652162
+ });
651220
652163
  const ctx = { cacheDir: config.cacheDir };
651221
652164
  const preflightLogger = (msg, level = "info") => {
651222
652165
  const mapped = level === "warn" ? "warning" : level;
@@ -651251,6 +652194,17 @@ async function runTests(config, options = {}) {
651251
652194
  log(config, "debug", `Browser pre-flight check skipped: ${browserErr?.message ?? browserErr}`);
651252
652195
  }
651253
652196
  }
652197
+ if (needs.windowsBash && process.platform === "win32") {
652198
+ try {
652199
+ const { resolveWindowsBash: resolveWindowsBash2 } = await Promise.resolve().then(() => (init_windowsBash(), windowsBash_exports));
652200
+ await resolveWindowsBash2({
652201
+ cacheDir: config.cacheDir,
652202
+ deps: { logger: preflightLogger }
652203
+ });
652204
+ } catch (bashErr) {
652205
+ log(config, "warning", `Git Bash pre-flight install hit an error: ${bashErr?.message ?? bashErr}. runShell steps using the bash shell will retry on demand.`);
652206
+ }
652207
+ }
651254
652208
  } catch (err) {
651255
652209
  log(config, "warning", `Runtime pre-flight install hit an error: ${err?.message ?? err}. Falling back to on-demand resolution.`);
651256
652210
  }