@hominis/fireforge 0.43.1 → 0.44.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 (478) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +3 -3
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +13 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-patch-manifest.d.ts +8 -0
  22. package/dist/src/commands/doctor-patch-manifest.js +155 -0
  23. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  24. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  25. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  26. package/dist/src/commands/doctor-working-tree.js +11 -18
  27. package/dist/src/commands/doctor.d.ts +1 -1
  28. package/dist/src/commands/doctor.js +64 -96
  29. package/dist/src/commands/download.js +32 -48
  30. package/dist/src/commands/export-all.js +29 -33
  31. package/dist/src/commands/export-flow.js +6 -6
  32. package/dist/src/commands/export-placement-conflicts.js +10 -9
  33. package/dist/src/commands/export-placement-gate.js +5 -5
  34. package/dist/src/commands/export-shared.d.ts +30 -33
  35. package/dist/src/commands/export-shared.js +45 -43
  36. package/dist/src/commands/export.js +21 -27
  37. package/dist/src/commands/furnace/apply.js +14 -23
  38. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  39. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  40. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  41. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  42. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  43. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  44. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  45. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  46. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  47. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  48. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  49. package/dist/src/commands/furnace/create-readback.js +12 -13
  50. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  51. package/dist/src/commands/furnace/create-templates.js +35 -30
  52. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  53. package/dist/src/commands/furnace/create.js +33 -23
  54. package/dist/src/commands/furnace/deploy.js +16 -24
  55. package/dist/src/commands/furnace/diff.js +15 -10
  56. package/dist/src/commands/furnace/init.js +33 -36
  57. package/dist/src/commands/furnace/override.js +23 -25
  58. package/dist/src/commands/furnace/preview.js +47 -67
  59. package/dist/src/commands/furnace/refresh.js +12 -16
  60. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  61. package/dist/src/commands/furnace/remove-mutations.js +14 -17
  62. package/dist/src/commands/furnace/remove-state.js +1 -1
  63. package/dist/src/commands/furnace/remove.js +33 -38
  64. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  65. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  66. package/dist/src/commands/furnace/rename.js +59 -69
  67. package/dist/src/commands/furnace/scan.js +19 -33
  68. package/dist/src/commands/furnace/status.js +12 -9
  69. package/dist/src/commands/furnace/sync.js +9 -16
  70. package/dist/src/commands/furnace/validate.js +20 -20
  71. package/dist/src/commands/import.js +48 -37
  72. package/dist/src/commands/lint-per-patch.js +15 -10
  73. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  74. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  75. package/dist/src/commands/lint-report.js +6 -7
  76. package/dist/src/commands/lint.d.ts +15 -16
  77. package/dist/src/commands/lint.js +86 -102
  78. package/dist/src/commands/package.js +6 -11
  79. package/dist/src/commands/patch/compact.js +1 -1
  80. package/dist/src/commands/patch/delete.js +24 -33
  81. package/dist/src/commands/patch/index.d.ts +5 -6
  82. package/dist/src/commands/patch/index.js +10 -12
  83. package/dist/src/commands/patch/lint-ignore.js +14 -13
  84. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  85. package/dist/src/commands/patch/move-files-create.js +8 -8
  86. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  87. package/dist/src/commands/patch/move-files-into.js +8 -8
  88. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  89. package/dist/src/commands/patch/patch-context.js +2 -3
  90. package/dist/src/commands/patch/rename.d.ts +10 -11
  91. package/dist/src/commands/patch/rename.js +11 -12
  92. package/dist/src/commands/patch/reorder.js +8 -9
  93. package/dist/src/commands/patch/split-plan.js +1 -1
  94. package/dist/src/commands/patch/split.d.ts +8 -10
  95. package/dist/src/commands/patch/split.js +9 -11
  96. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  97. package/dist/src/commands/patch/staged-dependency.js +7 -3
  98. package/dist/src/commands/patch/tier.d.ts +9 -9
  99. package/dist/src/commands/patch/tier.js +18 -15
  100. package/dist/src/commands/re-export-adjacent.js +9 -8
  101. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  102. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  103. package/dist/src/commands/re-export-drift.js +10 -10
  104. package/dist/src/commands/re-export-files.d.ts +6 -7
  105. package/dist/src/commands/re-export-files.js +34 -44
  106. package/dist/src/commands/re-export-lint.d.ts +10 -13
  107. package/dist/src/commands/re-export-lint.js +16 -14
  108. package/dist/src/commands/re-export-options.d.ts +6 -6
  109. package/dist/src/commands/re-export-options.js +6 -6
  110. package/dist/src/commands/re-export-register.d.ts +4 -10
  111. package/dist/src/commands/re-export-register.js +5 -11
  112. package/dist/src/commands/re-export-scan.js +1 -1
  113. package/dist/src/commands/re-export-single.d.ts +3 -3
  114. package/dist/src/commands/re-export-single.js +33 -25
  115. package/dist/src/commands/re-export.js +13 -21
  116. package/dist/src/commands/rebase/abort.js +3 -3
  117. package/dist/src/commands/rebase/confirm.js +2 -1
  118. package/dist/src/commands/rebase/continue.d.ts +1 -1
  119. package/dist/src/commands/rebase/continue.js +14 -9
  120. package/dist/src/commands/rebase/index.js +11 -11
  121. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  122. package/dist/src/commands/rebase/patch-loop.js +60 -39
  123. package/dist/src/commands/rebase/summary.js +1 -1
  124. package/dist/src/commands/register.js +5 -7
  125. package/dist/src/commands/reset.js +2 -1
  126. package/dist/src/commands/resolve.d.ts +16 -13
  127. package/dist/src/commands/resolve.js +30 -33
  128. package/dist/src/commands/run.js +33 -35
  129. package/dist/src/commands/setup-support.js +15 -19
  130. package/dist/src/commands/setup.js +13 -9
  131. package/dist/src/commands/status-check.d.ts +6 -6
  132. package/dist/src/commands/status-json.d.ts +6 -6
  133. package/dist/src/commands/status-json.js +5 -0
  134. package/dist/src/commands/status-output.d.ts +5 -5
  135. package/dist/src/commands/status-output.js +6 -6
  136. package/dist/src/commands/status-ownership.d.ts +16 -14
  137. package/dist/src/commands/status-ownership.js +16 -14
  138. package/dist/src/commands/status.js +42 -34
  139. package/dist/src/commands/test-build-phase.js +26 -13
  140. package/dist/src/commands/test-diagnose.js +44 -44
  141. package/dist/src/commands/test-register.js +1 -0
  142. package/dist/src/commands/test-run.d.ts +14 -16
  143. package/dist/src/commands/test-run.js +21 -13
  144. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  145. package/dist/src/commands/test-stale-gate.js +15 -16
  146. package/dist/src/commands/test-verdict.d.ts +20 -3
  147. package/dist/src/commands/test-verdict.js +30 -0
  148. package/dist/src/commands/test.js +83 -76
  149. package/dist/src/commands/token-coverage.js +3 -4
  150. package/dist/src/commands/token.js +16 -18
  151. package/dist/src/commands/tree.js +47 -31
  152. package/dist/src/commands/typecheck.d.ts +10 -12
  153. package/dist/src/commands/typecheck.js +24 -27
  154. package/dist/src/commands/verify.js +13 -15
  155. package/dist/src/commands/watch.js +21 -23
  156. package/dist/src/commands/wire.js +52 -62
  157. package/dist/src/core/ast-utils.d.ts +8 -7
  158. package/dist/src/core/ast-utils.js +8 -7
  159. package/dist/src/core/branding.d.ts +9 -14
  160. package/dist/src/core/branding.js +7 -11
  161. package/dist/src/core/browser-wire.d.ts +1 -1
  162. package/dist/src/core/browser-wire.js +14 -19
  163. package/dist/src/core/build-audit-platform.js +25 -33
  164. package/dist/src/core/build-audit-registration.js +17 -25
  165. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  166. package/dist/src/core/build-audit-resolve.js +39 -36
  167. package/dist/src/core/build-audit-transforms.js +18 -19
  168. package/dist/src/core/build-audit.js +28 -42
  169. package/dist/src/core/build-baseline-types.d.ts +29 -35
  170. package/dist/src/core/build-baseline.d.ts +5 -4
  171. package/dist/src/core/build-baseline.js +14 -14
  172. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  173. package/dist/src/core/build-overwrite-guard.js +17 -27
  174. package/dist/src/core/build-prepare.d.ts +2 -2
  175. package/dist/src/core/build-prepare.js +8 -9
  176. package/dist/src/core/config-mutate.js +20 -19
  177. package/dist/src/core/config-state.js +12 -4
  178. package/dist/src/core/config-validate.js +8 -5
  179. package/dist/src/core/config.d.ts +5 -8
  180. package/dist/src/core/config.js +7 -16
  181. package/dist/src/core/coverage-extend.d.ts +15 -13
  182. package/dist/src/core/coverage-extend.js +15 -13
  183. package/dist/src/core/destructive.d.ts +31 -9
  184. package/dist/src/core/destructive.js +29 -26
  185. package/dist/src/core/diff-hunks.js +10 -12
  186. package/dist/src/core/discard-baseline.d.ts +8 -8
  187. package/dist/src/core/discard-baseline.js +16 -15
  188. package/dist/src/core/display-state.d.ts +12 -14
  189. package/dist/src/core/display-state.js +12 -14
  190. package/dist/src/core/engine-changes.d.ts +2 -4
  191. package/dist/src/core/engine-changes.js +2 -4
  192. package/dist/src/core/engine-precondition.d.ts +28 -13
  193. package/dist/src/core/engine-precondition.js +25 -10
  194. package/dist/src/core/engine-session-lock.d.ts +47 -21
  195. package/dist/src/core/engine-session-lock.js +168 -33
  196. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  197. package/dist/src/core/export-moved-code-shape.js +10 -10
  198. package/dist/src/core/file-lock.d.ts +62 -5
  199. package/dist/src/core/file-lock.js +196 -59
  200. package/dist/src/core/firefox-cache.js +1 -3
  201. package/dist/src/core/firefox-extract.js +10 -14
  202. package/dist/src/core/firefox.d.ts +7 -5
  203. package/dist/src/core/firefox.js +4 -5
  204. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  205. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  206. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  207. package/dist/src/core/furnace-apply-ftl.js +16 -13
  208. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  209. package/dist/src/core/furnace-apply-helpers.js +30 -21
  210. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  211. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  212. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  213. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  214. package/dist/src/core/furnace-apply.d.ts +5 -8
  215. package/dist/src/core/furnace-apply.js +19 -24
  216. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  217. package/dist/src/core/furnace-checksum-utils.js +16 -0
  218. package/dist/src/core/furnace-config.d.ts +21 -30
  219. package/dist/src/core/furnace-config.js +32 -54
  220. package/dist/src/core/furnace-constants.d.ts +8 -0
  221. package/dist/src/core/furnace-constants.js +10 -2
  222. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  223. package/dist/src/core/furnace-css-fragments.js +5 -5
  224. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  225. package/dist/src/core/furnace-jsconfig.js +11 -12
  226. package/dist/src/core/furnace-marker.d.ts +7 -8
  227. package/dist/src/core/furnace-marker.js +7 -8
  228. package/dist/src/core/furnace-operation.d.ts +31 -0
  229. package/dist/src/core/furnace-operation.js +54 -17
  230. package/dist/src/core/furnace-precondition.d.ts +61 -0
  231. package/dist/src/core/furnace-precondition.js +67 -0
  232. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  233. package/dist/src/core/furnace-registration-remove.js +6 -7
  234. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  235. package/dist/src/core/furnace-registration-validate.js +20 -1
  236. package/dist/src/core/furnace-registration.d.ts +5 -6
  237. package/dist/src/core/furnace-registration.js +10 -12
  238. package/dist/src/core/furnace-rollback.js +7 -7
  239. package/dist/src/core/furnace-scanner.d.ts +1 -0
  240. package/dist/src/core/furnace-scanner.js +1 -2
  241. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  242. package/dist/src/core/furnace-stale-export.js +10 -10
  243. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  244. package/dist/src/core/furnace-state-persist.js +6 -8
  245. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  246. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  247. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  248. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  249. package/dist/src/core/furnace-validate-helpers.js +0 -491
  250. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  251. package/dist/src/core/furnace-validate-registration.js +115 -41
  252. package/dist/src/core/furnace-validate.d.ts +16 -0
  253. package/dist/src/core/furnace-validate.js +188 -145
  254. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  255. package/dist/src/core/furnace-version-drift.js +10 -11
  256. package/dist/src/core/git-base.d.ts +21 -9
  257. package/dist/src/core/git-base.js +24 -9
  258. package/dist/src/core/git-diff.d.ts +20 -9
  259. package/dist/src/core/git-diff.js +148 -63
  260. package/dist/src/core/git-file-ops.d.ts +19 -19
  261. package/dist/src/core/git-file-ops.js +19 -19
  262. package/dist/src/core/git-readonly-index.d.ts +53 -19
  263. package/dist/src/core/git-readonly-index.js +75 -31
  264. package/dist/src/core/git-status.d.ts +5 -6
  265. package/dist/src/core/git-status.js +5 -6
  266. package/dist/src/core/git.d.ts +9 -10
  267. package/dist/src/core/git.js +57 -71
  268. package/dist/src/core/license-headers.d.ts +17 -23
  269. package/dist/src/core/license-headers.js +17 -23
  270. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  271. package/dist/src/core/mach-build-artifacts.js +57 -19
  272. package/dist/src/core/mach-error-hints.js +42 -29
  273. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  274. package/dist/src/core/mach-known-noise-filter.js +18 -20
  275. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  276. package/dist/src/core/mach-mozconfig.js +30 -0
  277. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  278. package/dist/src/core/mach-resource-shim.js +50 -67
  279. package/dist/src/core/mach.d.ts +37 -41
  280. package/dist/src/core/mach.js +50 -51
  281. package/dist/src/core/marionette-port.d.ts +36 -1
  282. package/dist/src/core/marionette-port.js +96 -31
  283. package/dist/src/core/marionette-preflight.d.ts +8 -12
  284. package/dist/src/core/marionette-preflight.js +86 -52
  285. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  286. package/dist/src/core/mochitest-server-port.js +119 -0
  287. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  288. package/dist/src/core/module-resolution-preflight.js +9 -11
  289. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  290. package/dist/src/core/moz-manifest-helpers.js +163 -0
  291. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  292. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  293. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  294. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  295. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  296. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  297. package/dist/src/core/ownership-table.d.ts +14 -16
  298. package/dist/src/core/ownership-table.js +14 -16
  299. package/dist/src/core/parser-fallback.d.ts +15 -1
  300. package/dist/src/core/parser-fallback.js +22 -3
  301. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  302. package/dist/src/core/patch-apply-fuzz.js +15 -18
  303. package/dist/src/core/patch-apply.d.ts +13 -34
  304. package/dist/src/core/patch-apply.js +16 -76
  305. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  306. package/dist/src/core/patch-artifact-normalize.js +13 -15
  307. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  308. package/dist/src/core/patch-export-metadata.js +13 -4
  309. package/dist/src/core/patch-export-update.d.ts +13 -1
  310. package/dist/src/core/patch-export-update.js +25 -8
  311. package/dist/src/core/patch-export.d.ts +15 -8
  312. package/dist/src/core/patch-export.js +10 -11
  313. package/dist/src/core/patch-files.d.ts +5 -6
  314. package/dist/src/core/patch-files.js +5 -6
  315. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  316. package/dist/src/core/patch-identifier-suggest.js +14 -19
  317. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  318. package/dist/src/core/patch-lint-binary.js +39 -0
  319. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  320. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  321. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  322. package/dist/src/core/patch-lint-checkjs.js +41 -20
  323. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  324. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  325. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  326. package/dist/src/core/patch-lint-creators.js +8 -8
  327. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  328. package/dist/src/core/patch-lint-cross.js +16 -16
  329. package/dist/src/core/patch-lint-css.d.ts +3 -5
  330. package/dist/src/core/patch-lint-css.js +17 -22
  331. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  332. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  333. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  334. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  335. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  336. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  337. package/dist/src/core/patch-lint-observer.js +7 -7
  338. package/dist/src/core/patch-lint.d.ts +38 -29
  339. package/dist/src/core/patch-lint.js +89 -121
  340. package/dist/src/core/patch-lock.d.ts +1 -1
  341. package/dist/src/core/patch-lock.js +45 -9
  342. package/dist/src/core/patch-manifest-consistency.d.ts +57 -6
  343. package/dist/src/core/patch-manifest-consistency.js +111 -40
  344. package/dist/src/core/patch-manifest-files-affected.d.ts +43 -0
  345. package/dist/src/core/patch-manifest-files-affected.js +77 -0
  346. package/dist/src/core/patch-manifest-io.js +14 -18
  347. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  348. package/dist/src/core/patch-manifest-resolve.js +9 -12
  349. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  350. package/dist/src/core/patch-manifest-validate.js +25 -13
  351. package/dist/src/core/patch-manifest.d.ts +2 -1
  352. package/dist/src/core/patch-manifest.js +2 -1
  353. package/dist/src/core/patch-parse.d.ts +24 -13
  354. package/dist/src/core/patch-parse.js +19 -14
  355. package/dist/src/core/patch-policy.d.ts +2 -2
  356. package/dist/src/core/patch-policy.js +2 -2
  357. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  358. package/dist/src/core/patch-registration-refs.js +9 -9
  359. package/dist/src/core/process-cpu-time.d.ts +12 -0
  360. package/dist/src/core/process-cpu-time.js +52 -0
  361. package/dist/src/core/rebase-session.d.ts +38 -26
  362. package/dist/src/core/rebase-session.js +55 -28
  363. package/dist/src/core/register-browser-content.js +9 -74
  364. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  365. package/dist/src/core/register-module.js +10 -43
  366. package/dist/src/core/register-scaffold.d.ts +8 -8
  367. package/dist/src/core/register-scaffold.js +10 -10
  368. package/dist/src/core/register-shared-css.d.ts +9 -12
  369. package/dist/src/core/register-shared-css.js +17 -87
  370. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  371. package/dist/src/core/register-xpcshell-test.js +7 -8
  372. package/dist/src/core/shared-ftl.js +12 -4
  373. package/dist/src/core/state-file.d.ts +45 -0
  374. package/dist/src/core/state-file.js +34 -0
  375. package/dist/src/core/status-binary.d.ts +18 -11
  376. package/dist/src/core/status-binary.js +19 -12
  377. package/dist/src/core/status-classify.d.ts +30 -36
  378. package/dist/src/core/status-classify.js +21 -26
  379. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  380. package/dist/src/core/test-changed-prefs.js +78 -0
  381. package/dist/src/core/test-harness-crash.d.ts +25 -63
  382. package/dist/src/core/test-harness-crash.js +121 -142
  383. package/dist/src/core/test-harness-signature.d.ts +18 -0
  384. package/dist/src/core/test-harness-signature.js +13 -0
  385. package/dist/src/core/test-path-scope.d.ts +12 -15
  386. package/dist/src/core/test-path-scope.js +15 -18
  387. package/dist/src/core/test-stale-check.d.ts +17 -17
  388. package/dist/src/core/test-stale-check.js +50 -43
  389. package/dist/src/core/test-stall-triage.d.ts +51 -0
  390. package/dist/src/core/test-stall-triage.js +126 -0
  391. package/dist/src/core/token-category.js +66 -14
  392. package/dist/src/core/token-coverage.js +9 -9
  393. package/dist/src/core/token-dark-mode.d.ts +9 -11
  394. package/dist/src/core/token-dark-mode.js +29 -13
  395. package/dist/src/core/token-docs.d.ts +2 -0
  396. package/dist/src/core/token-docs.js +3 -1
  397. package/dist/src/core/token-manager.d.ts +10 -2
  398. package/dist/src/core/token-manager.js +17 -8
  399. package/dist/src/core/token-scaffold.d.ts +7 -7
  400. package/dist/src/core/token-scaffold.js +7 -7
  401. package/dist/src/core/token-variant.d.ts +4 -4
  402. package/dist/src/core/token-variant.js +28 -6
  403. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  404. package/dist/src/core/toolchain-preflight.js +28 -31
  405. package/dist/src/core/tree-guard.js +12 -2
  406. package/dist/src/core/tree-store.d.ts +41 -27
  407. package/dist/src/core/tree-store.js +68 -43
  408. package/dist/src/core/typecheck-shim.d.ts +23 -24
  409. package/dist/src/core/typecheck-shim.js +23 -24
  410. package/dist/src/core/typecheck.js +15 -9
  411. package/dist/src/core/wire-destroy.d.ts +3 -3
  412. package/dist/src/core/wire-destroy.js +7 -15
  413. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  414. package/dist/src/core/wire-dom-fragment.js +11 -44
  415. package/dist/src/core/wire-init.d.ts +2 -3
  416. package/dist/src/core/wire-init.js +8 -19
  417. package/dist/src/core/wire-subscript.d.ts +2 -3
  418. package/dist/src/core/wire-subscript.js +4 -13
  419. package/dist/src/core/wire-utils.d.ts +7 -8
  420. package/dist/src/core/wire-utils.js +7 -8
  421. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  422. package/dist/src/core/xpcshell-appdir.js +38 -45
  423. package/dist/src/errors/base.d.ts +37 -16
  424. package/dist/src/errors/base.js +37 -16
  425. package/dist/src/errors/build.d.ts +13 -1
  426. package/dist/src/errors/build.js +14 -2
  427. package/dist/src/errors/codes.d.ts +16 -0
  428. package/dist/src/errors/codes.js +16 -0
  429. package/dist/src/errors/furnace.d.ts +4 -4
  430. package/dist/src/errors/git.d.ts +6 -10
  431. package/dist/src/errors/git.js +6 -10
  432. package/dist/src/errors/patch.d.ts +7 -7
  433. package/dist/src/errors/patch.js +7 -7
  434. package/dist/src/errors/rebase.d.ts +4 -4
  435. package/dist/src/errors/rebase.js +4 -4
  436. package/dist/src/index.d.ts +7 -1
  437. package/dist/src/index.js +5 -0
  438. package/dist/src/types/commands/index.d.ts +2 -2
  439. package/dist/src/types/commands/options.d.ts +111 -70
  440. package/dist/src/types/commands/patches.d.ts +24 -34
  441. package/dist/src/types/commands/project.d.ts +5 -34
  442. package/dist/src/types/config.d.ts +25 -23
  443. package/dist/src/types/config.js +6 -1
  444. package/dist/src/types/furnace.d.ts +37 -13
  445. package/dist/src/types/furnace.js +19 -1
  446. package/dist/src/types/index.d.ts +3 -3
  447. package/dist/src/utils/build-info.d.ts +7 -8
  448. package/dist/src/utils/build-info.js +12 -11
  449. package/dist/src/utils/errors.d.ts +6 -8
  450. package/dist/src/utils/errors.js +6 -8
  451. package/dist/src/utils/logger.d.ts +27 -10
  452. package/dist/src/utils/logger.js +28 -16
  453. package/dist/src/utils/machine-output.d.ts +12 -0
  454. package/dist/src/utils/machine-output.js +33 -0
  455. package/dist/src/utils/options.d.ts +31 -14
  456. package/dist/src/utils/options.js +86 -30
  457. package/dist/src/utils/paths.d.ts +10 -8
  458. package/dist/src/utils/paths.js +10 -8
  459. package/dist/src/utils/platform.d.ts +0 -25
  460. package/dist/src/utils/platform.js +1 -42
  461. package/dist/src/utils/process-group.d.ts +9 -4
  462. package/dist/src/utils/process-group.js +19 -5
  463. package/dist/src/utils/process.d.ts +42 -7
  464. package/dist/src/utils/process.js +44 -17
  465. package/dist/src/utils/ps-duration.d.ts +31 -0
  466. package/dist/src/utils/ps-duration.js +70 -0
  467. package/dist/src/utils/regex.d.ts +9 -10
  468. package/dist/src/utils/regex.js +9 -10
  469. package/dist/src/utils/validation.d.ts +58 -28
  470. package/dist/src/utils/validation.js +60 -33
  471. package/package.json +3 -3
  472. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  473. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  474. package/dist/src/core/manifest-helpers.d.ts +0 -38
  475. package/dist/src/core/manifest-helpers.js +0 -120
  476. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  477. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  478. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -1,9 +1,18 @@
1
1
  /**
2
2
  * Filters an object to only include keys whose values are not undefined.
3
3
  * Designed for use with exactOptionalPropertyTypes — the result can be
4
- * spread into typed option objects without assigning undefined to optional properties.
4
+ * spread into typed option objects without assigning undefined to optional
5
+ * properties.
6
+ *
7
+ * Constrained to `object`, not `Record<string, unknown>`: a named interface
8
+ * has no index signature, so the narrower constraint rejects exactly the
9
+ * annotations this helper is most useful with. Nothing in the body needs the
10
+ * index signature — the key walk goes through `Object.keys`.
11
+ *
12
+ * @param obj - Object to filter
13
+ * @returns The same object with every `undefined`-valued key removed
5
14
  */
6
- export declare function pickDefined<T extends Record<string, unknown>>(obj: T): {
15
+ export declare function pickDefined<T extends object>(obj: T): {
7
16
  [K in keyof T]+?: Exclude<T[K], undefined>;
8
17
  };
9
18
  import type { Command } from 'commander';
@@ -15,11 +24,10 @@ import type { Command } from 'commander';
15
24
  * as argument-validation failures; anything else re-throws out of
16
25
  * `parseAsync`, BYPASSING `withErrorHandling` entirely and landing in the
17
26
  * bin's `main().catch` as an unformatted `Fatal error: …` dump with exit 1.
18
- * That was the observed behavior for `run --smoke-exit abc` (plain Error),
19
- * `test --harness-retries 99` (GeneralError), and `export --order 0`
20
- * (FireForge InvalidArgumentError, whose `code` is a numeric ExitCode).
21
- * Every `.argParser()`/option-parser callback must be wrapped with this
22
- * helper (or throw commander's InvalidArgumentError directly).
27
+ * That covers a plain Error, a `GeneralError`, and even a FireForge
28
+ * `InvalidArgumentError`, whose `code` is a numeric ExitCode. Every
29
+ * `.argParser()`/option-parser callback must be wrapped with this helper (or
30
+ * throw commander's InvalidArgumentError directly).
23
31
  */
24
32
  export declare function commanderArgParser<T>(parse: (raw: string) => T): (raw: string) => T;
25
33
  /**
@@ -30,23 +38,32 @@ export declare function commanderArgParser<T>(parse: (raw: string) => T): (raw:
30
38
  * .option('--mach-arg <arg>', 'Repeatable.', ...stringListOption())
31
39
  * ```
32
40
  *
33
- * Seven call sites open-coded this, each with its own `[] as string[]`
34
- * default — commander types that slot as `unknown`, so every one carried the
35
- * cast. Two of the seven also mutated the accumulator in place rather than
36
- * returning a new array. Returning a fresh array per call additionally means
37
- * the default cannot be shared between two `.option()` registrations.
41
+ * Commander types the default slot as `unknown`, so every open-coded copy
42
+ * carries an `[] as string[]` cast, and it is easy to mutate the accumulator
43
+ * in place instead of returning a new array. Returning a fresh array per
44
+ * call also means the default cannot be shared between two `.option()`
45
+ * registrations.
38
46
  */
39
47
  export declare function stringListOption(): [(value: string, previous: string[]) => string[], string[]];
48
+ /** Environment variable naming a standing wait budget for the whole session. */
49
+ export declare const WAIT_LOCK_ENV_VAR = "FIREFORGE_WAIT_LOCK";
40
50
  /**
41
51
  * Resolves the parsed `--wait-lock [seconds]` option value into a wait budget
42
52
  * in seconds for `withEngineSessionLock`:
43
- * - absent (`undefined`) → `undefined` (legacy ~1 s fail-fast),
53
+ * - absent (`undefined`) → {@link WAIT_LOCK_ENV_VAR} if set, else `undefined`
54
+ * (the ~1 s fail-fast),
44
55
  * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
45
56
  * - explicit value → integer validated into 1..3600.
46
57
  *
58
+ * The flag always wins over the environment: the environment expresses a
59
+ * default for a session, and an invocation that names a budget has said
60
+ * something more specific than the session did.
61
+ *
47
62
  * Accepts the raw string too, so it doubles as the option's arg parser (wrap
48
63
  * with {@link commanderArgParser} so failures surface through commander's
49
- * invalid-argument channel).
64
+ * invalid-argument channel). In that role the value is never `undefined`, so
65
+ * the environment fallback cannot leak into flag PARSING — only into flag
66
+ * ABSENCE, which is where it belongs.
50
67
  */
51
68
  export declare function resolveWaitLockSeconds(value: string | number | boolean | undefined): number | undefined;
52
69
  /**
@@ -2,19 +2,28 @@
2
2
  /**
3
3
  * Filters an object to only include keys whose values are not undefined.
4
4
  * Designed for use with exactOptionalPropertyTypes — the result can be
5
- * spread into typed option objects without assigning undefined to optional properties.
5
+ * spread into typed option objects without assigning undefined to optional
6
+ * properties.
7
+ *
8
+ * Constrained to `object`, not `Record<string, unknown>`: a named interface
9
+ * has no index signature, so the narrower constraint rejects exactly the
10
+ * annotations this helper is most useful with. Nothing in the body needs the
11
+ * index signature — the key walk goes through `Object.keys`.
12
+ *
13
+ * @param obj - Object to filter
14
+ * @returns The same object with every `undefined`-valued key removed
6
15
  */
7
16
  export function pickDefined(obj) {
8
17
  const result = {};
9
- for (const key of Object.keys(obj)) {
10
- if (obj[key] !== undefined) {
11
- result[key] = obj[key];
18
+ for (const [key, value] of Object.entries(obj)) {
19
+ if (value !== undefined) {
20
+ result[key] = value;
12
21
  }
13
22
  }
14
23
  return result;
15
24
  }
16
25
  import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
17
- import { GeneralError } from '../errors/base.js';
26
+ import { GeneralError, InvalidArgumentError } from '../errors/base.js';
18
27
  import { toError } from './errors.js';
19
28
  /**
20
29
  * Wraps an option-argument parser so its failures surface through
@@ -24,11 +33,10 @@ import { toError } from './errors.js';
24
33
  * as argument-validation failures; anything else re-throws out of
25
34
  * `parseAsync`, BYPASSING `withErrorHandling` entirely and landing in the
26
35
  * bin's `main().catch` as an unformatted `Fatal error: …` dump with exit 1.
27
- * That was the observed behavior for `run --smoke-exit abc` (plain Error),
28
- * `test --harness-retries 99` (GeneralError), and `export --order 0`
29
- * (FireForge InvalidArgumentError, whose `code` is a numeric ExitCode).
30
- * Every `.argParser()`/option-parser callback must be wrapped with this
31
- * helper (or throw commander's InvalidArgumentError directly).
36
+ * That covers a plain Error, a `GeneralError`, and even a FireForge
37
+ * `InvalidArgumentError`, whose `code` is a numeric ExitCode. Every
38
+ * `.argParser()`/option-parser callback must be wrapped with this helper (or
39
+ * throw commander's InvalidArgumentError directly).
32
40
  */
33
41
  export function commanderArgParser(parse) {
34
42
  return (raw) => {
@@ -48,31 +56,81 @@ export function commanderArgParser(parse) {
48
56
  * .option('--mach-arg <arg>', 'Repeatable.', ...stringListOption())
49
57
  * ```
50
58
  *
51
- * Seven call sites open-coded this, each with its own `[] as string[]`
52
- * default — commander types that slot as `unknown`, so every one carried the
53
- * cast. Two of the seven also mutated the accumulator in place rather than
54
- * returning a new array. Returning a fresh array per call additionally means
55
- * the default cannot be shared between two `.option()` registrations.
59
+ * Commander types the default slot as `unknown`, so every open-coded copy
60
+ * carries an `[] as string[]` cast, and it is easy to mutate the accumulator
61
+ * in place instead of returning a new array. Returning a fresh array per
62
+ * call also means the default cannot be shared between two `.option()`
63
+ * registrations.
56
64
  */
57
65
  export function stringListOption() {
58
66
  return [(value, previous) => [...previous, value], []];
59
67
  }
60
68
  /** Wait budget applied when `--wait-lock` is passed without a value. */
61
69
  const DEFAULT_WAIT_LOCK_SECONDS = 60;
70
+ /** Environment variable naming a standing wait budget for the whole session. */
71
+ export const WAIT_LOCK_ENV_VAR = 'FIREFORGE_WAIT_LOCK';
72
+ /** Bounds shared by the flag and the environment variable. */
73
+ const MIN_WAIT_LOCK_SECONDS = 1;
74
+ const MAX_WAIT_LOCK_SECONDS = 3600;
75
+ /**
76
+ * Parses a wait budget from text, or undefined when it is not an integer in
77
+ * range. Shared by the flag and {@link WAIT_LOCK_ENV_VAR} so the two cannot
78
+ * drift on what they accept.
79
+ */
80
+ function parseWaitLockSeconds(raw) {
81
+ const n = Number.parseInt(raw, 10);
82
+ if (!Number.isFinite(n) || n < MIN_WAIT_LOCK_SECONDS || n > MAX_WAIT_LOCK_SECONDS) {
83
+ return undefined;
84
+ }
85
+ return n;
86
+ }
87
+ /**
88
+ * The standing wait budget from {@link WAIT_LOCK_ENV_VAR}, or undefined when
89
+ * it is unset or empty.
90
+ *
91
+ * Exists because a wait budget is a property of the SESSION, not of the
92
+ * invocation: a checkout worked by several concurrent agent sessions has a
93
+ * held lock as its normal state, and an unattended loop would otherwise have
94
+ * to thread `--wait-lock` through every command it issues — the one place
95
+ * it is easiest to forget, and the failure only shows up once the loop has
96
+ * already produced a tail of refusals.
97
+ *
98
+ * An unusable value is a usage error rather than a silent fall-back to
99
+ * fail-fast: the operator set it precisely because they did not want to
100
+ * discover the budget at refusal time.
101
+ */
102
+ function waitLockSecondsFromEnv() {
103
+ const raw = process.env[WAIT_LOCK_ENV_VAR]?.trim();
104
+ if (raw === undefined || raw.length === 0) {
105
+ return undefined;
106
+ }
107
+ const parsed = parseWaitLockSeconds(raw);
108
+ if (parsed === undefined) {
109
+ throw new InvalidArgumentError(`${WAIT_LOCK_ENV_VAR} must be an integer in ${String(MIN_WAIT_LOCK_SECONDS)}..${String(MAX_WAIT_LOCK_SECONDS)} (got "${raw}")`, WAIT_LOCK_ENV_VAR);
110
+ }
111
+ return parsed;
112
+ }
62
113
  /**
63
114
  * Resolves the parsed `--wait-lock [seconds]` option value into a wait budget
64
115
  * in seconds for `withEngineSessionLock`:
65
- * - absent (`undefined`) → `undefined` (legacy ~1 s fail-fast),
116
+ * - absent (`undefined`) → {@link WAIT_LOCK_ENV_VAR} if set, else `undefined`
117
+ * (the ~1 s fail-fast),
66
118
  * - bare flag (`true`) → {@link DEFAULT_WAIT_LOCK_SECONDS},
67
119
  * - explicit value → integer validated into 1..3600.
68
120
  *
121
+ * The flag always wins over the environment: the environment expresses a
122
+ * default for a session, and an invocation that names a budget has said
123
+ * something more specific than the session did.
124
+ *
69
125
  * Accepts the raw string too, so it doubles as the option's arg parser (wrap
70
126
  * with {@link commanderArgParser} so failures surface through commander's
71
- * invalid-argument channel).
127
+ * invalid-argument channel). In that role the value is never `undefined`, so
128
+ * the environment fallback cannot leak into flag PARSING — only into flag
129
+ * ABSENCE, which is where it belongs.
72
130
  */
73
131
  export function resolveWaitLockSeconds(value) {
74
132
  if (value === undefined || value === false) {
75
- return undefined;
133
+ return waitLockSecondsFromEnv();
76
134
  }
77
135
  if (value === true) {
78
136
  return DEFAULT_WAIT_LOCK_SECONDS;
@@ -80,23 +138,21 @@ export function resolveWaitLockSeconds(value) {
80
138
  if (typeof value === 'number') {
81
139
  return value;
82
140
  }
83
- const n = Number.parseInt(value, 10);
84
- if (!Number.isFinite(n) || n < 1 || n > 3600) {
85
- throw new GeneralError(`--wait-lock must be an integer in 1..3600 (got "${value}")`);
141
+ const parsed = parseWaitLockSeconds(value);
142
+ if (parsed === undefined) {
143
+ throw new GeneralError(`--wait-lock must be an integer in ${String(MIN_WAIT_LOCK_SECONDS)}..${String(MAX_WAIT_LOCK_SECONDS)} (got "${value}")`);
86
144
  }
87
- return n;
145
+ return parsed;
88
146
  }
89
147
  /**
90
148
  * Registers `--wait-lock [seconds]` on a command that takes NO lock, so a
91
149
  * scripted sequence can blanket-append the flag without hitting a usage
92
- * error.
150
+ * error — a command that rejects it with "unknown option" kills the whole
151
+ * sequence with a usage error instead of a lock message.
93
152
  *
94
- * `export` / `re-export` / `build` / `test` / `patch move-files` all
95
- * accept the flag; `status` and `patch staged-dependency` used to reject
96
- * it with "unknown option", which killed the whole sequence with a usage
97
- * error instead of a lock message. The flag is accepted and ignored here —
98
- * never silently repurposed — and the help text says so, so nobody reads
99
- * its presence as evidence that this command waits for anything.
153
+ * The flag is accepted and ignored here — never silently repurposed — and
154
+ * the help text says so, so nobody reads its presence as evidence that this
155
+ * command waits for anything.
100
156
  *
101
157
  * The value is parsed and validated exactly as the honoring variant does:
102
158
  * `--wait-lock nonsense` must still be a usage error everywhere, or the
@@ -134,5 +190,5 @@ export function ensureWaitLockOptionEverywhere(command) {
134
190
  * `waitLockSeconds` for `withEngineSessionLock`/`withPatchDirectoryLock`.
135
191
  */
136
192
  export function addWaitLockOption(command) {
137
- return command.option('--wait-lock [seconds]', 'Wait up to this many seconds (default 60) for another FireForge command to release the contended lock, instead of failing on the default budget', commanderArgParser((raw) => resolveWaitLockSeconds(raw)));
193
+ return command.option('--wait-lock [seconds]', `Wait up to this many seconds (default 60) for another FireForge command to release the contended lock, instead of failing on the default budget. Set ${WAIT_LOCK_ENV_VAR} to apply a budget to every command in a session`, commanderArgParser((raw) => resolveWaitLockSeconds(raw)));
138
194
  }
@@ -4,15 +4,17 @@ export declare function normalizePathSlashes(path: string): string;
4
4
  * Strips a leading `engine/` (or `engine\\`) segment from a user-supplied
5
5
  * path so the same command invocation accepts both repo-root-relative paths
6
6
  * (`engine/browser/base/content/foo.js`) and engine-relative paths
7
- * (`browser/base/content/foo.js`). The match is case-insensitive because
8
- * default macOS and Windows filesystems treat `Engine/` and `engine/` as
9
- * the same directory; a literal lowercase-only check previously left `mach`
10
- * / the manifest writers resolving against a wrongly-cased prefix. Leading
11
- * whitespace is ignored so tab-completed inputs don't slip past the strip.
7
+ * (`browser/base/content/foo.js`).
12
8
  *
13
- * The return value is trimmed of the same leading whitespace when the
14
- * prefix matched, and otherwise passed through verbatim — callers that
15
- * care about internal whitespace can trim on their side.
9
+ * The match is case-insensitive because default macOS and Windows
10
+ * filesystems treat `Engine/` and `engine/` as the same directory; a literal
11
+ * lowercase-only check leaves `mach` and the manifest writers resolving
12
+ * against a wrongly-cased prefix. Leading whitespace is ignored so
13
+ * tab-completed inputs do not slip past the strip.
14
+ *
15
+ * The return value is trimmed of that leading whitespace when the prefix
16
+ * matched, and otherwise passed through verbatim — callers that care about
17
+ * internal whitespace can trim on their side.
16
18
  *
17
19
  * @param filePath Path as provided by the user
18
20
  * @returns Path relative to the engine directory (or the original when the
@@ -18,15 +18,17 @@ export function normalizePathSlashes(path) {
18
18
  * Strips a leading `engine/` (or `engine\\`) segment from a user-supplied
19
19
  * path so the same command invocation accepts both repo-root-relative paths
20
20
  * (`engine/browser/base/content/foo.js`) and engine-relative paths
21
- * (`browser/base/content/foo.js`). The match is case-insensitive because
22
- * default macOS and Windows filesystems treat `Engine/` and `engine/` as
23
- * the same directory; a literal lowercase-only check previously left `mach`
24
- * / the manifest writers resolving against a wrongly-cased prefix. Leading
25
- * whitespace is ignored so tab-completed inputs don't slip past the strip.
21
+ * (`browser/base/content/foo.js`).
26
22
  *
27
- * The return value is trimmed of the same leading whitespace when the
28
- * prefix matched, and otherwise passed through verbatim — callers that
29
- * care about internal whitespace can trim on their side.
23
+ * The match is case-insensitive because default macOS and Windows
24
+ * filesystems treat `Engine/` and `engine/` as the same directory; a literal
25
+ * lowercase-only check leaves `mach` and the manifest writers resolving
26
+ * against a wrongly-cased prefix. Leading whitespace is ignored so
27
+ * tab-completed inputs do not slip past the strip.
28
+ *
29
+ * The return value is trimmed of that leading whitespace when the prefix
30
+ * matched, and otherwise passed through verbatim — callers that care about
31
+ * internal whitespace can trim on their side.
30
32
  *
31
33
  * @param filePath Path as provided by the user
32
34
  * @returns Path relative to the engine directory (or the original when the
@@ -11,28 +11,3 @@ export type Arch = 'x64' | 'arm64';
11
11
  * @throws Error if running on an unsupported platform
12
12
  */
13
13
  export declare function getPlatform(): Platform;
14
- /**
15
- * Gets the current CPU architecture.
16
- * @throws Error if running on an unsupported architecture
17
- */
18
- export declare function getArch(): Arch;
19
- /**
20
- * Gets the mozconfig filename for the current platform.
21
- */
22
- export declare function getMozconfigName(): string;
23
- /**
24
- * Checks if the current platform is macOS.
25
- */
26
- export declare function isDarwin(): boolean;
27
- /**
28
- * Checks if the current platform is Linux.
29
- */
30
- export declare function isLinux(): boolean;
31
- /**
32
- * Checks if the current platform is Windows.
33
- */
34
- export declare function isWindows(): boolean;
35
- /**
36
- * Gets the appropriate file extension for executables on the current platform.
37
- */
38
- export declare function getExecutableExtension(): string;
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { arch, platform } from 'node:os';
2
+ import { platform } from 'node:os';
3
3
  import { GeneralError } from '../errors/base.js';
4
4
  /**
5
5
  * Gets the current operating system platform.
@@ -12,44 +12,3 @@ export function getPlatform() {
12
12
  }
13
13
  throw new GeneralError(`Unsupported platform: ${p}. FireForge supports darwin, linux, and win32.`);
14
14
  }
15
- /**
16
- * Gets the current CPU architecture.
17
- * @throws Error if running on an unsupported architecture
18
- */
19
- export function getArch() {
20
- const a = arch();
21
- if (a === 'x64' || a === 'arm64') {
22
- return a;
23
- }
24
- throw new GeneralError(`Unsupported architecture: ${a}. FireForge supports x64 and arm64.`);
25
- }
26
- /**
27
- * Gets the mozconfig filename for the current platform.
28
- */
29
- export function getMozconfigName() {
30
- return `${getPlatform()}.mozconfig`;
31
- }
32
- /**
33
- * Checks if the current platform is macOS.
34
- */
35
- export function isDarwin() {
36
- return platform() === 'darwin';
37
- }
38
- /**
39
- * Checks if the current platform is Linux.
40
- */
41
- export function isLinux() {
42
- return platform() === 'linux';
43
- }
44
- /**
45
- * Checks if the current platform is Windows.
46
- */
47
- export function isWindows() {
48
- return platform() === 'win32';
49
- }
50
- /**
51
- * Gets the appropriate file extension for executables on the current platform.
52
- */
53
- export function getExecutableExtension() {
54
- return isWindows() ? '.exe' : '';
55
- }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Process-group kill and post-run sweep helpers for the exec layer
3
- * (0.37.0 item 9a). Split out of `process.ts` to keep that file within the
4
- * per-file line budget; deliberately spawn-based (not `exec`-based) so the
5
- * two modules do not import each other cyclically.
2
+ * Process-group kill and post-run sweep helpers for the exec layer. Split
3
+ * out of `process.ts` to keep that file within the per-file line budget;
4
+ * deliberately spawn-based (not `exec`-based) so the two modules do not
5
+ * import each other cyclically.
6
6
  */
7
7
  import { type ChildProcess } from 'node:child_process';
8
8
  /**
@@ -11,6 +11,11 @@ import { type ChildProcess } from 'node:child_process';
11
11
  * chains), or a `taskkill /T /F` tree kill plus a direct `child.kill`
12
12
  * fallback on Windows. No-ops once the direct child has exited (group
13
13
  * survivors after exit are the post-run sweep's job, not this function's).
14
+ *
15
+ * A failed group kill falls through to a direct `child.kill` on POSIX too:
16
+ * ESRCH/EPERM on the negative PID means the group is gone or was never
17
+ * created, and signalling the direct child is strictly better than
18
+ * returning silently.
14
19
  */
15
20
  export declare function killProcessTree(child: ChildProcess, signal: NodeJS.Signals, usesProcessGroup: boolean): void;
16
21
  /** One process still alive in a swept group. */
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Process-group kill and post-run sweep helpers for the exec layer
4
- * (0.37.0 item 9a). Split out of `process.ts` to keep that file within the
5
- * per-file line budget; deliberately spawn-based (not `exec`-based) so the
6
- * two modules do not import each other cyclically.
3
+ * Process-group kill and post-run sweep helpers for the exec layer. Split
4
+ * out of `process.ts` to keep that file within the per-file line budget;
5
+ * deliberately spawn-based (not `exec`-based) so the two modules do not
6
+ * import each other cyclically.
7
7
  */
8
8
  import { spawn } from 'node:child_process';
9
9
  import { getNodeErrorCode } from './errors.js';
@@ -14,6 +14,11 @@ import { verbose, warn } from './logger.js';
14
14
  * chains), or a `taskkill /T /F` tree kill plus a direct `child.kill`
15
15
  * fallback on Windows. No-ops once the direct child has exited (group
16
16
  * survivors after exit are the post-run sweep's job, not this function's).
17
+ *
18
+ * A failed group kill falls through to a direct `child.kill` on POSIX too:
19
+ * ESRCH/EPERM on the negative PID means the group is gone or was never
20
+ * created, and signalling the direct child is strictly better than
21
+ * returning silently.
17
22
  */
18
23
  export function killProcessTree(child, signal, usesProcessGroup) {
19
24
  if (child.exitCode !== null || child.signalCode !== null)
@@ -26,7 +31,16 @@ export function killProcessTree(child, signal, usesProcessGroup) {
26
31
  // Negative PID routes to the process group, killing the Python
27
32
  // wrapper, the firefox it forked, and every content process
28
33
  // that inherited the group.
29
- process.kill(-targetPid, signal);
34
+ try {
35
+ process.kill(-targetPid, signal);
36
+ }
37
+ catch {
38
+ // ESRCH/EPERM: the group is gone, or was never created because the
39
+ // platform ignored `detached`. Signal the direct child rather than
40
+ // doing nothing — it may well still be alive. Without this
41
+ // fall-through a failed group kill left the child running.
42
+ child.kill(signal);
43
+ }
30
44
  }
31
45
  else {
32
46
  // No process group on Windows — taskkill /T walks the descendant
@@ -1,3 +1,4 @@
1
+ import { spawn } from 'node:child_process';
1
2
  /**
2
3
  * Result of executing a command.
3
4
  */
@@ -33,9 +34,8 @@ export interface ExecOptions {
33
34
  * POSIX: spawn the child as a process-group leader and route every kill
34
35
  * (parent-signal forwarding, abort, escalation) to the whole GROUP, then
35
36
  * sweep the group for survivors after close — so a harness that dies at
36
- * startup cannot strand spinning `multiprocessing` workers (field
37
- * incident: an orphaned Python spawn worker reparented to launchd and
38
- * busy-spun at 100% CPU for ~26 days). Win32: tree-kill via
37
+ * startup cannot strand spinning `multiprocessing` workers, which reparent
38
+ * to launchd and busy-spin at 100% CPU indefinitely. Win32: tree-kill via
39
39
  * `taskkill /T /F` on abort/signals only, no post-run sweep
40
40
  * (best-effort). Default false — non-mach consumers are unaffected.
41
41
  *
@@ -74,6 +74,27 @@ export interface StreamOptions extends ExecOptions {
74
74
  * @returns Exit code of the process
75
75
  */
76
76
  export declare function execStream(command: string, args: string[], options?: StreamOptions): Promise<number>;
77
+ /**
78
+ * Registers a child with {@link waitForActiveChildShutdown}.
79
+ *
80
+ * Exported for the one legitimate spawn outside this module:
81
+ * `core/marionette-preflight.ts` keeps its own `spawn` because it needs the
82
+ * live `ChildProcess` mid-run, returns while the child is still running, and
83
+ * aborts on a TCP byte rather than a deadline — none of which any wrapper
84
+ * here can express. It still needs the shutdown contract, and a second
85
+ * hand-rolled copy is what lets a Ctrl+C orphan the whole mach → Firefox
86
+ * tree.
87
+ */
88
+ /**
89
+ * Registers a child whose shutdown {@link waitForActiveChildShutdown} must
90
+ * wait for, and returns the handle that deregisters it.
91
+ *
92
+ * @returns `settle()` — call from both the child's `close` and `error`
93
+ * handlers so a dead child never holds the shutdown wait open
94
+ */
95
+ export declare function trackChildClosure(): {
96
+ settle: () => void;
97
+ };
77
98
  /**
78
99
  * Waits (bounded) for every tracked child process to close. Called by the
79
100
  * bin signal handler after forwarding SIGINT/SIGTERM, so the parent stays
@@ -100,6 +121,17 @@ export declare function waitForActiveChildShutdown(timeoutMs: number): Promise<v
100
121
  export declare function execInherit(command: string, args: string[], options?: ExecOptions & {
101
122
  shutdownGraceMs?: number;
102
123
  }): Promise<number>;
124
+ /**
125
+ * Wires parent-process SIGINT/SIGTERM to a child: first signal → child.kill
126
+ * (SIGTERM) + grace timer; second matching signal → immediate SIGKILL; grace
127
+ * timer expiry → SIGKILL. Returns a `dispose()` that clears the listeners and
128
+ * any outstanding timer. Callers must invoke `dispose()` from both the child's
129
+ * `close` and `error` handlers so the process does not accumulate signal
130
+ * listeners across repeated spawns.
131
+ */
132
+ export declare function installGracefulShutdownForwarder(child: ReturnType<typeof spawn>, graceMs: number, killTarget?: (signal: NodeJS.Signals) => void): {
133
+ dispose: () => void;
134
+ };
103
135
  /**
104
136
  * Executes a command while inheriting stdin, streaming stdout/stderr live,
105
137
  * and capturing the emitted output for diagnostics.
@@ -118,11 +150,14 @@ export type SmokeLineCallback = (line: string) => void;
118
150
  *
119
151
  * Deliberately omits `ExecOptions.timeout`: the smoke run's only deadline is
120
152
  * {@link SmokeRunOptions.smokeTimeoutMs}, which signals the whole process
121
- * group. Inheriting `timeout` used to be a leaky trap — it was accepted by
122
- * the type but silently ignored, so a caller setting it got no deadline at
123
- * all.
153
+ * group. Inheriting `timeout` is a leaky trap — accepted by the type but
154
+ * silently ignored, so a caller setting it gets no deadline at all.
155
+ *
156
+ * `processGroup` is omitted for the same reason: a smoke run is ALWAYS
157
+ * detached on POSIX (`usesProcessGroup` is derived from `process.platform`
158
+ * alone), so the field would be accepted and never read.
124
159
  */
125
- export interface SmokeRunOptions extends Omit<ExecOptions, 'timeout'> {
160
+ export interface SmokeRunOptions extends Omit<ExecOptions, 'processGroup' | 'timeout'> {
126
161
  /**
127
162
  * Hard deadline in milliseconds. When it elapses the child process
128
163
  * group is sent SIGTERM and, after `killGraceMs`, SIGKILL. The returned