@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
@@ -145,6 +145,12 @@ export async function execStream(command, args, options = {}) {
145
145
  killProcessTree(child, signal, usesProcessGroup);
146
146
  })
147
147
  : undefined;
148
+ // Closure tracking: this was the one wrapper that omitted it, so the bin
149
+ // signal handler did not wait for `runMachStream`'s children on Ctrl+C
150
+ // and the forwarder's SIGTERM → grace → SIGKILL escalation above could
151
+ // not finish before the parent exited — the exact failure the tracking
152
+ // set was introduced to fix, left unwired here.
153
+ const closure = trackChildClosure();
148
154
  child.on('error', (error) => {
149
155
  // Abort/startup failure: make sure a partially-started tree does not
150
156
  // outlive the dispatch (a mach dying at startup used to strand
@@ -153,11 +159,13 @@ export async function execStream(command, args, options = {}) {
153
159
  killProcessTree(child, 'SIGKILL', usesProcessGroup);
154
160
  }
155
161
  forwarder?.dispose();
162
+ closure.settle();
156
163
  reject(toExecRejection(error, command, args, options.timeout));
157
164
  });
158
165
  child.on('close', (code, signal) => {
159
166
  forwarder?.dispose();
160
167
  const finish = () => {
168
+ closure.settle();
161
169
  resolve(exitCodeFromClose(code, signal));
162
170
  };
163
171
  if (groupPid !== undefined) {
@@ -171,15 +179,33 @@ export async function execStream(command, args, options = {}) {
171
179
  }
172
180
  /**
173
181
  * Close-promises of children whose shutdown the CLI must wait for when a
174
- * termination signal arrives. The bin signal handler used to `process.exit`
175
- * within a microtask of the first Ctrl+C, which made `execInherit`'s
176
- * documented SIGTERM → grace → SIGKILL escalation unreachable: the parent
177
- * was gone before the 1500 ms grace timer could fire, so a hung Firefox
178
- * was orphaned forever instead of being SIGKILLed and a healthy one lost
179
- * its AsyncShutdown flush window.
182
+ * termination signal arrives. A bin signal handler that calls `process.exit`
183
+ * within a microtask of the first Ctrl+C makes `execInherit`'s documented
184
+ * SIGTERM → grace → SIGKILL escalation unreachable: the parent is gone
185
+ * before the 1500 ms grace timer can fire, so a hung Firefox is orphaned
186
+ * forever instead of being SIGKILLed and a healthy one loses its
187
+ * AsyncShutdown flush window.
180
188
  */
181
189
  const activeChildClosures = new Set();
182
- function trackChildClosure() {
190
+ /**
191
+ * Registers a child with {@link waitForActiveChildShutdown}.
192
+ *
193
+ * Exported for the one legitimate spawn outside this module:
194
+ * `core/marionette-preflight.ts` keeps its own `spawn` because it needs the
195
+ * live `ChildProcess` mid-run, returns while the child is still running, and
196
+ * aborts on a TCP byte rather than a deadline — none of which any wrapper
197
+ * here can express. It still needs the shutdown contract, and a second
198
+ * hand-rolled copy is what lets a Ctrl+C orphan the whole mach → Firefox
199
+ * tree.
200
+ */
201
+ /**
202
+ * Registers a child whose shutdown {@link waitForActiveChildShutdown} must
203
+ * wait for, and returns the handle that deregisters it.
204
+ *
205
+ * @returns `settle()` — call from both the child's `close` and `error`
206
+ * handlers so a dead child never holds the shutdown wait open
207
+ */
208
+ export function trackChildClosure() {
183
209
  let resolveClosed;
184
210
  const closed = new Promise((resolve) => {
185
211
  resolveClosed = resolve;
@@ -274,7 +300,7 @@ export async function execInherit(command, args, options = {}) {
274
300
  * `close` and `error` handlers so the process does not accumulate signal
275
301
  * listeners across repeated spawns.
276
302
  */
277
- function installGracefulShutdownForwarder(child, graceMs, killTarget) {
303
+ export function installGracefulShutdownForwarder(child, graceMs, killTarget) {
278
304
  let graceTimer;
279
305
  const forwarded = new Set();
280
306
  const sendKill = (signal) => {
@@ -508,6 +534,8 @@ export async function execSmokeRun(command, args, options) {
508
534
  stdout: out.getText(),
509
535
  stderr: err.getText(),
510
536
  exitCode: exitCodeFromClose(code, signal),
537
+ stdoutTruncated: out.wasTruncated(),
538
+ stderrTruncated: err.wasTruncated(),
511
539
  timedOut,
512
540
  });
513
541
  });
@@ -516,21 +544,20 @@ export async function execSmokeRun(command, args, options) {
516
544
  /**
517
545
  * Cap on the partial-line tail kept between chunks. A child emitting one
518
546
  * enormous line with no terminator (minified JS dumped to stderr, a raw
519
- * binary blob) previously grew the buffer without bound — the 50 MB cap
520
- * only guarded the collector, not these line buffers. When the tail
521
- * exceeds the cap it is dispatched as a synthetic (oversized) line so the
522
- * matchers still get to see its content, then the buffer resets.
547
+ * binary blob) would otherwise grow the buffer without bound — the 50 MB cap
548
+ * guards the collector, not these line buffers. When the tail exceeds the
549
+ * cap it is dispatched as a synthetic (oversized) line so the matchers still
550
+ * see its content, then the buffer resets.
523
551
  */
524
552
  const MAX_PARTIAL_LINE_SIZE = 1024 * 1024;
525
553
  /**
526
554
  * Drains complete lines from `buffer`, dispatching each to `cb`. Treats
527
555
  * `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
528
556
  * matters for progress-bar style output (mach, cargo) that repaints a line
529
- * with carriage returns and never sends a newline; before `\r` counted as a
530
- * terminator those updates accumulated indefinitely. A single trailing `\r`
531
- * is held back since it may be the first half of a `\r\n` pair split across
532
- * chunks. Returns the remaining partial line — callers keep accumulating
533
- * into it.
557
+ * with carriage returns and never sends a newline, which otherwise
558
+ * accumulates indefinitely. A single trailing `\r` is held back since it may
559
+ * be the first half of a `\r\n` pair split across chunks. Returns the
560
+ * remaining partial line — callers keep accumulating into it.
534
561
  */
535
562
  function dispatchCompleteLines(buffer, cb) {
536
563
  let searchFrom = 0;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Parser for the duration fields `ps` prints.
3
+ *
4
+ * Two different columns share one grammar, which is why this lives apart
5
+ * from either consumer: `time=` (accumulated CPU) and `etime=` (elapsed
6
+ * wall clock). Reading them with one parser is deliberate — a second
7
+ * hand-rolled copy is how the two would drift, and the darwin dialect is
8
+ * the half that is easy to get wrong.
9
+ *
10
+ * Dialects:
11
+ * - linux `[dd-]hh:mm:ss` (e.g. `26-03:14:12`, `03:14:12`)
12
+ * - darwin/BSD `mm:ss.cc`, whose minutes field accumulates without
13
+ * wrapping (e.g. `38412:07.55`)
14
+ *
15
+ * Returns `NaN` for anything else, so callers must treat an unrecognized
16
+ * shape as "unknown" rather than as zero — a browser reported as 0 seconds
17
+ * old would be exactly the wrong attribution.
18
+ */
19
+ /**
20
+ * Parses a `ps` duration field into whole seconds.
21
+ *
22
+ * @param value - Raw field text, e.g. `03:14:12` or `38412:07.55`
23
+ * @returns Seconds, or `NaN` when the shape is not recognized
24
+ */
25
+ export declare function parsePsDuration(value: string): number;
26
+ /**
27
+ * Renders a duration for an operator-facing line: `4s`, `3m12s`, `2h05m`.
28
+ * Returns `undefined` for `NaN`, so a caller can omit the clause entirely
29
+ * rather than print "unknown" noise.
30
+ */
31
+ export declare function formatPsDuration(seconds: number): string | undefined;
@@ -0,0 +1,70 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Parser for the duration fields `ps` prints.
4
+ *
5
+ * Two different columns share one grammar, which is why this lives apart
6
+ * from either consumer: `time=` (accumulated CPU) and `etime=` (elapsed
7
+ * wall clock). Reading them with one parser is deliberate — a second
8
+ * hand-rolled copy is how the two would drift, and the darwin dialect is
9
+ * the half that is easy to get wrong.
10
+ *
11
+ * Dialects:
12
+ * - linux `[dd-]hh:mm:ss` (e.g. `26-03:14:12`, `03:14:12`)
13
+ * - darwin/BSD `mm:ss.cc`, whose minutes field accumulates without
14
+ * wrapping (e.g. `38412:07.55`)
15
+ *
16
+ * Returns `NaN` for anything else, so callers must treat an unrecognized
17
+ * shape as "unknown" rather than as zero — a browser reported as 0 seconds
18
+ * old would be exactly the wrong attribution.
19
+ */
20
+ /**
21
+ * Parses a `ps` duration field into whole seconds.
22
+ *
23
+ * @param value - Raw field text, e.g. `03:14:12` or `38412:07.55`
24
+ * @returns Seconds, or `NaN` when the shape is not recognized
25
+ */
26
+ export function parsePsDuration(value) {
27
+ const trimmed = value.trim();
28
+ let days = 0;
29
+ let rest = trimmed;
30
+ const dayMatch = /^(\d+)-(.*)$/.exec(trimmed);
31
+ if (dayMatch) {
32
+ days = Number(dayMatch[1]);
33
+ rest = dayMatch[2] ?? '';
34
+ }
35
+ const parts = rest.split(':');
36
+ if (parts.length === 3) {
37
+ // hh:mm:ss (linux; seconds may not carry fractions but tolerate them)
38
+ const [h, m, s] = parts.map(Number);
39
+ if ([h, m, s].some((n) => Number.isNaN(n)))
40
+ return NaN;
41
+ return days * 86400 + (h ?? 0) * 3600 + (m ?? 0) * 60 + (s ?? 0);
42
+ }
43
+ if (parts.length === 2) {
44
+ // mm:ss.cc (darwin — the minutes field accumulates without wrapping)
45
+ const [m, s] = parts.map(Number);
46
+ if ([m, s].some((n) => Number.isNaN(n)))
47
+ return NaN;
48
+ return days * 86400 + (m ?? 0) * 60 + (s ?? 0);
49
+ }
50
+ return NaN;
51
+ }
52
+ /**
53
+ * Renders a duration for an operator-facing line: `4s`, `3m12s`, `2h05m`.
54
+ * Returns `undefined` for `NaN`, so a caller can omit the clause entirely
55
+ * rather than print "unknown" noise.
56
+ */
57
+ export function formatPsDuration(seconds) {
58
+ if (Number.isNaN(seconds) || seconds < 0)
59
+ return undefined;
60
+ if (seconds < 60)
61
+ return `${String(Math.floor(seconds))}s`;
62
+ if (seconds < 3600) {
63
+ const m = Math.floor(seconds / 60);
64
+ const s = Math.floor(seconds % 60);
65
+ return `${String(m)}m${String(s).padStart(2, '0')}s`;
66
+ }
67
+ const h = Math.floor(seconds / 3600);
68
+ const m = Math.floor((seconds % 3600) / 60);
69
+ return `${String(h)}h${String(m).padStart(2, '0')}m`;
70
+ }
@@ -9,17 +9,16 @@ export declare function hasRawCssColors(content: string): boolean;
9
9
  /**
10
10
  * Strips JS single-line and multi-line comments from source code, replacing
11
11
  * comment bytes with spaces (newlines inside block comments are kept) so
12
- * both character offsets AND line numbers are preserved. String literals
13
- * are preserved intact.
12
+ * both character offsets AND line numbers are preserved. String literals are
13
+ * preserved intact.
14
14
  *
15
- * Uses acorn's tokenizer, which understands regex literals — the previous
16
- * pure-regex implementation did not model them, so two adjacent slashes
17
- * inside a regex (e.g. the tail of `/https?:\/\//`) were treated as a `//`
18
- * line comment and the rest of the line was blanked, corrupting whatever
19
- * lint pass consumed the stripped text. Firefox chrome sources contain
20
- * preprocessor directives (`#ifdef`) and other constructs acorn cannot
21
- * tokenize; those fall back to the legacy regex strip, which handles
22
- * strings but NOT regex literals (documented limitation of the fallback).
15
+ * Uses acorn's tokenizer, which understands regex literals — a pure-regex
16
+ * implementation does not model them, so two adjacent slashes inside a regex
17
+ * (the tail of `/https?:\/\//`) read as a `//` line comment and the rest of
18
+ * the line is blanked, corrupting whatever lint pass consumes the stripped
19
+ * text. Firefox chrome sources contain preprocessor directives (`#ifdef`)
20
+ * and other constructs acorn cannot tokenize; those fall back to the legacy
21
+ * regex strip, which handles strings but NOT regex literals.
23
22
  */
24
23
  export declare function stripJsComments(source: string): string;
25
24
  /**
@@ -25,17 +25,16 @@ export function hasRawCssColors(content) {
25
25
  /**
26
26
  * Strips JS single-line and multi-line comments from source code, replacing
27
27
  * comment bytes with spaces (newlines inside block comments are kept) so
28
- * both character offsets AND line numbers are preserved. String literals
29
- * are preserved intact.
28
+ * both character offsets AND line numbers are preserved. String literals are
29
+ * preserved intact.
30
30
  *
31
- * Uses acorn's tokenizer, which understands regex literals — the previous
32
- * pure-regex implementation did not model them, so two adjacent slashes
33
- * inside a regex (e.g. the tail of `/https?:\/\//`) were treated as a `//`
34
- * line comment and the rest of the line was blanked, corrupting whatever
35
- * lint pass consumed the stripped text. Firefox chrome sources contain
36
- * preprocessor directives (`#ifdef`) and other constructs acorn cannot
37
- * tokenize; those fall back to the legacy regex strip, which handles
38
- * strings but NOT regex literals (documented limitation of the fallback).
31
+ * Uses acorn's tokenizer, which understands regex literals — a pure-regex
32
+ * implementation does not model them, so two adjacent slashes inside a regex
33
+ * (the tail of `/https?:\/\//`) read as a `//` line comment and the rest of
34
+ * the line is blanked, corrupting whatever lint pass consumes the stripped
35
+ * text. Firefox chrome sources contain preprocessor directives (`#ifdef`)
36
+ * and other constructs acorn cannot tokenize; those fall back to the legacy
37
+ * regex strip, which handles strings but NOT regex literals.
39
38
  */
40
39
  export function stripJsComments(source) {
41
40
  const comments = [];
@@ -1,4 +1,3 @@
1
- import type { FirefoxProduct } from '../types/config.js';
2
1
  import type { JsonObject, JsonValue } from '../types/json.js';
3
2
  /**
4
3
  * Checks whether a value is a string.
@@ -22,15 +21,15 @@ export declare function isPositiveInteger(value: unknown): value is number;
22
21
  * Parses a CLI flag value as a positive integer. Throws
23
22
  * {@link InvalidArgumentError} on NaN, non-integer, or non-positive input.
24
23
  *
25
- * Intended for use inside Commander `argParser` bodies where the raw
26
- * input arrives as a string. Without this wrapper the default pattern
27
- * (`parseInt(v, 10)`) silently hands NaN to downstream planners, which
28
- * then embed it into filenames / orders instead of failing fast.
24
+ * Intended for use inside Commander `argParser` bodies where the raw input
25
+ * arrives as a string. The default pattern (`parseInt(v, 10)`) silently
26
+ * hands NaN to downstream planners, which then embed it into filenames and
27
+ * orders instead of failing fast.
29
28
  *
30
29
  * Rejects leading-zero forms ("01"), decimals ("1.5"), whitespace, and
31
- * non-numeric garbage via a strict regex — we only accept the canonical
32
- * representation so there is no ambiguity between what the user typed
33
- * and what the value becomes on disk.
30
+ * non-numeric garbage via a strict regex — only the canonical
31
+ * representation is accepted, so there is no ambiguity between what the user
32
+ * typed and what the value becomes on disk.
34
33
  *
35
34
  * @param flagName - Flag name to include in the error (e.g. `--order`)
36
35
  * @param rawValue - Raw string value from Commander
@@ -75,30 +74,61 @@ export declare function isValidFirefoxVersion(version: string): boolean;
75
74
  */
76
75
  export declare function isValidFirefoxCandidate(candidate: string): boolean;
77
76
  /**
78
- * Valid Firefox product identifiers.
77
+ * Naming contract for this module's checks.
78
+ *
79
+ * `validate*` is easy to spread across incompatible return contracts — some
80
+ * throwing and returning void, some returning an issue list, some a parsed
81
+ * value, some a boolean, some an error MESSAGE — and a caller cannot tell
82
+ * which from the name. Passing a THROWING `validate*` to a clack `validate`
83
+ * callback, which expects a returned message, kills the prompt instead of
84
+ * re-prompting.
85
+ *
86
+ * The two dominant contracts keep the prefix:
87
+ * - `validate*` — throws on failure, or returns an issue list.
88
+ * - `is*` / `has*` — a type predicate or boolean.
89
+ * The message-returning minority is `describe*Problem`, which reads as what
90
+ * it is: a description of what is wrong, or `undefined`.
79
91
  *
80
- * `satisfies readonly FirefoxProduct[]` links the runtime list to the union at
81
- * `types/config.ts:5` in ONE direction: it rejects an entry here that the union
82
- * does not declare. It cannot see a union member missing from this list —
83
- * widening a `readonly T[]` check never fails for being short. The reverse
84
- * direction is covered by the exhaustive switch in
85
- * `utils/__tests__/validation.test.ts`, which fails to compile when the union
86
- * grows.
92
+ * `assert*` is uniform throughout: throw-or-continue.
93
+ */
94
+ /**
95
+ * Valid Firefox product identifiers.
87
96
  *
88
- * Two further copies of this list existed before 0.41.0 — an inline literal
89
- * inside the validator below and `SOURCE_PRODUCTS` in `commands/source.ts` —
90
- * neither linked to the union.
97
+ * `satisfies readonly FirefoxProduct[]` links the runtime list to the union
98
+ * in ONE direction: it rejects an entry here that the union does not
99
+ * declare. It cannot see a union member missing from this list — widening a
100
+ * `readonly T[]` check never fails for being short. The reverse direction is
101
+ * covered by the exhaustive switch in `utils/__tests__/validation.test.ts`,
102
+ * which fails to compile when the union grows.
91
103
  */
92
104
  export declare const FIREFOX_PRODUCTS: readonly ["firefox", "firefox-esr", "firefox-beta", "firefox-devedition"];
93
105
  /**
94
106
  * Validates a Firefox product string.
95
107
  *
96
108
  * A type predicate, matching its siblings {@link isValidPatchCategory} and
97
- * {@link isValidProjectLicense}. It returned plain `boolean` until 0.41.0,
98
- * which forced `as FirefoxProduct` casts at both call sites even though the
99
- * `.includes` check IS the runtime proof.
109
+ * {@link isValidProjectLicense}. Returning plain `boolean` would force
110
+ * `as FirefoxProduct` casts at the call sites even though the `.includes`
111
+ * check IS the runtime proof.
112
+ */
113
+ export declare const isValidFirefoxProduct: (value: string) => value is "firefox" | "firefox-esr" | "firefox-beta" | "firefox-devedition";
114
+ /**
115
+ * Builds a type predicate from a `readonly` tuple of allowed values.
116
+ *
117
+ * Deriving the type from the list — rather than declaring a union and
118
+ * hand-maintaining a matching array — removes a whole class of drift: a
119
+ * union can otherwise accept a stale allowlist with no compile error, and a
120
+ * copy of the member list on the `fireforge.json` read path can silently
121
+ * reject a newly added value.
122
+ *
123
+ * Returning a predicate rather than a boolean is what removes the `as`
124
+ * casts: `.includes` IS the runtime proof, so the caller should not have to
125
+ * re-assert it. `ParsedRecord.stringEnum` (src/utils/parse.ts) consumes
126
+ * exactly this shape.
127
+ *
128
+ * @param values - The allowed values, as a `readonly` tuple
129
+ * @returns A type predicate narrowing a string to one of `values`
100
130
  */
101
- export declare function isValidFirefoxProduct(product: string): product is FirefoxProduct;
131
+ export declare function makeEnumGuard<const T extends readonly string[]>(values: T): (value: string) => value is T[number];
102
132
  /**
103
133
  * Valid project license SPDX identifiers.
104
134
  */
@@ -106,7 +136,7 @@ export declare const PROJECT_LICENSES: readonly ["EUPL-1.2", "MPL-2.0", "0BSD",
106
136
  /**
107
137
  * Validates a project license string.
108
138
  */
109
- export declare function isValidProjectLicense(license: string): license is (typeof PROJECT_LICENSES)[number];
139
+ export declare const isValidProjectLicense: (value: string) => value is "EUPL-1.2" | "MPL-2.0" | "0BSD" | "GPL-2.0-or-later";
110
140
  /**
111
141
  * Valid patch categories.
112
142
  */
@@ -114,7 +144,7 @@ export declare const PATCH_CATEGORIES: readonly ["branding", "ui", "privacy", "s
114
144
  /**
115
145
  * Validates a patch category string.
116
146
  */
117
- export declare function isValidPatchCategory(category: string): category is (typeof PATCH_CATEGORIES)[number];
147
+ export declare const isValidPatchCategory: (value: string) => value is "branding" | "ui" | "privacy" | "security" | "infra";
118
148
  /**
119
149
  * Infers the Firefox product type from a version string.
120
150
  * Returns undefined if no clear inference can be made.
@@ -130,7 +160,7 @@ export declare function inferProductFromVersion(version: string): 'firefox' | 'f
130
160
  *
131
161
  * @returns An error message if incompatible, or undefined if valid.
132
162
  */
133
- export declare function validateFirefoxProductVersionCompatibility(version: string, product: string): string | undefined;
163
+ export declare function describeProductVersionIncompatibility(version: string, product: string): string | undefined;
134
164
  /**
135
165
  * Validates an application ID string.
136
166
  * Accepts reverse-domain format like "org.example.browser"
@@ -151,7 +181,7 @@ export declare function isDefined<T>(value: T | undefined | null): value is T;
151
181
  *
152
182
  * @returns An error message if invalid, or undefined if valid.
153
183
  */
154
- export declare function validateTokenName(name: string): string | undefined;
184
+ export declare function describeTokenNameProblem(name: string): string | undefined;
155
185
  /**
156
186
  * Normalizes a CSS custom property token name.
157
187
  * Strips leading `--` if present, then always prepends `--`.
@@ -175,4 +205,4 @@ export declare function normalizePatchDisplayName(name: string, category: string
175
205
  * @param name - The patch name to validate
176
206
  * @returns Error message if invalid, undefined if valid
177
207
  */
178
- export declare function validatePatchName(name: string): string | undefined;
208
+ export declare function describePatchNameProblem(name: string): string | undefined;
@@ -36,15 +36,15 @@ export function isPositiveInteger(value) {
36
36
  * Parses a CLI flag value as a positive integer. Throws
37
37
  * {@link InvalidArgumentError} on NaN, non-integer, or non-positive input.
38
38
  *
39
- * Intended for use inside Commander `argParser` bodies where the raw
40
- * input arrives as a string. Without this wrapper the default pattern
41
- * (`parseInt(v, 10)`) silently hands NaN to downstream planners, which
42
- * then embed it into filenames / orders instead of failing fast.
39
+ * Intended for use inside Commander `argParser` bodies where the raw input
40
+ * arrives as a string. The default pattern (`parseInt(v, 10)`) silently
41
+ * hands NaN to downstream planners, which then embed it into filenames and
42
+ * orders instead of failing fast.
43
43
  *
44
44
  * Rejects leading-zero forms ("01"), decimals ("1.5"), whitespace, and
45
- * non-numeric garbage via a strict regex — we only accept the canonical
46
- * representation so there is no ambiguity between what the user typed
47
- * and what the value becomes on disk.
45
+ * non-numeric garbage via a strict regex — only the canonical
46
+ * representation is accepted, so there is no ambiguity between what the user
47
+ * typed and what the value becomes on disk.
48
48
  *
49
49
  * @param flagName - Flag name to include in the error (e.g. `--order`)
50
50
  * @param rawValue - Raw string value from Commander
@@ -108,19 +108,32 @@ export function isValidFirefoxCandidate(candidate) {
108
108
  return /^build[1-9]\d{0,3}$/.test(candidate);
109
109
  }
110
110
  /**
111
- * Valid Firefox product identifiers.
111
+ * Naming contract for this module's checks.
112
+ *
113
+ * `validate*` is easy to spread across incompatible return contracts — some
114
+ * throwing and returning void, some returning an issue list, some a parsed
115
+ * value, some a boolean, some an error MESSAGE — and a caller cannot tell
116
+ * which from the name. Passing a THROWING `validate*` to a clack `validate`
117
+ * callback, which expects a returned message, kills the prompt instead of
118
+ * re-prompting.
112
119
  *
113
- * `satisfies readonly FirefoxProduct[]` links the runtime list to the union at
114
- * `types/config.ts:5` in ONE direction: it rejects an entry here that the union
115
- * does not declare. It cannot see a union member missing from this list —
116
- * widening a `readonly T[]` check never fails for being short. The reverse
117
- * direction is covered by the exhaustive switch in
118
- * `utils/__tests__/validation.test.ts`, which fails to compile when the union
119
- * grows.
120
+ * The two dominant contracts keep the prefix:
121
+ * - `validate*` — throws on failure, or returns an issue list.
122
+ * - `is*` / `has*` — a type predicate or boolean.
123
+ * The message-returning minority is `describe*Problem`, which reads as what
124
+ * it is: a description of what is wrong, or `undefined`.
120
125
  *
121
- * Two further copies of this list existed before 0.41.0 — an inline literal
122
- * inside the validator below and `SOURCE_PRODUCTS` in `commands/source.ts` —
123
- * neither linked to the union.
126
+ * `assert*` is uniform throughout: throw-or-continue.
127
+ */
128
+ /**
129
+ * Valid Firefox product identifiers.
130
+ *
131
+ * `satisfies readonly FirefoxProduct[]` links the runtime list to the union
132
+ * in ONE direction: it rejects an entry here that the union does not
133
+ * declare. It cannot see a union member missing from this list — widening a
134
+ * `readonly T[]` check never fails for being short. The reverse direction is
135
+ * covered by the exhaustive switch in `utils/__tests__/validation.test.ts`,
136
+ * which fails to compile when the union grows.
124
137
  */
125
138
  export const FIREFOX_PRODUCTS = [
126
139
  'firefox',
@@ -132,12 +145,30 @@ export const FIREFOX_PRODUCTS = [
132
145
  * Validates a Firefox product string.
133
146
  *
134
147
  * A type predicate, matching its siblings {@link isValidPatchCategory} and
135
- * {@link isValidProjectLicense}. It returned plain `boolean` until 0.41.0,
136
- * which forced `as FirefoxProduct` casts at both call sites even though the
137
- * `.includes` check IS the runtime proof.
148
+ * {@link isValidProjectLicense}. Returning plain `boolean` would force
149
+ * `as FirefoxProduct` casts at the call sites even though the `.includes`
150
+ * check IS the runtime proof.
138
151
  */
139
- export function isValidFirefoxProduct(product) {
140
- return FIREFOX_PRODUCTS.includes(product);
152
+ export const isValidFirefoxProduct = makeEnumGuard(FIREFOX_PRODUCTS);
153
+ /**
154
+ * Builds a type predicate from a `readonly` tuple of allowed values.
155
+ *
156
+ * Deriving the type from the list — rather than declaring a union and
157
+ * hand-maintaining a matching array — removes a whole class of drift: a
158
+ * union can otherwise accept a stale allowlist with no compile error, and a
159
+ * copy of the member list on the `fireforge.json` read path can silently
160
+ * reject a newly added value.
161
+ *
162
+ * Returning a predicate rather than a boolean is what removes the `as`
163
+ * casts: `.includes` IS the runtime proof, so the caller should not have to
164
+ * re-assert it. `ParsedRecord.stringEnum` (src/utils/parse.ts) consumes
165
+ * exactly this shape.
166
+ *
167
+ * @param values - The allowed values, as a `readonly` tuple
168
+ * @returns A type predicate narrowing a string to one of `values`
169
+ */
170
+ export function makeEnumGuard(values) {
171
+ return (value) => values.includes(value);
141
172
  }
142
173
  /**
143
174
  * Valid project license SPDX identifiers.
@@ -146,9 +177,7 @@ export const PROJECT_LICENSES = ['EUPL-1.2', 'MPL-2.0', '0BSD', 'GPL-2.0-or-late
146
177
  /**
147
178
  * Validates a project license string.
148
179
  */
149
- export function isValidProjectLicense(license) {
150
- return PROJECT_LICENSES.includes(license);
151
- }
180
+ export const isValidProjectLicense = makeEnumGuard(PROJECT_LICENSES);
152
181
  /**
153
182
  * Valid patch categories.
154
183
  */
@@ -156,9 +185,7 @@ export const PATCH_CATEGORIES = ['branding', 'ui', 'privacy', 'security', 'infra
156
185
  /**
157
186
  * Validates a patch category string.
158
187
  */
159
- export function isValidPatchCategory(category) {
160
- return PATCH_CATEGORIES.includes(category);
161
- }
188
+ export const isValidPatchCategory = makeEnumGuard(PATCH_CATEGORIES);
162
189
  /**
163
190
  * Checks whether a Firefox version string has an ESR suffix.
164
191
  */
@@ -194,7 +221,7 @@ export function inferProductFromVersion(version) {
194
221
  *
195
222
  * @returns An error message if incompatible, or undefined if valid.
196
223
  */
197
- export function validateFirefoxProductVersionCompatibility(version, product) {
224
+ export function describeProductVersionIncompatibility(version, product) {
198
225
  const versionIsEsr = isEsrVersion(version);
199
226
  const versionIsBeta = isBetaVersion(version);
200
227
  switch (product) {
@@ -247,7 +274,7 @@ export function isDefined(value) {
247
274
  *
248
275
  * @returns An error message if invalid, or undefined if valid.
249
276
  */
250
- export function validateTokenName(name) {
277
+ export function describeTokenNameProblem(name) {
251
278
  // Strip leading -- for validation (callers may pass with or without)
252
279
  const ident = name.replace(/^--/, '');
253
280
  if (!ident) {
@@ -282,7 +309,7 @@ export function validateTokenName(name) {
282
309
  * @throws InvalidArgumentError if the resulting name is not a valid CSS custom property.
283
310
  */
284
311
  export function normalizeTokenName(name) {
285
- const error = validateTokenName(name);
312
+ const error = describeTokenNameProblem(name);
286
313
  if (error) {
287
314
  throw new InvalidArgumentError(error, 'tokenName');
288
315
  }
@@ -323,7 +350,7 @@ export function normalizePatchDisplayName(name, category) {
323
350
  * @param name - The patch name to validate
324
351
  * @returns Error message if invalid, undefined if valid
325
352
  */
326
- export function validatePatchName(name) {
353
+ export function describePatchNameProblem(name) {
327
354
  if (!name.trim())
328
355
  return 'Name is required';
329
356
  if (name.length > 50)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.43.1",
3
+ "version": "0.44.1",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -38,7 +38,7 @@
38
38
  "format:check": "prettier --check --ignore-unknown \"src/**/*.ts\" \"bin/**/*.ts\" \"scripts/**/*.mjs\" \"eslint-rules/**/*.js\" \"package.json\" \"eslint.config.js\" \"vitest.config.ts\" \"vitest.pack.config.ts\" \"tsconfig.json\" \"tsconfig.build.json\" \".lintstagedrc.json\" \".prettierignore\" \".prettierrc\" \".gitignore\" \"README.md\" \"CHANGELOG.md\" \"docs/**/*.md\" \"knip.json\"",
39
39
  "prepare": "node -e \"import('./scripts/prepare.mjs').catch((error) => { if (error && typeof error === 'object' && 'code' in error && error.code === 'ERR_MODULE_NOT_FOUND') process.exit(0); throw error; })\"",
40
40
  "prepack": "npm run build && node ./scripts/generate-build-info.mjs --loud",
41
- "release:check": "npm run format:check && npm run whitespace:check && npm run lint:ci && npm run typecheck && npm run deadcode:check && npm run cycles:check && npm run test:coverage && npm run pack:verify && npm run pack:dry-run",
41
+ "release:check": "npm run format:check && npm run whitespace:check && npm run lint:ci && npm run typecheck && npm run deadcode:check && npm run cycles:check && npm run test:coverage && npm run pack:verify",
42
42
  "prepublishOnly": "npm run release:check"
43
43
  },
44
44
  "files": [
@@ -83,7 +83,7 @@
83
83
  "vitest": "^4.0.18"
84
84
  },
85
85
  "engines": {
86
- "node": ">=22.22.1"
86
+ "node": ">=22.22.2"
87
87
  },
88
88
  "packageManager": "npm@11.12.1",
89
89
  "license": "EUPL-1.2",
@@ -1,2 +0,0 @@
1
- import type { DoctorCheckDefinition } from '../doctor-check-core.js';
2
- export declare const POST_REBASE_AUDIT_CHECK: DoctorCheckDefinition;
@@ -1,18 +0,0 @@
1
- /**
2
- * "Furnace manifest sync" doctor check.
3
- *
4
- * Surfaces orphaned component directories on disk whose names are missing
5
- * from `furnace.json`. The motivating eval case is the concurrent-override
6
- * race (eval 2) where two parallel `furnace override` commands both left
7
- * their directory on disk but only the second reached
8
- * `writeFurnaceConfig`. Under `--repair-furnace`, override orphans are
9
- * re-registered from the `override.json` sidecar the command wrote during
10
- * the copy phase; custom orphans are listed for the operator to either
11
- * re-run `furnace create` against or delete manually, because custom
12
- * components have no similar persisted metadata.
13
- *
14
- * Lives in a sibling module to keep `doctor-furnace.ts` under the
15
- * per-file LOC budget.
16
- */
17
- import type { DoctorCheckDefinition } from './doctor-check-core.js';
18
- export declare const furnaceManifestSyncCheck: DoctorCheckDefinition;