@hominis/fireforge 0.45.0 → 0.46.1

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 (662) hide show
  1. package/CHANGELOG.md +409 -446
  2. package/dist/bin/fireforge.d.ts +1 -1
  3. package/dist/bin/fireforge.js +21 -15
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/cli-usage-error.d.ts +46 -0
  6. package/dist/src/cli-usage-error.js +81 -0
  7. package/dist/src/cli.d.ts +7 -2
  8. package/dist/src/cli.js +47 -47
  9. package/dist/src/commands/bootstrap-checks.js +2 -1
  10. package/dist/src/commands/bootstrap.js +3 -4
  11. package/dist/src/commands/build.js +27 -17
  12. package/dist/src/commands/config.js +9 -9
  13. package/dist/src/commands/destructive-decision.d.ts +19 -0
  14. package/dist/src/commands/destructive-decision.js +31 -0
  15. package/dist/src/commands/discard.js +5 -5
  16. package/dist/src/commands/doctor-check-core.d.ts +4 -10
  17. package/dist/src/commands/doctor-check-core.js +0 -8
  18. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  19. package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
  20. package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
  21. package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
  22. package/dist/src/commands/doctor-furnace-jar.js +1 -1
  23. package/dist/src/commands/doctor-furnace.js +22 -22
  24. package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
  25. package/dist/src/commands/doctor-orphaned-harness.js +14 -23
  26. package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
  27. package/dist/src/commands/doctor-patch-manifest.js +7 -6
  28. package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
  29. package/dist/src/commands/doctor-source-pin.d.ts +12 -12
  30. package/dist/src/commands/doctor-source-pin.js +14 -14
  31. package/dist/src/commands/doctor-working-tree.d.ts +3 -3
  32. package/dist/src/commands/doctor-working-tree.js +3 -3
  33. package/dist/src/commands/doctor.d.ts +3 -1
  34. package/dist/src/commands/doctor.js +15 -16
  35. package/dist/src/commands/download.js +50 -37
  36. package/dist/src/commands/export-all.js +29 -12
  37. package/dist/src/commands/export-flow.d.ts +5 -5
  38. package/dist/src/commands/export-flow.js +29 -59
  39. package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
  40. package/dist/src/commands/export-placement-conflicts.js +12 -12
  41. package/dist/src/commands/export-placement-gate.d.ts +2 -2
  42. package/dist/src/commands/export-placement-gate.js +7 -13
  43. package/dist/src/commands/export-placement-policy.d.ts +1 -1
  44. package/dist/src/commands/export-placement-policy.js +4 -6
  45. package/dist/src/commands/export-shared.d.ts +51 -32
  46. package/dist/src/commands/export-shared.js +17 -32
  47. package/dist/src/commands/export.js +14 -5
  48. package/dist/src/commands/furnace/apply.js +16 -16
  49. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  50. package/dist/src/commands/furnace/authoring-config.js +19 -0
  51. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
  52. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  53. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
  54. package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
  55. package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
  56. package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
  57. package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
  58. package/dist/src/commands/furnace/chrome-doc.js +18 -18
  59. package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
  60. package/dist/src/commands/furnace/create-browser-test.js +7 -12
  61. package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
  62. package/dist/src/commands/furnace/create-dry-run.js +6 -9
  63. package/dist/src/commands/furnace/create-features.d.ts +2 -2
  64. package/dist/src/commands/furnace/create-features.js +2 -2
  65. package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
  66. package/dist/src/commands/furnace/create-mochikit.js +7 -7
  67. package/dist/src/commands/furnace/create-templates.d.ts +31 -15
  68. package/dist/src/commands/furnace/create-templates.js +20 -19
  69. package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
  70. package/dist/src/commands/furnace/create-xpcshell.js +8 -8
  71. package/dist/src/commands/furnace/create.d.ts +1 -1
  72. package/dist/src/commands/furnace/create.js +35 -29
  73. package/dist/src/commands/furnace/deploy.js +15 -6
  74. package/dist/src/commands/furnace/diff.js +7 -7
  75. package/dist/src/commands/furnace/index.js +1 -1
  76. package/dist/src/commands/furnace/init.js +17 -16
  77. package/dist/src/commands/furnace/list.js +2 -2
  78. package/dist/src/commands/furnace/override.d.ts +1 -1
  79. package/dist/src/commands/furnace/override.js +43 -34
  80. package/dist/src/commands/furnace/preview.js +17 -17
  81. package/dist/src/commands/furnace/refresh.js +15 -7
  82. package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
  83. package/dist/src/commands/furnace/remove-mutations.js +19 -19
  84. package/dist/src/commands/furnace/remove-state.d.ts +1 -1
  85. package/dist/src/commands/furnace/remove-state.js +1 -1
  86. package/dist/src/commands/furnace/remove.js +4 -8
  87. package/dist/src/commands/furnace/rename-browser-test.js +10 -15
  88. package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
  89. package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
  90. package/dist/src/commands/furnace/rename.js +36 -36
  91. package/dist/src/commands/furnace/scan.js +3 -3
  92. package/dist/src/commands/furnace/status.js +19 -16
  93. package/dist/src/commands/furnace/sync.js +6 -6
  94. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  95. package/dist/src/commands/furnace/test-file-name.js +39 -0
  96. package/dist/src/commands/furnace/validate.js +11 -12
  97. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  98. package/dist/src/commands/furnace/validation-output.js +3 -8
  99. package/dist/src/commands/import.js +22 -29
  100. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  101. package/dist/src/commands/lint-per-patch.js +27 -12
  102. package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
  103. package/dist/src/commands/lint-per-run-checkjs.js +14 -15
  104. package/dist/src/commands/lint-report.d.ts +3 -3
  105. package/dist/src/commands/lint-report.js +4 -4
  106. package/dist/src/commands/lint.d.ts +5 -4
  107. package/dist/src/commands/lint.js +36 -36
  108. package/dist/src/commands/manifest.d.ts +4 -4
  109. package/dist/src/commands/manifest.js +1 -1
  110. package/dist/src/commands/package.js +4 -6
  111. package/dist/src/commands/patch/compact.d.ts +2 -2
  112. package/dist/src/commands/patch/compact.js +19 -20
  113. package/dist/src/commands/patch/delete.d.ts +1 -1
  114. package/dist/src/commands/patch/delete.js +23 -33
  115. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  116. package/dist/src/commands/patch/entry-projection.js +24 -0
  117. package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
  118. package/dist/src/commands/patch/lint-ignore.js +33 -44
  119. package/dist/src/commands/patch/move-files-create.d.ts +2 -2
  120. package/dist/src/commands/patch/move-files-create.js +29 -15
  121. package/dist/src/commands/patch/move-files-into.d.ts +2 -2
  122. package/dist/src/commands/patch/move-files-into.js +41 -37
  123. package/dist/src/commands/patch/move-files.js +5 -14
  124. package/dist/src/commands/patch/patch-context.d.ts +1 -1
  125. package/dist/src/commands/patch/rename.d.ts +4 -4
  126. package/dist/src/commands/patch/rename.js +35 -49
  127. package/dist/src/commands/patch/reorder.js +35 -48
  128. package/dist/src/commands/patch/split-plan.d.ts +7 -8
  129. package/dist/src/commands/patch/split-plan.js +10 -13
  130. package/dist/src/commands/patch/split.d.ts +2 -2
  131. package/dist/src/commands/patch/split.js +50 -48
  132. package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
  133. package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
  134. package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
  135. package/dist/src/commands/patch/staged-dependency.js +22 -28
  136. package/dist/src/commands/patch/tier.d.ts +2 -2
  137. package/dist/src/commands/patch/tier.js +20 -30
  138. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  139. package/dist/src/commands/patch-rename-map.js +36 -0
  140. package/dist/src/commands/pending-resolution.d.ts +15 -0
  141. package/dist/src/commands/pending-resolution.js +25 -0
  142. package/dist/src/commands/re-export-adjacent.d.ts +25 -3
  143. package/dist/src/commands/re-export-adjacent.js +40 -24
  144. package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
  145. package/dist/src/commands/re-export-bulk-scan.js +23 -27
  146. package/dist/src/commands/re-export-drift.d.ts +10 -10
  147. package/dist/src/commands/re-export-drift.js +33 -33
  148. package/dist/src/commands/re-export-files.d.ts +2 -3
  149. package/dist/src/commands/re-export-files.js +52 -44
  150. package/dist/src/commands/re-export-lint.d.ts +29 -30
  151. package/dist/src/commands/re-export-lint.js +36 -29
  152. package/dist/src/commands/re-export-options.d.ts +1 -1
  153. package/dist/src/commands/re-export-options.js +1 -1
  154. package/dist/src/commands/re-export-register.d.ts +1 -1
  155. package/dist/src/commands/re-export-register.js +1 -1
  156. package/dist/src/commands/re-export-scan.d.ts +1 -1
  157. package/dist/src/commands/re-export-scan.js +12 -9
  158. package/dist/src/commands/re-export-single.d.ts +23 -4
  159. package/dist/src/commands/re-export-single.js +39 -31
  160. package/dist/src/commands/re-export.js +35 -17
  161. package/dist/src/commands/rebase/abort.js +9 -14
  162. package/dist/src/commands/rebase/continue.js +20 -19
  163. package/dist/src/commands/rebase/index.d.ts +1 -1
  164. package/dist/src/commands/rebase/index.js +5 -5
  165. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  166. package/dist/src/commands/rebase/patch-loop.js +20 -24
  167. package/dist/src/commands/register.js +5 -5
  168. package/dist/src/commands/reset.js +1 -1
  169. package/dist/src/commands/resolve.d.ts +2 -2
  170. package/dist/src/commands/resolve.js +21 -13
  171. package/dist/src/commands/run.d.ts +0 -13
  172. package/dist/src/commands/run.js +38 -51
  173. package/dist/src/commands/setup-support.d.ts +16 -4
  174. package/dist/src/commands/setup-support.js +20 -20
  175. package/dist/src/commands/setup.js +4 -10
  176. package/dist/src/commands/source.js +9 -2
  177. package/dist/src/commands/status-check.d.ts +3 -3
  178. package/dist/src/commands/status-check.js +6 -6
  179. package/dist/src/commands/status-json.d.ts +14 -13
  180. package/dist/src/commands/status-json.js +9 -8
  181. package/dist/src/commands/status-output.d.ts +3 -3
  182. package/dist/src/commands/status-output.js +5 -5
  183. package/dist/src/commands/status-ownership.d.ts +3 -3
  184. package/dist/src/commands/status-ownership.js +3 -3
  185. package/dist/src/commands/status.js +25 -26
  186. package/dist/src/commands/test-build-phase.d.ts +3 -3
  187. package/dist/src/commands/test-build-phase.js +48 -24
  188. package/dist/src/commands/test-diagnose.d.ts +1 -1
  189. package/dist/src/commands/test-diagnose.js +20 -20
  190. package/dist/src/commands/test-modes.d.ts +4 -4
  191. package/dist/src/commands/test-modes.js +4 -5
  192. package/dist/src/commands/test-register.js +5 -3
  193. package/dist/src/commands/test-run.d.ts +11 -11
  194. package/dist/src/commands/test-run.js +40 -33
  195. package/dist/src/commands/test-stale-gate.d.ts +12 -12
  196. package/dist/src/commands/test-stale-gate.js +17 -17
  197. package/dist/src/commands/test-verdict.d.ts +19 -5
  198. package/dist/src/commands/test-verdict.js +26 -11
  199. package/dist/src/commands/test.d.ts +3 -3
  200. package/dist/src/commands/test.js +73 -36
  201. package/dist/src/commands/token-coverage.js +3 -3
  202. package/dist/src/commands/token-list.d.ts +26 -0
  203. package/dist/src/commands/token-list.js +153 -0
  204. package/dist/src/commands/token.js +26 -10
  205. package/dist/src/commands/tree.js +26 -21
  206. package/dist/src/commands/typecheck.d.ts +6 -6
  207. package/dist/src/commands/typecheck.js +16 -16
  208. package/dist/src/commands/verify.d.ts +3 -3
  209. package/dist/src/commands/verify.js +10 -10
  210. package/dist/src/commands/watch.js +11 -11
  211. package/dist/src/commands/wire.js +17 -16
  212. package/dist/src/core/ast-utils.d.ts +7 -7
  213. package/dist/src/core/ast-utils.js +8 -8
  214. package/dist/src/core/branding.d.ts +5 -12
  215. package/dist/src/core/branding.js +6 -5
  216. package/dist/src/core/browser-wire.d.ts +1 -1
  217. package/dist/src/core/browser-wire.js +10 -7
  218. package/dist/src/core/build-audit-platform.d.ts +32 -3
  219. package/dist/src/core/build-audit-platform.js +153 -13
  220. package/dist/src/core/build-audit-registration.d.ts +5 -5
  221. package/dist/src/core/build-audit-registration.js +10 -9
  222. package/dist/src/core/build-audit-resolve.d.ts +5 -5
  223. package/dist/src/core/build-audit-resolve.js +6 -6
  224. package/dist/src/core/build-audit-skip.d.ts +57 -0
  225. package/dist/src/core/build-audit-skip.js +112 -0
  226. package/dist/src/core/build-audit-transforms.d.ts +2 -2
  227. package/dist/src/core/build-audit-transforms.js +3 -3
  228. package/dist/src/core/build-audit.d.ts +21 -8
  229. package/dist/src/core/build-audit.js +142 -40
  230. package/dist/src/core/build-baseline-types.d.ts +19 -18
  231. package/dist/src/core/build-baseline-types.js +1 -1
  232. package/dist/src/core/build-baseline.d.ts +48 -31
  233. package/dist/src/core/build-baseline.js +20 -43
  234. package/dist/src/core/build-jar-escalation.d.ts +8 -8
  235. package/dist/src/core/build-jar-escalation.js +18 -17
  236. package/dist/src/core/build-overwrite-guard.d.ts +4 -4
  237. package/dist/src/core/build-overwrite-guard.js +14 -14
  238. package/dist/src/core/build-prepare.d.ts +4 -12
  239. package/dist/src/core/build-prepare.js +22 -26
  240. package/dist/src/core/config-mutate.js +4 -4
  241. package/dist/src/core/config-paths.d.ts +2 -6
  242. package/dist/src/core/config-paths.js +4 -2
  243. package/dist/src/core/config-state.d.ts +0 -6
  244. package/dist/src/core/config-state.js +3 -21
  245. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  246. package/dist/src/core/config-validate-build-audit.js +80 -0
  247. package/dist/src/core/config-validate-file-size.d.ts +1 -1
  248. package/dist/src/core/config-validate-file-size.js +3 -3
  249. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  250. package/dist/src/core/config-validate-patch-policy.js +3 -3
  251. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  252. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  253. package/dist/src/core/config-validate.js +22 -12
  254. package/dist/src/core/config.d.ts +12 -12
  255. package/dist/src/core/config.js +21 -25
  256. package/dist/src/core/coverage-extend.d.ts +16 -16
  257. package/dist/src/core/coverage-extend.js +20 -20
  258. package/dist/src/core/destructive.d.ts +14 -14
  259. package/dist/src/core/destructive.js +9 -9
  260. package/dist/src/core/diff-hunks.d.ts +2 -2
  261. package/dist/src/core/diff-hunks.js +7 -7
  262. package/dist/src/core/discard-baseline.d.ts +10 -10
  263. package/dist/src/core/discard-baseline.js +22 -23
  264. package/dist/src/core/display-state.d.ts +11 -11
  265. package/dist/src/core/display-state.js +12 -12
  266. package/dist/src/core/engine-changes.d.ts +2 -2
  267. package/dist/src/core/engine-changes.js +2 -2
  268. package/dist/src/core/engine-precondition.d.ts +5 -13
  269. package/dist/src/core/engine-precondition.js +5 -10
  270. package/dist/src/core/engine-session-lock.d.ts +18 -18
  271. package/dist/src/core/engine-session-lock.js +50 -54
  272. package/dist/src/core/export-moved-code-shape.d.ts +7 -7
  273. package/dist/src/core/export-moved-code-shape.js +10 -10
  274. package/dist/src/core/file-lock-owner.d.ts +103 -0
  275. package/dist/src/core/file-lock-owner.js +259 -0
  276. package/dist/src/core/file-lock.d.ts +14 -19
  277. package/dist/src/core/file-lock.js +90 -128
  278. package/dist/src/core/firefox-cache.d.ts +13 -1
  279. package/dist/src/core/firefox-cache.js +61 -36
  280. package/dist/src/core/firefox-download.d.ts +15 -0
  281. package/dist/src/core/firefox-download.js +38 -22
  282. package/dist/src/core/firefox-extract.d.ts +8 -7
  283. package/dist/src/core/firefox-extract.js +45 -27
  284. package/dist/src/core/firefox.d.ts +34 -36
  285. package/dist/src/core/firefox.js +13 -44
  286. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  287. package/dist/src/core/furnace-apply-dry-run.js +2 -8
  288. package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
  289. package/dist/src/core/furnace-apply-ftl.js +8 -8
  290. package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
  291. package/dist/src/core/furnace-apply-helpers.js +28 -39
  292. package/dist/src/core/furnace-apply-output.js +1 -1
  293. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
  294. package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
  295. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
  296. package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
  297. package/dist/src/core/furnace-apply.d.ts +4 -4
  298. package/dist/src/core/furnace-apply.js +50 -29
  299. package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
  300. package/dist/src/core/furnace-checksum-utils.js +5 -5
  301. package/dist/src/core/furnace-config-custom.d.ts +1 -1
  302. package/dist/src/core/furnace-config-custom.js +2 -2
  303. package/dist/src/core/furnace-config-order.js +1 -1
  304. package/dist/src/core/furnace-config-tokens.d.ts +3 -3
  305. package/dist/src/core/furnace-config-tokens.js +3 -3
  306. package/dist/src/core/furnace-config-validate.js +2 -2
  307. package/dist/src/core/furnace-config.d.ts +5 -5
  308. package/dist/src/core/furnace-config.js +40 -53
  309. package/dist/src/core/furnace-constants.d.ts +6 -6
  310. package/dist/src/core/furnace-constants.js +9 -8
  311. package/dist/src/core/furnace-css-fragments.d.ts +6 -6
  312. package/dist/src/core/furnace-css-fragments.js +11 -11
  313. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  314. package/dist/src/core/furnace-dir-entry.js +21 -0
  315. package/dist/src/core/furnace-jsconfig.d.ts +7 -7
  316. package/dist/src/core/furnace-jsconfig.js +22 -20
  317. package/dist/src/core/furnace-operation.d.ts +22 -19
  318. package/dist/src/core/furnace-operation.js +38 -34
  319. package/dist/src/core/furnace-precondition.d.ts +10 -10
  320. package/dist/src/core/furnace-precondition.js +8 -8
  321. package/dist/src/core/furnace-refresh.d.ts +18 -6
  322. package/dist/src/core/furnace-refresh.js +5 -8
  323. package/dist/src/core/furnace-registration-ast.d.ts +2 -3
  324. package/dist/src/core/furnace-registration-ast.js +9 -12
  325. package/dist/src/core/furnace-registration-remove.d.ts +4 -4
  326. package/dist/src/core/furnace-registration-remove.js +6 -6
  327. package/dist/src/core/furnace-registration-validate.d.ts +2 -2
  328. package/dist/src/core/furnace-registration-validate.js +2 -2
  329. package/dist/src/core/furnace-registration.d.ts +7 -6
  330. package/dist/src/core/furnace-registration.js +29 -36
  331. package/dist/src/core/furnace-rollback.d.ts +1 -1
  332. package/dist/src/core/furnace-rollback.js +5 -5
  333. package/dist/src/core/furnace-scanner.js +3 -6
  334. package/dist/src/core/furnace-stale-export.d.ts +17 -16
  335. package/dist/src/core/furnace-stale-export.js +16 -15
  336. package/dist/src/core/furnace-staleness.d.ts +2 -2
  337. package/dist/src/core/furnace-staleness.js +2 -2
  338. package/dist/src/core/furnace-state-persist.d.ts +12 -12
  339. package/dist/src/core/furnace-state-persist.js +10 -10
  340. package/dist/src/core/furnace-step-errors.d.ts +6 -6
  341. package/dist/src/core/furnace-step-errors.js +6 -6
  342. package/dist/src/core/furnace-validate-accessibility.js +14 -14
  343. package/dist/src/core/furnace-validate-compatibility.js +9 -9
  344. package/dist/src/core/furnace-validate-registration.d.ts +2 -2
  345. package/dist/src/core/furnace-validate-registration.js +18 -20
  346. package/dist/src/core/furnace-validate-structure.d.ts +1 -1
  347. package/dist/src/core/furnace-validate-structure.js +4 -4
  348. package/dist/src/core/furnace-validate.js +9 -9
  349. package/dist/src/core/furnace-version-drift.d.ts +5 -5
  350. package/dist/src/core/furnace-version-drift.js +5 -5
  351. package/dist/src/core/git-base.d.ts +6 -4
  352. package/dist/src/core/git-base.js +29 -7
  353. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  354. package/dist/src/core/git-diff-new-file.js +119 -0
  355. package/dist/src/core/git-diff.d.ts +13 -13
  356. package/dist/src/core/git-diff.js +121 -189
  357. package/dist/src/core/git-file-ops.d.ts +6 -13
  358. package/dist/src/core/git-file-ops.js +11 -35
  359. package/dist/src/core/git-readonly-index.d.ts +12 -14
  360. package/dist/src/core/git-readonly-index.js +12 -16
  361. package/dist/src/core/git-status.d.ts +9 -2
  362. package/dist/src/core/git-status.js +23 -11
  363. package/dist/src/core/git.d.ts +3 -9
  364. package/dist/src/core/git.js +28 -57
  365. package/dist/src/core/harness-orphans.d.ts +17 -17
  366. package/dist/src/core/harness-orphans.js +28 -27
  367. package/dist/src/core/history-log.d.ts +19 -0
  368. package/dist/src/core/history-log.js +29 -0
  369. package/dist/src/core/license-headers.d.ts +19 -18
  370. package/dist/src/core/license-headers.js +29 -28
  371. package/dist/src/core/mach-build-artifacts.d.ts +21 -21
  372. package/dist/src/core/mach-build-artifacts.js +23 -23
  373. package/dist/src/core/mach-error-hints.d.ts +5 -10
  374. package/dist/src/core/mach-error-hints.js +14 -14
  375. package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
  376. package/dist/src/core/mach-known-noise-filter.js +57 -56
  377. package/dist/src/core/mach-mozconfig.d.ts +6 -6
  378. package/dist/src/core/mach-mozconfig.js +17 -16
  379. package/dist/src/core/mach-python.d.ts +3 -0
  380. package/dist/src/core/mach-python.js +13 -7
  381. package/dist/src/core/mach-resource-shim.d.ts +24 -12
  382. package/dist/src/core/mach-resource-shim.js +124 -21
  383. package/dist/src/core/mach.d.ts +59 -73
  384. package/dist/src/core/mach.js +47 -115
  385. package/dist/src/core/marionette-port.d.ts +15 -30
  386. package/dist/src/core/marionette-port.js +46 -89
  387. package/dist/src/core/marionette-preflight.d.ts +6 -6
  388. package/dist/src/core/marionette-preflight.js +32 -50
  389. package/dist/src/core/markdown-table.d.ts +9 -9
  390. package/dist/src/core/markdown-table.js +14 -14
  391. package/dist/src/core/mochitest-server-port.d.ts +8 -8
  392. package/dist/src/core/mochitest-server-port.js +17 -17
  393. package/dist/src/core/module-resolution-preflight.d.ts +8 -8
  394. package/dist/src/core/module-resolution-preflight.js +11 -11
  395. package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
  396. package/dist/src/core/moz-manifest-helpers.js +7 -7
  397. package/dist/src/core/moz-manifest-register.d.ts +1 -1
  398. package/dist/src/core/moz-manifest-register.js +2 -2
  399. package/dist/src/core/moz-manifest-rules.js +46 -42
  400. package/dist/src/core/moz-manifest-tokenizers.js +1 -1
  401. package/dist/src/core/ownership-table.d.ts +5 -5
  402. package/dist/src/core/ownership-table.js +7 -7
  403. package/dist/src/core/parser-fallback.d.ts +3 -3
  404. package/dist/src/core/parser-fallback.js +3 -3
  405. package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
  406. package/dist/src/core/patch-apply-fuzz.js +13 -13
  407. package/dist/src/core/patch-apply.d.ts +13 -14
  408. package/dist/src/core/patch-apply.js +36 -42
  409. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  410. package/dist/src/core/patch-export-coverage.js +1 -30
  411. package/dist/src/core/patch-export-update.d.ts +21 -4
  412. package/dist/src/core/patch-export-update.js +7 -6
  413. package/dist/src/core/patch-export.d.ts +20 -30
  414. package/dist/src/core/patch-export.js +55 -77
  415. package/dist/src/core/patch-files.d.ts +0 -4
  416. package/dist/src/core/patch-files.js +0 -11
  417. package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
  418. package/dist/src/core/patch-identifier-suggest.js +4 -4
  419. package/dist/src/core/patch-lint-binary.d.ts +12 -18
  420. package/dist/src/core/patch-lint-cache.d.ts +18 -2
  421. package/dist/src/core/patch-lint-cache.js +16 -19
  422. package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
  423. package/dist/src/core/patch-lint-checkjs.js +78 -64
  424. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
  425. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
  426. package/dist/src/core/patch-lint-creators.d.ts +5 -9
  427. package/dist/src/core/patch-lint-creators.js +3 -3
  428. package/dist/src/core/patch-lint-cross.d.ts +27 -19
  429. package/dist/src/core/patch-lint-cross.js +67 -110
  430. package/dist/src/core/patch-lint-css.d.ts +1 -1
  431. package/dist/src/core/patch-lint-css.js +15 -11
  432. package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
  433. package/dist/src/core/patch-lint-diff-tag.js +5 -5
  434. package/dist/src/core/patch-lint-diff.d.ts +4 -4
  435. package/dist/src/core/patch-lint-diff.js +4 -4
  436. package/dist/src/core/patch-lint-file-size.d.ts +3 -3
  437. package/dist/src/core/patch-lint-file-size.js +6 -6
  438. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  439. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  440. package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
  441. package/dist/src/core/patch-lint-jsdoc.js +46 -46
  442. package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
  443. package/dist/src/core/patch-lint-module-registration.js +1 -1
  444. package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
  445. package/dist/src/core/patch-lint-mozbuild.js +10 -10
  446. package/dist/src/core/patch-lint-observer.d.ts +3 -3
  447. package/dist/src/core/patch-lint-observer.js +7 -7
  448. package/dist/src/core/patch-lint-ownership.d.ts +6 -6
  449. package/dist/src/core/patch-lint-ownership.js +6 -6
  450. package/dist/src/core/patch-lint-prettier.d.ts +6 -6
  451. package/dist/src/core/patch-lint-prettier.js +7 -7
  452. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  453. package/dist/src/core/patch-lint-queue-types.js +12 -0
  454. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  455. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  456. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
  457. package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
  458. package/dist/src/core/patch-lint.d.ts +41 -35
  459. package/dist/src/core/patch-lint.js +52 -49
  460. package/dist/src/core/patch-lock.d.ts +1 -1
  461. package/dist/src/core/patch-lock.js +11 -11
  462. package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
  463. package/dist/src/core/patch-manifest-consistency.js +16 -17
  464. package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
  465. package/dist/src/core/patch-manifest-files-affected.js +3 -3
  466. package/dist/src/core/patch-manifest-io.d.ts +14 -14
  467. package/dist/src/core/patch-manifest-io.js +35 -34
  468. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  469. package/dist/src/core/patch-manifest-query.js +4 -4
  470. package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
  471. package/dist/src/core/patch-manifest-resolve.js +7 -7
  472. package/dist/src/core/patch-manifest-validate.js +3 -3
  473. package/dist/src/core/patch-manifest.d.ts +2 -2
  474. package/dist/src/core/patch-manifest.js +2 -2
  475. package/dist/src/core/patch-parse.d.ts +32 -21
  476. package/dist/src/core/patch-parse.js +40 -15
  477. package/dist/src/core/patch-policy.js +15 -27
  478. package/dist/src/core/patch-registration-refs.d.ts +4 -4
  479. package/dist/src/core/patch-registration-refs.js +7 -7
  480. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  481. package/dist/src/core/patch-source-metadata.js +0 -4
  482. package/dist/src/core/patch-transform.d.ts +8 -16
  483. package/dist/src/core/patch-transform.js +13 -23
  484. package/dist/src/core/process-cpu-time.d.ts +1 -1
  485. package/dist/src/core/process-cpu-time.js +6 -6
  486. package/dist/src/core/rebase-session.d.ts +9 -15
  487. package/dist/src/core/rebase-session.js +13 -25
  488. package/dist/src/core/register-browser-content.js +3 -2
  489. package/dist/src/core/register-browser-test.js +2 -1
  490. package/dist/src/core/register-module.js +2 -1
  491. package/dist/src/core/register-result.d.ts +1 -1
  492. package/dist/src/core/register-result.js +1 -1
  493. package/dist/src/core/register-scaffold.d.ts +2 -2
  494. package/dist/src/core/register-scaffold.js +8 -7
  495. package/dist/src/core/register-shared-css.d.ts +3 -3
  496. package/dist/src/core/register-shared-css.js +6 -5
  497. package/dist/src/core/register-xpcshell-test.d.ts +2 -2
  498. package/dist/src/core/register-xpcshell-test.js +2 -2
  499. package/dist/src/core/run-log-redact.d.ts +38 -0
  500. package/dist/src/core/run-log-redact.js +69 -0
  501. package/dist/src/core/run-log.d.ts +21 -10
  502. package/dist/src/core/run-log.js +76 -27
  503. package/dist/src/core/shared-ftl.d.ts +2 -2
  504. package/dist/src/core/shared-ftl.js +6 -6
  505. package/dist/src/core/signal-critical.d.ts +2 -2
  506. package/dist/src/core/signal-critical.js +4 -6
  507. package/dist/src/core/smoke-patterns.d.ts +5 -6
  508. package/dist/src/core/smoke-patterns.js +15 -20
  509. package/dist/src/core/state-file.d.ts +15 -4
  510. package/dist/src/core/state-file.js +14 -1
  511. package/dist/src/core/status-binary.d.ts +8 -8
  512. package/dist/src/core/status-binary.js +12 -12
  513. package/dist/src/core/status-classify.d.ts +17 -17
  514. package/dist/src/core/status-classify.js +13 -12
  515. package/dist/src/core/test-changed-prefs.d.ts +12 -12
  516. package/dist/src/core/test-changed-prefs.js +40 -25
  517. package/dist/src/core/test-harness-crash.d.ts +39 -39
  518. package/dist/src/core/test-harness-crash.js +69 -69
  519. package/dist/src/core/test-harness-output.d.ts +7 -7
  520. package/dist/src/core/test-harness-output.js +7 -7
  521. package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
  522. package/dist/src/core/test-harness-verdict-notes.js +4 -4
  523. package/dist/src/core/test-path-scope.d.ts +8 -8
  524. package/dist/src/core/test-path-scope.js +11 -11
  525. package/dist/src/core/test-stale-check.d.ts +22 -23
  526. package/dist/src/core/test-stale-check.js +31 -30
  527. package/dist/src/core/test-stale-symlink.d.ts +1 -1
  528. package/dist/src/core/test-stale-symlink.js +1 -1
  529. package/dist/src/core/test-stall-triage.d.ts +9 -9
  530. package/dist/src/core/test-stall-triage.js +22 -22
  531. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  532. package/dist/src/core/test-xpcshell-retry.js +14 -11
  533. package/dist/src/core/token-category.d.ts +35 -2
  534. package/dist/src/core/token-category.js +67 -58
  535. package/dist/src/core/token-coverage.js +4 -5
  536. package/dist/src/core/token-dark-mode.d.ts +9 -9
  537. package/dist/src/core/token-dark-mode.js +13 -25
  538. package/dist/src/core/token-docs.d.ts +1 -1
  539. package/dist/src/core/token-inventory.d.ts +56 -0
  540. package/dist/src/core/token-inventory.js +109 -0
  541. package/dist/src/core/token-manager.d.ts +4 -4
  542. package/dist/src/core/token-manager.js +22 -22
  543. package/dist/src/core/token-scaffold.d.ts +4 -4
  544. package/dist/src/core/token-scaffold.js +4 -4
  545. package/dist/src/core/token-variant.d.ts +14 -14
  546. package/dist/src/core/token-variant.js +52 -53
  547. package/dist/src/core/toolchain-preflight.d.ts +15 -15
  548. package/dist/src/core/toolchain-preflight.js +23 -23
  549. package/dist/src/core/tree-cow.d.ts +3 -5
  550. package/dist/src/core/tree-cow.js +8 -8
  551. package/dist/src/core/tree-guard.d.ts +3 -3
  552. package/dist/src/core/tree-guard.js +23 -23
  553. package/dist/src/core/tree-store.d.ts +15 -15
  554. package/dist/src/core/tree-store.js +39 -38
  555. package/dist/src/core/typecheck-shim.d.ts +16 -15
  556. package/dist/src/core/typecheck-shim.js +26 -25
  557. package/dist/src/core/typecheck.d.ts +12 -12
  558. package/dist/src/core/typecheck.js +33 -33
  559. package/dist/src/core/wire-destroy.d.ts +2 -2
  560. package/dist/src/core/wire-destroy.js +5 -5
  561. package/dist/src/core/wire-dom-fragment.d.ts +3 -3
  562. package/dist/src/core/wire-dom-fragment.js +12 -23
  563. package/dist/src/core/wire-init.d.ts +2 -2
  564. package/dist/src/core/wire-init.js +7 -7
  565. package/dist/src/core/wire-subscript.d.ts +1 -1
  566. package/dist/src/core/wire-subscript.js +3 -3
  567. package/dist/src/core/wire-utils.d.ts +9 -9
  568. package/dist/src/core/wire-utils.js +16 -28
  569. package/dist/src/core/xpcshell-appdir.d.ts +20 -20
  570. package/dist/src/core/xpcshell-appdir.js +28 -30
  571. package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
  572. package/dist/src/core/xpcshell-profile-dir.js +7 -7
  573. package/dist/src/errors/base.d.ts +69 -16
  574. package/dist/src/errors/base.js +95 -26
  575. package/dist/src/errors/build.d.ts +6 -6
  576. package/dist/src/errors/build.js +26 -34
  577. package/dist/src/errors/codes.d.ts +10 -10
  578. package/dist/src/errors/codes.js +10 -10
  579. package/dist/src/errors/config.d.ts +0 -14
  580. package/dist/src/errors/config.js +13 -34
  581. package/dist/src/errors/download.d.ts +13 -0
  582. package/dist/src/errors/download.js +53 -24
  583. package/dist/src/errors/furnace.d.ts +2 -2
  584. package/dist/src/errors/furnace.js +8 -9
  585. package/dist/src/errors/git.d.ts +9 -9
  586. package/dist/src/errors/git.js +21 -31
  587. package/dist/src/errors/patch.d.ts +3 -3
  588. package/dist/src/errors/patch.js +11 -13
  589. package/dist/src/errors/rebase.d.ts +1 -1
  590. package/dist/src/errors/rebase.js +8 -8
  591. package/dist/src/errors/run.d.ts +1 -1
  592. package/dist/src/errors/run.js +1 -1
  593. package/dist/src/index.d.ts +4 -4
  594. package/dist/src/index.js +4 -4
  595. package/dist/src/types/commands/options.d.ts +155 -200
  596. package/dist/src/types/commands/patches.d.ts +19 -19
  597. package/dist/src/types/commands/project.d.ts +3 -3
  598. package/dist/src/types/config.d.ts +52 -19
  599. package/dist/src/types/furnace.d.ts +17 -17
  600. package/dist/src/types/index.d.ts +0 -1
  601. package/dist/src/types/json.d.ts +3 -3
  602. package/dist/src/types/json.js +2 -2
  603. package/dist/src/types/typecheck.d.ts +3 -3
  604. package/dist/src/utils/assert.d.ts +4 -16
  605. package/dist/src/utils/assert.js +7 -24
  606. package/dist/src/utils/build-info.d.ts +6 -6
  607. package/dist/src/utils/build-info.js +6 -6
  608. package/dist/src/utils/child-env.d.ts +7 -6
  609. package/dist/src/utils/child-env.js +5 -5
  610. package/dist/src/utils/concurrency.d.ts +2 -2
  611. package/dist/src/utils/concurrency.js +2 -2
  612. package/dist/src/utils/elapsed.js +10 -1
  613. package/dist/src/utils/errors.d.ts +8 -8
  614. package/dist/src/utils/errors.js +8 -8
  615. package/dist/src/utils/fs.d.ts +1 -1
  616. package/dist/src/utils/fs.js +15 -20
  617. package/dist/src/utils/hash.d.ts +12 -0
  618. package/dist/src/utils/hash.js +16 -0
  619. package/dist/src/utils/line-dispatch.d.ts +15 -0
  620. package/dist/src/utils/line-dispatch.js +48 -0
  621. package/dist/src/utils/logger.d.ts +4 -4
  622. package/dist/src/utils/logger.js +11 -11
  623. package/dist/src/utils/machine-output.js +2 -2
  624. package/dist/src/utils/options.d.ts +14 -20
  625. package/dist/src/utils/options.js +26 -27
  626. package/dist/src/utils/package-root.js +5 -14
  627. package/dist/src/utils/paths.d.ts +4 -4
  628. package/dist/src/utils/paths.js +4 -4
  629. package/dist/src/utils/platform.d.ts +0 -4
  630. package/dist/src/utils/process-group.d.ts +10 -9
  631. package/dist/src/utils/process-group.js +37 -36
  632. package/dist/src/utils/process.d.ts +70 -55
  633. package/dist/src/utils/process.js +129 -179
  634. package/dist/src/utils/ps-duration.d.ts +4 -4
  635. package/dist/src/utils/ps-duration.js +9 -9
  636. package/dist/src/utils/regex.d.ts +4 -4
  637. package/dist/src/utils/regex.js +7 -7
  638. package/dist/src/utils/sleep.d.ts +26 -0
  639. package/dist/src/utils/sleep.js +31 -0
  640. package/dist/src/utils/stdio-drain.d.ts +7 -7
  641. package/dist/src/utils/stdio-drain.js +8 -8
  642. package/dist/src/utils/validation.d.ts +12 -49
  643. package/dist/src/utils/validation.js +26 -36
  644. package/docs/README.md +2 -2
  645. package/docs/configuration.md +163 -69
  646. package/docs/exit-codes.md +66 -49
  647. package/docs/furnace.md +20 -19
  648. package/docs/lifecycle-invariants.md +414 -247
  649. package/docs/machine-output.md +58 -34
  650. package/docs/patch-workflow.md +48 -44
  651. package/docs/run-logs.md +72 -28
  652. package/docs/testing.md +105 -98
  653. package/docs/verification-trees.md +23 -22
  654. package/package.json +7 -6
  655. package/dist/src/commands/rebase.d.ts +0 -4
  656. package/dist/src/commands/rebase.js +0 -5
  657. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  658. package/dist/src/core/patch-artifact-normalize.js +0 -24
  659. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  660. package/dist/src/core/patch-lint-reexports.js +0 -8
  661. package/dist/src/core/wire-targets.d.ts +0 -7
  662. package/dist/src/core/wire-targets.js +0 -8
@@ -7,11 +7,11 @@
7
7
  * browser with that flag, so any test run needs the port free at start.
8
8
  *
9
9
  * An interrupted `fireforge test` can leave an orphan browser process
10
- * listening on 2828 with parent PID 1, and the next test run — possibly in a
11
- * *different* FireForge project — then fails with a bare Marionette bind
12
- * error. This probe runs before every test launch, detects when the port is
13
- * held, and — when the holder is a browser process (by command-line
14
- * `-marionette` flag or by basename matching a known browser binary) —
10
+ * listening on 2828 with parent PID 1, and the next test run (possibly in a
11
+ * *different* FireForge project) then fails with a bare Marionette bind
12
+ * error. This probe runs before every test launch and detects when the port
13
+ * is held. When the holder is a browser process (by command-line
14
+ * `-marionette` flag or by basename matching a known browser binary), it
15
15
  * throws a targeted `GeneralError` naming the PID and the exact `kill`
16
16
  * command to run.
17
17
  *
@@ -22,9 +22,10 @@
22
22
  *
23
23
  * Both paths tolerate missing tooling: if `lsof` / PowerShell is not
24
24
  * installed the probe returns `{ inUse: false }` rather than failing the
25
- * test run — it is a best-effort friendliness check, not a prerequisite.
25
+ * test run. It is a best-effort friendliness check rather than a
26
+ * prerequisite.
26
27
  */
27
- import { GeneralError } from '../errors/base.js';
28
+ import { PreflightRefusalError } from '../errors/base.js';
28
29
  import { toError } from '../utils/errors.js';
29
30
  import { getPlatform } from '../utils/platform.js';
30
31
  import { exec } from '../utils/process.js';
@@ -63,7 +64,7 @@ async function findRunningBundleProcesses(launchableBinary) {
63
64
  return parseProcessList(result.stdout, launchableBinary);
64
65
  }
65
66
  // `etime=` is what makes the refusal attributable on a shared checkout:
66
- // a browser that started as YOUR run was finishing is not yours.
67
+ // a browser that started as your run was finishing is not yours.
67
68
  const result = await exec('ps', ['-axo', 'pid=,etime=,args=']);
68
69
  return parseProcessList(result.stdout, launchableBinary);
69
70
  }
@@ -76,7 +77,7 @@ async function findRunningBundleProcesses(launchableBinary) {
76
77
  * regression-testable.
77
78
  *
78
79
  * Reads `pid etime args` where the middle field is a `ps` duration. The
79
- * elapsed field is parsed OPTIMISTICALLY: a listing produced without
80
+ * elapsed field is parsed optimistically: a listing produced without
80
81
  * `etime=` still parses, with the duration reported as `NaN` and the whole
81
82
  * second field folded back into the command line, so a caller that lost the
82
83
  * column degrades to the old behaviour instead of dropping the process.
@@ -133,19 +134,19 @@ export async function ensureLaunchableBrowserNotRunning(launchableBinary, option
133
134
  return;
134
135
  }
135
136
  catch (error) {
136
- throw new GeneralError(`A browser from this objdir is still running (PID ${holder.pid}), but FireForge could not terminate it: ${toError(error).message}`);
137
+ throw new PreflightRefusalError(`A browser from this objdir is still running (PID ${holder.pid}), but FireForge could not terminate it: ${toError(error).message}`, 'stale-browser-kill-failed');
137
138
  }
138
139
  }
139
- throw new GeneralError(describeRunningBundleRefusal(holder));
140
+ throw new PreflightRefusalError(describeRunningBundleRefusal(holder), 'stale-browser');
140
141
  }
141
142
  /**
142
- * True when the process was launched BY a test harness — its command line
143
- * carries `-marionette` (the control channel every `fireforge test` browser
144
- * is started with) or a harness `-profile`.
143
+ * True when the process was launched by a test harness, i.e. its command
144
+ * line carries `-marionette` (the control channel every `fireforge test`
145
+ * browser is started with) or a harness `-profile`.
145
146
  *
146
147
  * This is the distinction the refusal turns on. The objdir-bundle probe
147
148
  * matches any process running this project's binary, which on a shared
148
- * checkout includes a peer session's LIVE browser and a developer's own
149
+ * checkout includes a peer session's live browser and a developer's own
149
150
  * interactive one. Only a marionette-driven browser is safely
150
151
  * attributable to an interrupted run.
151
152
  */
@@ -155,17 +156,17 @@ function isHarnessDrivenBrowser(commandLine) {
155
156
  /**
156
157
  * Builds the refusal for a running objdir browser.
157
158
  *
158
- * Reports the EVIDENCE rather than a bare PID: the elapsed time and the
159
+ * Reports the evidence rather than a bare PID: the elapsed time and the
159
160
  * command line are what let an operator on a shared checkout decide whose
160
161
  * process it is, without reconstructing PID ancestry by hand. A downstream
161
- * fork hit exactly this — the message named a PID belonging to a peer
162
+ * fork hit exactly this: the message named a PID belonging to a peer
162
163
  * session's live browser and offered a flag that would have killed a
163
164
  * multi-hour evaluation run.
164
165
  *
165
- * So `--kill-stale-marionette` is offered ONLY for a marionette-driven
166
+ * So `--kill-stale-marionette` is offered only for a marionette-driven
166
167
  * browser. For a bare launch the message says what it found and stops:
167
168
  * FireForge cannot tell a dead run's orphan from someone's live window, and
168
- * the flag is the right MANUAL clear once ownership is verified, never an
169
+ * the flag is the right manual clear once ownership is verified, never an
169
170
  * automatic one.
170
171
  *
171
172
  * Exported for direct unit testing.
@@ -216,19 +217,19 @@ function isBrowserMarionettePortHolder(holder, binaryName) {
216
217
  }
217
218
  /**
218
219
  * Probes the given port with `lsof` (macOS / Linux). Returns
219
- * `{ inUse: false }` when the port is free OR when `lsof` is not
220
- * available — the probe is a best-effort courtesy check, so a
220
+ * `{ inUse: false }` when the port is free or when `lsof` is not
221
+ * available. The probe is a best-effort courtesy check, so a
221
222
  * missing tool must not block the test run.
222
223
  */
223
224
  async function probeWithLsof(port) {
224
225
  try {
225
- // `-sTCP:LISTEN` filters to listeners only; `-P -n` avoids
226
+ // `-sTCP:LISTEN` filters to listeners only, and `-P -n` avoids
226
227
  // service/host lookups (faster + no DNS-dependent flakiness).
227
228
  // `-Fpcn` emits a machine-readable format: one field per line,
228
229
  // with `p<pid>`, `c<command>`, `n<name>` records.
229
230
  const result = await exec('lsof', ['-i', `tcp:${port}`, '-P', '-n', '-sTCP:LISTEN', '-Fpcn']);
230
- // `lsof` exits 1 when no matches — that's "port is free", not an
231
- // error. We key off stdout shape instead of exit code.
231
+ // `lsof` exits 1 when no matches, which means "port is free" rather
232
+ // than an error. We key off stdout shape instead of exit code.
232
233
  const stdout = result.stdout;
233
234
  const lines = stdout.split(/\r?\n/).filter((l) => l.length > 0);
234
235
  let pid = -1;
@@ -242,7 +243,7 @@ async function probeWithLsof(port) {
242
243
  if (!Number.isFinite(pid) || pid < 0 || command === '') {
243
244
  return { inUse: false };
244
245
  }
245
- // `lsof` does not return the full command line; `ps` does. A
246
+ // `lsof` does not return the full command line, but `ps` does. A
246
247
  // missing `ps` (exotic Linux container) falls back to `command`
247
248
  // alone, which is still enough to match `BROWSER_BASENAMES`.
248
249
  let commandLine = command;
@@ -253,7 +254,7 @@ async function probeWithLsof(port) {
253
254
  commandLine = psLine.trim();
254
255
  }
255
256
  catch {
256
- // ps not available — keep the basename.
257
+ // ps not available, so keep the basename.
257
258
  }
258
259
  return { inUse: true, holder: { pid, command, commandLine } };
259
260
  }
@@ -320,7 +321,7 @@ export async function probeMarionettePort(port = DEFAULT_MARIONETTE_PORT) {
320
321
  platform = getPlatform();
321
322
  }
322
323
  catch {
323
- // Unrecognised host platform — no probe strategy applies, so the port is
324
+ // Unrecognised host platform, so no probe strategy applies and the port is
324
325
  // reported free rather than blocking the run.
325
326
  return { inUse: false };
326
327
  }
@@ -332,7 +333,7 @@ export async function probeMarionettePort(port = DEFAULT_MARIONETTE_PORT) {
332
333
  }
333
334
  /**
334
335
  * Raises a targeted {@link GeneralError} when the Marionette port
335
- * is held by a browser process; raises a softer warning-shaped
336
+ * is held by a browser process. Raises a softer warning-shaped
336
337
  * error when the holder is unrelated (so the operator still sees
337
338
  * a useful signal but can decide whether to wait it out).
338
339
  *
@@ -349,18 +350,18 @@ export async function assertMarionettePortAvailable(port = DEFAULT_MARIONETTE_PO
349
350
  const killHint = process.platform === 'win32'
350
351
  ? `Stop-Process -Id ${holder.pid} -Force`
351
352
  : `kill ${holder.pid} # or "kill -9 ${holder.pid}" if it doesn't exit`;
352
- throw new GeneralError(`Marionette port ${port} is already in use by ${holder.command} (PID ${holder.pid}). ` +
353
+ throw new PreflightRefusalError(`Marionette port ${port} is already in use by ${holder.command} (PID ${holder.pid}). ` +
353
354
  `This is usually a browser left running by a previously interrupted "fireforge test" run. ` +
354
355
  `Kill it with "${killHint}", then retry. ` +
355
356
  `(If you expected ${holder.command} to be running on ${port}, stop it manually or pass ` +
356
- `"--marionette-port <port>" to launch mach test on a different port.)`);
357
+ `"--marionette-port <port>" to launch mach test on a different port.)`, 'marionette-port-busy');
357
358
  }
358
359
  // Non-browser holder: mach test will still fail to bind, but the
359
360
  // cause is not a stale FireForge-launched browser. Flag it
360
361
  // explicitly so the operator can decide what to do instead of
361
362
  // getting mach's bind error with no FireForge context.
362
- throw new GeneralError(`Marionette port ${port} is already in use by ${holder.command} (PID ${holder.pid}). ` +
363
- `This is not a FireForge-launched browser; stop the holder process or free the port before rerunning.`);
363
+ throw new PreflightRefusalError(`Marionette port ${port} is already in use by ${holder.command} (PID ${holder.pid}). ` +
364
+ `This is not a FireForge-launched browser; stop the holder process or free the port before rerunning.`, 'marionette-port-busy');
364
365
  }
365
366
  /**
366
367
  * Ensures the Marionette port is usable, optionally terminating a stale
@@ -390,8 +391,8 @@ export async function ensureMarionettePortAvailable(port = DEFAULT_MARIONETTE_PO
390
391
  }
391
392
  }
392
393
  catch (error) {
393
- throw new GeneralError(`Marionette port ${port} is held by stale browser ${holder.command} (PID ${holder.pid}), ` +
394
- `but FireForge could not terminate it: ${toError(error).message}`);
394
+ throw new PreflightRefusalError(`Marionette port ${port} is held by stale browser ${holder.command} (PID ${holder.pid}), ` +
395
+ `but FireForge could not terminate it: ${toError(error).message}`, 'stale-browser-kill-failed');
395
396
  }
396
397
  }
397
398
  /**
@@ -405,15 +406,13 @@ export async function ensureMarionettePortAvailable(port = DEFAULT_MARIONETTE_PO
405
406
  * the test command auto-forwards to mach.
406
407
  *
407
408
  * @param machArgs - Forwarded mach args as they would appear on the command
408
- * line (one element per token; `--foo=bar` and `--foo bar` both supported).
409
- * @returns The integer port if a recognised arg is present and parses; else
410
- * `undefined`.
409
+ * line (one element per token, with `--foo=bar` and `--foo bar` both
410
+ * supported).
411
+ * @returns The integer port if a recognised arg is present and parses,
412
+ * otherwise `undefined`.
411
413
  */
412
414
  export function extractForwardedMarionettePort(machArgs) {
413
- for (let i = 0; i < machArgs.length; i++) {
414
- const arg = machArgs[i];
415
- if (arg === undefined)
416
- continue;
415
+ for (const [i, arg] of machArgs.entries()) {
417
416
  // `--marionette-port=NNNN`
418
417
  let match = /^--marionette-port=(\d+)$/.exec(arg);
419
418
  if (match?.[1]) {
@@ -430,7 +429,7 @@ export function extractForwardedMarionettePort(machArgs) {
430
429
  return n;
431
430
  }
432
431
  }
433
- // `--setpref=marionette.port=NNNN` — the auto-forward shape; recognised
432
+ // `--setpref=marionette.port=NNNN`, the auto-forward shape. Recognised
434
433
  // here so a duplicate check at the call site can spot operator-supplied
435
434
  // setprefs without re-implementing the parse.
436
435
  match = /^--setpref=marionette\.port=(\d+)$/.exec(arg);
@@ -446,16 +445,14 @@ export function extractForwardedMarionettePort(machArgs) {
446
445
  * True when forwarded mach args already set a Marionette **client** address
447
446
  * for mach/mochitest (`--marionette=host:port` or `--marionette host:port`).
448
447
  * Used only to avoid duplicating FireForge's auto-injected
449
- * `--marionette=127.0.0.1:<n>`; this is not a full URL validator (IPv6, etc.).
448
+ * `--marionette=127.0.0.1:<n>`. This is not a full URL validator (IPv6,
449
+ * etc.).
450
450
  *
451
- * Deliberately does **not** treat `--marionette-port` as a client endpoint.
451
+ * Does not treat `--marionette-port` as a client endpoint.
452
452
  */
453
453
  export function forwardedMachArgsIncludeMarionetteClient(machArgs) {
454
454
  const valueLooksLikeHostPort = (token) => /:[0-9]+$/.test(token) || /^\[[^]]+\]:[0-9]+$/.test(token);
455
- for (let i = 0; i < machArgs.length; i++) {
456
- const arg = machArgs[i];
457
- if (arg === undefined)
458
- continue;
455
+ for (const [i, arg] of machArgs.entries()) {
459
456
  if (arg.startsWith('--marionette=') && !arg.startsWith('--marionette-port=')) {
460
457
  return true;
461
458
  }
@@ -473,8 +470,7 @@ export function forwardedMachArgsIncludeMarionetteClient(machArgs) {
473
470
  * for runs where the pref is ignored anyway.
474
471
  */
475
472
  export function hasExplicitXpcshellFlavor(machArgs) {
476
- for (let i = 0; i < machArgs.length; i += 1) {
477
- const arg = machArgs[i] ?? '';
473
+ for (const [i, arg] of machArgs.entries()) {
478
474
  if (/^--flavor=xpcshell\b/.test(arg) || arg === '--flavor=xpcshell-tests')
479
475
  return true;
480
476
  if (arg === '--flavor' && /^xpcshell(?:-tests)?$/.test(machArgs[i + 1] ?? ''))
@@ -493,42 +489,3 @@ export function hasExplicitXpcshellFlavor(machArgs) {
493
489
  export function shouldAutoForwardMarionettePortToMach(machArgs) {
494
490
  return !hasExplicitXpcshellFlavor(machArgs);
495
491
  }
496
- /**
497
- * Heuristic: do the test paths or forwarded mach args indicate a flavour
498
- * that actually launches a Marionette-driven browser? Browser-chrome and
499
- * mochitest do; xpcshell does not. A no-paths invocation (the default "run
500
- * all tests" shape) is treated as marionette-relevant since it includes
501
- * browser-chrome.
502
- *
503
- * Note: `fireforge test` auto-forward of `--marionette-port` to mach uses
504
- * {@link shouldAutoForwardMarionettePortToMach} (mach-arg flavor gate) rather
505
- * than this function alone, so toolkit paths without `/mochitest/` still get
506
- * the listener pref and harness `--marionette=127.0.0.1:<n>` when appropriate.
507
- *
508
- * @param testPaths - Engine-relative paths after `stripEnginePrefix`.
509
- * @param machArgs - Forwarded mach args (post-`--mach-arg`).
510
- * @returns `true` when the run is likely to bind a Marionette listener.
511
- */
512
- export function isMarionetteFlavor(testPaths, machArgs) {
513
- if (hasExplicitXpcshellFlavor(machArgs))
514
- return false;
515
- for (const arg of machArgs) {
516
- if (/^--flavor=(browser-chrome|mochitest|chrome|a11y)\b/.test(arg))
517
- return true;
518
- }
519
- if (testPaths.length === 0)
520
- return true;
521
- for (const path of testPaths) {
522
- const base = path.split('/').pop() ?? path;
523
- if (/^browser_.+\.(js|ini|toml)$/.test(base))
524
- return true;
525
- if (path.includes('/mochitest/') || path.startsWith('mochitest/'))
526
- return true;
527
- if (path.includes('/browser-chrome/') || path.startsWith('browser-chrome/'))
528
- return true;
529
- if (path.includes('toolkit/content/tests/') && !path.includes('/tests/xpcshell/')) {
530
- return true;
531
- }
532
- }
533
- return false;
534
- }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Answers a single question before tests run: "does marionette come up?" A
5
5
  * silent 360-second mach-test hang is indistinguishable from "tests failed
6
- * to discover"; this helper surfaces the failure in under a minute with a
6
+ * to discover". This helper surfaces the failure in under a minute with a
7
7
  * clear PASS/FAIL line and the tail of the browser's stderr.
8
8
  *
9
9
  * The probe is a cascade of layered checks (engine → mach → python →
@@ -22,7 +22,7 @@ export interface MarionettePreflightResult {
22
22
  export interface MarionettePreflightOptions {
23
23
  /** Total budget in ms. Defaults to 30 seconds. */
24
24
  timeoutMs?: number;
25
- /** Overrides marionette TCP port — primarily used in tests. */
25
+ /** Overrides marionette TCP port. Primarily used in tests. */
26
26
  port?: number;
27
27
  /**
28
28
  * Grace window after spawn() before the browser is considered "running
@@ -37,16 +37,16 @@ export interface MarionettePreflightOptions {
37
37
  }
38
38
  /**
39
39
  * Runs the marionette preflight. Returns PASS on first byte read from the
40
- * marionette socket within the budget; FAIL otherwise, with a diagnostic
41
- * identifying which layer of the cascade broke. Always tears down the
42
- * spawned browser before returning.
40
+ * marionette socket within the budget, and FAIL otherwise, with a
41
+ * diagnostic identifying which layer of the cascade broke. Always tears
42
+ * down the spawned browser before returning.
43
43
  */
44
44
  export declare function runMarionettePreflight(engineDir: string, options?: MarionettePreflightOptions): Promise<MarionettePreflightResult>;
45
45
  /** Renders a PASS/FAIL banner to the CLI using the shared logger helpers. */
46
46
  export declare function reportMarionettePreflight(result: MarionettePreflightResult): void;
47
47
  /**
48
48
  * Formats the PASS/FAIL banner as a plain string for direct
49
- * `process.stdout.write` use — bypassing the clack logger entirely so
49
+ * `process.stdout.write` use, bypassing the clack logger entirely so
50
50
  * operators running `fireforge test --doctor` under a non-TTY (pipe, CI,
51
51
  * `tee`-wrapped capture) always see the final line. Clack's renderer can
52
52
  * swallow trailing log output just before process exit, and a
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Answers a single question before tests run: "does marionette come up?" A
6
6
  * silent 360-second mach-test hang is indistinguishable from "tests failed
7
- * to discover"; this helper surfaces the failure in under a minute with a
7
+ * to discover". This helper surfaces the failure in under a minute with a
8
8
  * clear PASS/FAIL line and the tail of the browser's stderr.
9
9
  *
10
10
  * The probe is a cascade of layered checks (engine → mach → python →
@@ -22,6 +22,7 @@ import { pathExists } from '../utils/fs.js';
22
22
  import { info, verbose, warn } from '../utils/logger.js';
23
23
  import { installGracefulShutdownForwarder, trackChildClosure } from '../utils/process.js';
24
24
  import { killProcessTree, sweepProcessGroup } from '../utils/process-group.js';
25
+ import { sleep } from '../utils/sleep.js';
25
26
  import { ensureMach } from './mach.js';
26
27
  import { getPython } from './mach-python.js';
27
28
  /** Marionette's default TCP port when the browser is launched with `--marionette`. */
@@ -33,7 +34,7 @@ const SOCKET_ATTEMPT_TIMEOUT_MS = 2_000;
33
34
  /**
34
35
  * Grace window after spawn() returns before we accept the child as
35
36
  * "spawned OK". A browser binary that exits immediately (missing dylib,
36
- * wrong CPU arch, corrupt profile) must be caught here — not 30 seconds
37
+ * wrong CPU arch, corrupt profile) must be caught here, not 30 seconds
37
38
  * later at the socket layer.
38
39
  */
39
40
  const SPAWN_SETTLE_MS = 750;
@@ -57,9 +58,9 @@ function layerTag(name) {
57
58
  }
58
59
  /**
59
60
  * Runs the marionette preflight. Returns PASS on first byte read from the
60
- * marionette socket within the budget; FAIL otherwise, with a diagnostic
61
- * identifying which layer of the cascade broke. Always tears down the
62
- * spawned browser before returning.
61
+ * marionette socket within the budget, and FAIL otherwise, with a
62
+ * diagnostic identifying which layer of the cascade broke. Always tears
63
+ * down the spawned browser before returning.
63
64
  */
64
65
  export async function runMarionettePreflight(engineDir, options = {}) {
65
66
  const timeoutMs = options.timeoutMs ?? DEFAULT_PREFLIGHT_TIMEOUT_MS;
@@ -100,15 +101,15 @@ export async function runMarionettePreflight(engineDir, options = {}) {
100
101
  let stderrTail = '';
101
102
  // Shutdown contract for a child spawned outside the exec layer.
102
103
  //
103
- // This is the repo's one legitimate raw `spawn`: the preflight needs the
104
- // live `ChildProcess` mid-run (`hasChildExited` gates the socket poll),
104
+ // This is the one raw `spawn` in the repo. The preflight needs the live
105
+ // `ChildProcess` mid-run (`hasChildExited` gates the socket poll),
105
106
  // returns while the browser is still running, and aborts on a TCP byte
106
- // rather than on a deadline — none of which any wrapper in utils/process
107
- // can express. What it does NOT get to skip is the contract every wrapper
108
- // applies to a detached child: register the closure so the bin signal
109
- // handler waits for it, and forward the parent's SIGINT/SIGTERM to the
110
- // group. Without both, Ctrl+C during `fireforge test --doctor` left the
111
- // whole mach → Firefox tree running.
107
+ // rather than on a deadline. No wrapper in utils/process can express
108
+ // that. It still has to honour the contract every wrapper applies to a
109
+ // detached child: register the closure so the bin signal handler waits
110
+ // for it, and forward the parent's SIGINT/SIGTERM to the group. Without
111
+ // both, Ctrl+C during `fireforge test --doctor` left the whole
112
+ // mach → Firefox tree running.
112
113
  let closure;
113
114
  let forwarder;
114
115
  try {
@@ -129,7 +130,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
129
130
  // `detached: true` puts the child in a new process group so we can
130
131
  // signal it and every descendant (Firefox, its helpers) via
131
132
  // `process.kill(-pid, …)` in the finally block. Without it, the
132
- // child is Python running mach; a SIGTERM kills Python but the
133
+ // child is Python running mach. A SIGTERM kills Python but the
133
134
  // Firefox grandchild inherits the stderr pipe FD and keeps Node's
134
135
  // event loop alive even after the preflight PASS log, so
135
136
  // `fireforge test --doctor` prints `Marionette preflight: PASS`
@@ -143,22 +144,22 @@ export async function runMarionettePreflight(engineDir, options = {}) {
143
144
  const spawnedChild = child;
144
145
  closure = trackChildClosure();
145
146
  forwarder = installGracefulShutdownForwarder(spawnedChild, 500, (signal) => {
146
- killProcessGroup(spawnedChild, signal);
147
+ killProcessTree(spawnedChild, signal, process.platform !== 'win32');
147
148
  });
148
149
  child.stderr?.on('data', (data) => {
149
150
  const chunk = data.toString();
150
151
  stderrTail = (stderrTail + chunk).slice(-STDERR_TAIL_LIMIT);
151
152
  });
152
- // Short settle window — catches "binary exits immediately" failures
153
+ // Short settle window. Catches "binary exits immediately" failures
153
154
  // (missing dylib, wrong CPU arch, corrupt profile) before the socket
154
155
  // poll swallows the full overall budget waiting for bytes that will
155
156
  // never come.
156
157
  const settleDeadline = Math.min(spawnSettleMs, Math.max(0, timeoutMs - elapsed()));
157
158
  if (settleDeadline > 0) {
158
- await delay(settleDeadline);
159
+ await sleep(settleDeadline, { unref: true });
159
160
  }
160
161
  if (hasChildExited(spawnedChild)) {
161
- return fail('browser-spawns', `Browser process exited during spawn (exit code ${String(spawnedChild.exitCode)}, signal ${spawnedChild.signalCode ?? 'none'}). ` +
162
+ return fail('browser-spawns', `Browser process exited during spawn (exit code ${spawnedChild.exitCode}, signal ${spawnedChild.signalCode ?? 'none'}). ` +
162
163
  `stderr tail: ${stderrTail.trim().slice(-2_000) || '(empty)'}`, elapsed());
163
164
  }
164
165
  // Layer 6: marionette handshake within the remaining budget.
@@ -172,10 +173,10 @@ export async function runMarionettePreflight(engineDir, options = {}) {
172
173
  detail: `Marionette handshake received on 127.0.0.1:${port} in ${Date.now() - startedAt}ms.`,
173
174
  };
174
175
  }
175
- // Child may have exited before the socket was ever ready — surface that
176
+ // Child may have exited before the socket was ever ready. Surface that
176
177
  // distinctly from "socket never answered" so the operator has a lead.
177
178
  if (hasChildExited(spawnedChild)) {
178
- return fail('marionette-handshake', `Browser process exited before marionette handshake (exit code ${String(spawnedChild.exitCode)}, signal ${spawnedChild.signalCode ?? 'none'}). ` +
179
+ return fail('marionette-handshake', `Browser process exited before marionette handshake (exit code ${spawnedChild.exitCode}, signal ${spawnedChild.signalCode ?? 'none'}). ` +
179
180
  `stderr tail: ${stderrTail.trim().slice(-2_000) || '(empty)'}`, elapsed());
180
181
  }
181
182
  return fail('marionette-handshake', `Marionette socket on 127.0.0.1:${port} did not respond within ${timeoutMs}ms. ` +
@@ -203,17 +204,17 @@ async function teardownPreflightChild(child, forwarder, closure, profileDir) {
203
204
  forwarder?.dispose();
204
205
  const groupPid = child?.pid;
205
206
  if (child && !hasChildExited(child)) {
206
- killProcessGroup(child, 'SIGTERM');
207
+ killProcessTree(child, 'SIGTERM', process.platform !== 'win32');
207
208
  // Small escalation: if the child doesn't honour SIGTERM quickly, SIGKILL
208
209
  // so we don't leave a ghost mach process around after a failed probe.
209
- await delay(500);
210
+ await sleep(500, { unref: true });
210
211
  if (!hasChildExited(child)) {
211
- killProcessGroup(child, 'SIGKILL');
212
+ killProcessTree(child, 'SIGKILL', process.platform !== 'win32');
212
213
  }
213
214
  }
214
215
  // Reap anything that outlived the group signal. The file's own comments
215
- // worry about exactly this — Firefox grandchildren surviving the Python
216
- // mach wrapper — and every exec-layer wrapper sweeps for it.
216
+ // worry about exactly this case (Firefox grandchildren surviving the
217
+ // Python mach wrapper), and every exec-layer wrapper sweeps for it.
217
218
  if (groupPid !== undefined && process.platform !== 'win32') {
218
219
  try {
219
220
  await sweepProcessGroup(groupPid);
@@ -225,8 +226,8 @@ async function teardownPreflightChild(child, forwarder, closure, profileDir) {
225
226
  closure?.settle();
226
227
  // Destroy the stderr pipe explicitly. Firefox (a grandchild of the Python
227
228
  // mach wrapper we spawned) can inherit and hold the stderr FD even after
228
- // its direct parent exits — until the pipe closes, Node's readable
229
- // stream stays attached and `uv__io_poll` keeps the event loop alive.
229
+ // its direct parent exits. Until the pipe closes, Node's readable stream
230
+ // stays attached and `uv__io_poll` keeps the event loop alive.
230
231
  // `destroy()` closes the local end regardless, so `fireforge test
231
232
  // --doctor` exits cleanly after a passing preflight.
232
233
  child?.stderr?.destroy();
@@ -237,19 +238,6 @@ async function teardownPreflightChild(child, forwarder, closure, profileDir) {
237
238
  warn(`Could not clean up marionette preflight profile: ${toError(error).message}`);
238
239
  }
239
240
  }
240
- /**
241
- * Sends `signal` to the child's whole process group when possible, falling
242
- * back to a direct `child.kill` for environments that don't support
243
- * `detached: true` (Windows in particular: Node still returns a pid, but
244
- * `kill(-pid, …)` is not a supported kernel primitive).
245
- */
246
- function killProcessGroup(child, signal) {
247
- // Delegates to the shared implementation, which is a strict superset of
248
- // the hand-rolled one this replaced: same POSIX `kill(-pid)` with the same
249
- // fall-through to a direct `child.kill`, plus a Windows `taskkill /T /F`
250
- // branch and an already-exited early return.
251
- killProcessTree(child, signal, process.platform !== 'win32');
252
- }
253
241
  function fail(layer, message, durationMs) {
254
242
  return {
255
243
  ok: false,
@@ -267,7 +255,7 @@ async function waitForMarionetteSocket(port, connectFn, keepTrying) {
267
255
  if (result.ok) {
268
256
  return { ok: true };
269
257
  }
270
- await delay(400);
258
+ await sleep(400, { unref: true });
271
259
  }
272
260
  return { ok: false };
273
261
  }
@@ -283,7 +271,7 @@ function attemptMarionetteConnect(port, connectFn) {
283
271
  socket.destroy();
284
272
  }
285
273
  catch {
286
- // Ignore — already closed.
274
+ // Ignore: already closed.
287
275
  }
288
276
  resolve({ ok });
289
277
  };
@@ -292,7 +280,7 @@ function attemptMarionetteConnect(port, connectFn) {
292
280
  }, SOCKET_ATTEMPT_TIMEOUT_MS);
293
281
  attemptTimer.unref();
294
282
  socket.once('connect', () => {
295
- // Connect alone is insufficient — the marionette server performs a
283
+ // Connect alone is insufficient. The marionette server performs a
296
284
  // handshake send as soon as the socket opens, so wait for at least one
297
285
  // byte to confirm the server is actually speaking marionette.
298
286
  const readTimer = setTimeout(() => {
@@ -312,12 +300,6 @@ function attemptMarionetteConnect(port, connectFn) {
312
300
  });
313
301
  });
314
302
  }
315
- function delay(ms) {
316
- return new Promise((resolve) => {
317
- const timer = setTimeout(resolve, ms);
318
- timer.unref();
319
- });
320
- }
321
303
  /** Renders a PASS/FAIL banner to the CLI using the shared logger helpers. */
322
304
  export function reportMarionettePreflight(result) {
323
305
  if (result.ok) {
@@ -329,7 +311,7 @@ export function reportMarionettePreflight(result) {
329
311
  }
330
312
  /**
331
313
  * Formats the PASS/FAIL banner as a plain string for direct
332
- * `process.stdout.write` use — bypassing the clack logger entirely so
314
+ * `process.stdout.write` use, bypassing the clack logger entirely so
333
315
  * operators running `fireforge test --doctor` under a non-TTY (pipe, CI,
334
316
  * `tee`-wrapped capture) always see the final line. Clack's renderer can
335
317
  * swallow trailing log output just before process exit, and a
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Minimal Markdown pipe-table parser/writer used by token-manager.
3
3
  *
4
- * This is **not** a general Markdown parser. It understands exactly the
4
+ * This is not a general Markdown parser. It understands exactly the
5
5
  * slice of GitHub-flavoured Markdown that FireForge emits into token docs:
6
6
  *
7
7
  * - Leading `|` per row, trailing `|` optional.
@@ -12,10 +12,10 @@
12
12
  * - Literal `|` and `\` inside a cell are expressed as `\|` and `\\`
13
13
  * respectively. The parser treats any other backslash as a literal
14
14
  * so prose-style backslashes in cell values (e.g. a Windows path)
15
- * still round-trip. Unescaping happens at split time; serialization
15
+ * still round-trip. Unescaping happens at split time. Serialization
16
16
  * re-applies escapes so round-trips are exact for well-formed input.
17
17
  *
18
- * The parser returns **positional metadata** (`startLine`, `endLine`) so
18
+ * The parser returns positional metadata (`startLine`, `endLine`) so
19
19
  * callers can splice the table back into the surrounding document by
20
20
  * range instead of hand-rolled line counters. Mutation operations return
21
21
  * a fresh line array rather than mutating in place, matching the rest of
@@ -24,7 +24,7 @@
24
24
  * Fallback tolerance: rows with more cells than the header get their
25
25
  * overflow merged into the last column (using a literal `|` separator
26
26
  * between the merged values). This is for the rare case where a FireForge
27
- * writer emits an unescaped pipe — the parser still produces a consistent
27
+ * writer emits an unescaped pipe. The parser still produces a consistent
28
28
  * cell count rather than desynchronising the table. On re-serialize the
29
29
  * merged cell's literal pipes are escaped, so a malformed input becomes
30
30
  * a well-formed output after one round trip.
@@ -37,8 +37,8 @@ export interface MarkdownTable {
37
37
  headers: string[];
38
38
  /**
39
39
  * Data rows. Each row is an array with exactly `headers.length` entries,
40
- * trimmed. Rows shorter than the header are right-padded with `''`;
41
- * longer rows have trailing cells merged into the last column so the
40
+ * trimmed. Rows shorter than the header are right-padded with `''`.
41
+ * Longer rows have trailing cells merged into the last column so the
42
42
  * round-trip is faithful.
43
43
  */
44
44
  rows: string[][];
@@ -60,14 +60,14 @@ export interface MarkdownTable {
60
60
  */
61
61
  export declare function findNextTable(lines: string[], fromLine: number): MarkdownTable | null;
62
62
  /**
63
- * Returns the first table whose header contains **all** of the provided
63
+ * Returns the first table whose header contains all of the provided
64
64
  * column names (case-sensitive, order-insensitive). Useful when several
65
65
  * pipe tables share a document and you want to select "the one with a
66
66
  * Mode column".
67
67
  */
68
68
  export declare function findTableByColumns(lines: string[], requiredColumns: string[]): MarkdownTable | null;
69
69
  /**
70
- * Returns the first table that appears **after** a heading matching the
70
+ * Returns the first table that appears after a heading matching the
71
71
  * given regex. The heading regex is applied to raw lines (no trimming)
72
72
  * so callers that want leading whitespace flexibility should include
73
73
  * `^\s*` or `^#+\s*` as appropriate.
@@ -83,7 +83,7 @@ export declare function findTableAfterHeading(lines: string[], headingPattern: R
83
83
  export declare function serializeRow(cells: string[]): string;
84
84
  /**
85
85
  * Inserts a new row into `table.rows` at the given zero-based index. A
86
- * negative index counts from the end; `Infinity` appends. Mutates the
86
+ * negative index counts from the end. `Infinity` appends. Mutates the
87
87
  * table object so callers using {@link rewriteTableRows} see the update.
88
88
  */
89
89
  export declare function insertRow(table: MarkdownTable, cells: string[], index: number): void;