@hominis/fireforge 0.43.1 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +10 -1
  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 +4 -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-post-rebase-audit.d.ts +2 -0
  22. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  23. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  24. package/dist/src/commands/doctor-working-tree.js +11 -18
  25. package/dist/src/commands/doctor.js +35 -53
  26. package/dist/src/commands/download.js +32 -48
  27. package/dist/src/commands/export-all.js +29 -33
  28. package/dist/src/commands/export-flow.js +6 -6
  29. package/dist/src/commands/export-placement-conflicts.js +10 -9
  30. package/dist/src/commands/export-placement-gate.js +5 -5
  31. package/dist/src/commands/export-shared.d.ts +30 -33
  32. package/dist/src/commands/export-shared.js +45 -43
  33. package/dist/src/commands/export.js +21 -27
  34. package/dist/src/commands/furnace/apply.js +14 -23
  35. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  36. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  37. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  38. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  39. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  40. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  41. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  42. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  43. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  44. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  45. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  46. package/dist/src/commands/furnace/create-readback.js +12 -13
  47. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  48. package/dist/src/commands/furnace/create-templates.js +35 -30
  49. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  50. package/dist/src/commands/furnace/create.js +33 -23
  51. package/dist/src/commands/furnace/deploy.js +16 -24
  52. package/dist/src/commands/furnace/diff.js +9 -9
  53. package/dist/src/commands/furnace/init.js +33 -36
  54. package/dist/src/commands/furnace/override.js +23 -25
  55. package/dist/src/commands/furnace/preview.js +47 -67
  56. package/dist/src/commands/furnace/refresh.js +12 -16
  57. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  58. package/dist/src/commands/furnace/remove-mutations.js +9 -16
  59. package/dist/src/commands/furnace/remove-state.js +1 -1
  60. package/dist/src/commands/furnace/remove.js +33 -38
  61. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  62. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  63. package/dist/src/commands/furnace/rename.js +59 -69
  64. package/dist/src/commands/furnace/scan.js +19 -33
  65. package/dist/src/commands/furnace/status.js +12 -9
  66. package/dist/src/commands/furnace/sync.js +9 -16
  67. package/dist/src/commands/furnace/validate.js +20 -20
  68. package/dist/src/commands/import.js +42 -35
  69. package/dist/src/commands/lint-per-patch.js +15 -10
  70. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  71. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  72. package/dist/src/commands/lint-report.js +6 -7
  73. package/dist/src/commands/lint.d.ts +15 -16
  74. package/dist/src/commands/lint.js +86 -102
  75. package/dist/src/commands/package.js +6 -11
  76. package/dist/src/commands/patch/compact.js +1 -1
  77. package/dist/src/commands/patch/delete.js +24 -33
  78. package/dist/src/commands/patch/index.d.ts +5 -6
  79. package/dist/src/commands/patch/index.js +10 -12
  80. package/dist/src/commands/patch/lint-ignore.js +14 -13
  81. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  82. package/dist/src/commands/patch/move-files-create.js +8 -8
  83. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  84. package/dist/src/commands/patch/move-files-into.js +8 -8
  85. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  86. package/dist/src/commands/patch/patch-context.js +2 -3
  87. package/dist/src/commands/patch/rename.d.ts +10 -11
  88. package/dist/src/commands/patch/rename.js +11 -12
  89. package/dist/src/commands/patch/reorder.js +8 -9
  90. package/dist/src/commands/patch/split-plan.js +1 -1
  91. package/dist/src/commands/patch/split.d.ts +8 -10
  92. package/dist/src/commands/patch/split.js +9 -11
  93. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  94. package/dist/src/commands/patch/staged-dependency.js +7 -3
  95. package/dist/src/commands/patch/tier.d.ts +9 -9
  96. package/dist/src/commands/patch/tier.js +18 -15
  97. package/dist/src/commands/re-export-adjacent.js +9 -8
  98. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  99. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  100. package/dist/src/commands/re-export-drift.js +10 -10
  101. package/dist/src/commands/re-export-files.d.ts +6 -7
  102. package/dist/src/commands/re-export-files.js +34 -44
  103. package/dist/src/commands/re-export-lint.d.ts +10 -13
  104. package/dist/src/commands/re-export-lint.js +16 -14
  105. package/dist/src/commands/re-export-options.d.ts +6 -6
  106. package/dist/src/commands/re-export-options.js +6 -6
  107. package/dist/src/commands/re-export-register.d.ts +4 -10
  108. package/dist/src/commands/re-export-register.js +5 -11
  109. package/dist/src/commands/re-export-scan.js +1 -1
  110. package/dist/src/commands/re-export-single.d.ts +3 -3
  111. package/dist/src/commands/re-export-single.js +33 -25
  112. package/dist/src/commands/re-export.js +13 -21
  113. package/dist/src/commands/rebase/abort.js +3 -3
  114. package/dist/src/commands/rebase/confirm.js +2 -1
  115. package/dist/src/commands/rebase/continue.d.ts +1 -1
  116. package/dist/src/commands/rebase/continue.js +14 -9
  117. package/dist/src/commands/rebase/index.js +11 -11
  118. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  119. package/dist/src/commands/rebase/patch-loop.js +60 -39
  120. package/dist/src/commands/rebase/summary.js +1 -1
  121. package/dist/src/commands/register.js +5 -7
  122. package/dist/src/commands/reset.js +2 -1
  123. package/dist/src/commands/resolve.d.ts +16 -13
  124. package/dist/src/commands/resolve.js +30 -33
  125. package/dist/src/commands/run.js +33 -35
  126. package/dist/src/commands/setup-support.js +15 -19
  127. package/dist/src/commands/setup.js +13 -9
  128. package/dist/src/commands/status-check.d.ts +6 -6
  129. package/dist/src/commands/status-json.d.ts +6 -6
  130. package/dist/src/commands/status-json.js +5 -0
  131. package/dist/src/commands/status-output.d.ts +5 -5
  132. package/dist/src/commands/status-output.js +6 -6
  133. package/dist/src/commands/status-ownership.d.ts +16 -14
  134. package/dist/src/commands/status-ownership.js +16 -14
  135. package/dist/src/commands/status.js +42 -34
  136. package/dist/src/commands/test-build-phase.js +26 -13
  137. package/dist/src/commands/test-diagnose.js +44 -44
  138. package/dist/src/commands/test-register.js +1 -0
  139. package/dist/src/commands/test-run.d.ts +14 -16
  140. package/dist/src/commands/test-run.js +21 -13
  141. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  142. package/dist/src/commands/test-stale-gate.js +15 -16
  143. package/dist/src/commands/test-verdict.d.ts +20 -3
  144. package/dist/src/commands/test-verdict.js +30 -0
  145. package/dist/src/commands/test.js +83 -76
  146. package/dist/src/commands/token-coverage.js +3 -4
  147. package/dist/src/commands/token.js +16 -18
  148. package/dist/src/commands/tree.js +47 -31
  149. package/dist/src/commands/typecheck.d.ts +10 -12
  150. package/dist/src/commands/typecheck.js +24 -27
  151. package/dist/src/commands/verify.js +13 -15
  152. package/dist/src/commands/watch.js +21 -23
  153. package/dist/src/commands/wire.js +52 -62
  154. package/dist/src/core/ast-utils.d.ts +8 -7
  155. package/dist/src/core/ast-utils.js +8 -7
  156. package/dist/src/core/branding.d.ts +9 -14
  157. package/dist/src/core/branding.js +7 -11
  158. package/dist/src/core/browser-wire.d.ts +1 -1
  159. package/dist/src/core/browser-wire.js +14 -19
  160. package/dist/src/core/build-audit-platform.js +25 -33
  161. package/dist/src/core/build-audit-registration.js +17 -25
  162. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  163. package/dist/src/core/build-audit-resolve.js +27 -33
  164. package/dist/src/core/build-audit-transforms.js +18 -19
  165. package/dist/src/core/build-audit.js +28 -42
  166. package/dist/src/core/build-baseline-types.d.ts +29 -35
  167. package/dist/src/core/build-baseline.d.ts +5 -4
  168. package/dist/src/core/build-baseline.js +14 -14
  169. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  170. package/dist/src/core/build-overwrite-guard.js +17 -27
  171. package/dist/src/core/build-prepare.d.ts +2 -2
  172. package/dist/src/core/build-prepare.js +8 -9
  173. package/dist/src/core/config-state.js +12 -4
  174. package/dist/src/core/config-validate.js +8 -5
  175. package/dist/src/core/config.d.ts +5 -8
  176. package/dist/src/core/config.js +7 -16
  177. package/dist/src/core/coverage-extend.d.ts +15 -13
  178. package/dist/src/core/coverage-extend.js +15 -13
  179. package/dist/src/core/destructive.d.ts +31 -9
  180. package/dist/src/core/destructive.js +29 -26
  181. package/dist/src/core/diff-hunks.js +10 -12
  182. package/dist/src/core/discard-baseline.d.ts +8 -8
  183. package/dist/src/core/discard-baseline.js +16 -15
  184. package/dist/src/core/display-state.d.ts +12 -14
  185. package/dist/src/core/display-state.js +12 -14
  186. package/dist/src/core/engine-changes.d.ts +2 -4
  187. package/dist/src/core/engine-changes.js +2 -4
  188. package/dist/src/core/engine-precondition.d.ts +28 -13
  189. package/dist/src/core/engine-precondition.js +25 -10
  190. package/dist/src/core/engine-session-lock.d.ts +47 -21
  191. package/dist/src/core/engine-session-lock.js +168 -33
  192. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  193. package/dist/src/core/export-moved-code-shape.js +10 -10
  194. package/dist/src/core/file-lock.d.ts +62 -5
  195. package/dist/src/core/file-lock.js +196 -59
  196. package/dist/src/core/firefox-cache.js +1 -3
  197. package/dist/src/core/firefox-extract.js +10 -14
  198. package/dist/src/core/firefox.d.ts +7 -5
  199. package/dist/src/core/firefox.js +4 -5
  200. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  201. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  202. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  203. package/dist/src/core/furnace-apply-ftl.js +12 -12
  204. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  205. package/dist/src/core/furnace-apply-helpers.js +19 -16
  206. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  207. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  208. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  209. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  210. package/dist/src/core/furnace-apply.d.ts +5 -8
  211. package/dist/src/core/furnace-apply.js +19 -24
  212. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  213. package/dist/src/core/furnace-checksum-utils.js +16 -0
  214. package/dist/src/core/furnace-config.d.ts +21 -30
  215. package/dist/src/core/furnace-config.js +32 -54
  216. package/dist/src/core/furnace-constants.d.ts +8 -0
  217. package/dist/src/core/furnace-constants.js +10 -2
  218. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  219. package/dist/src/core/furnace-css-fragments.js +5 -5
  220. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  221. package/dist/src/core/furnace-jsconfig.js +11 -12
  222. package/dist/src/core/furnace-marker.d.ts +7 -8
  223. package/dist/src/core/furnace-marker.js +7 -8
  224. package/dist/src/core/furnace-operation.d.ts +31 -0
  225. package/dist/src/core/furnace-operation.js +54 -17
  226. package/dist/src/core/furnace-precondition.d.ts +61 -0
  227. package/dist/src/core/furnace-precondition.js +67 -0
  228. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  229. package/dist/src/core/furnace-registration-remove.js +6 -7
  230. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  231. package/dist/src/core/furnace-registration-validate.js +20 -1
  232. package/dist/src/core/furnace-registration.d.ts +5 -6
  233. package/dist/src/core/furnace-registration.js +10 -12
  234. package/dist/src/core/furnace-rollback.js +7 -7
  235. package/dist/src/core/furnace-scanner.d.ts +1 -0
  236. package/dist/src/core/furnace-scanner.js +1 -2
  237. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  238. package/dist/src/core/furnace-stale-export.js +10 -10
  239. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  240. package/dist/src/core/furnace-state-persist.js +6 -8
  241. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  242. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  243. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  244. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  245. package/dist/src/core/furnace-validate-helpers.js +0 -491
  246. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  247. package/dist/src/core/furnace-validate-registration.js +115 -41
  248. package/dist/src/core/furnace-validate.d.ts +16 -0
  249. package/dist/src/core/furnace-validate.js +188 -145
  250. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  251. package/dist/src/core/furnace-version-drift.js +10 -11
  252. package/dist/src/core/git-base.d.ts +7 -9
  253. package/dist/src/core/git-base.js +7 -9
  254. package/dist/src/core/git-diff.d.ts +20 -9
  255. package/dist/src/core/git-diff.js +148 -63
  256. package/dist/src/core/git-file-ops.d.ts +19 -19
  257. package/dist/src/core/git-file-ops.js +19 -19
  258. package/dist/src/core/git-readonly-index.d.ts +53 -19
  259. package/dist/src/core/git-readonly-index.js +75 -31
  260. package/dist/src/core/git-status.d.ts +5 -6
  261. package/dist/src/core/git-status.js +5 -6
  262. package/dist/src/core/git.d.ts +9 -10
  263. package/dist/src/core/git.js +54 -70
  264. package/dist/src/core/license-headers.d.ts +17 -23
  265. package/dist/src/core/license-headers.js +17 -23
  266. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  267. package/dist/src/core/mach-build-artifacts.js +57 -19
  268. package/dist/src/core/mach-error-hints.js +42 -29
  269. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  270. package/dist/src/core/mach-known-noise-filter.js +18 -20
  271. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  272. package/dist/src/core/mach-mozconfig.js +30 -0
  273. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  274. package/dist/src/core/mach-resource-shim.js +50 -67
  275. package/dist/src/core/mach.d.ts +37 -41
  276. package/dist/src/core/mach.js +50 -51
  277. package/dist/src/core/marionette-port.d.ts +36 -1
  278. package/dist/src/core/marionette-port.js +96 -31
  279. package/dist/src/core/marionette-preflight.d.ts +8 -12
  280. package/dist/src/core/marionette-preflight.js +86 -52
  281. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  282. package/dist/src/core/mochitest-server-port.js +119 -0
  283. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  284. package/dist/src/core/module-resolution-preflight.js +9 -11
  285. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  286. package/dist/src/core/moz-manifest-helpers.js +163 -0
  287. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  288. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  289. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  290. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  291. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  292. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  293. package/dist/src/core/ownership-table.d.ts +14 -16
  294. package/dist/src/core/ownership-table.js +14 -16
  295. package/dist/src/core/parser-fallback.d.ts +15 -1
  296. package/dist/src/core/parser-fallback.js +22 -3
  297. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  298. package/dist/src/core/patch-apply-fuzz.js +15 -18
  299. package/dist/src/core/patch-apply.d.ts +13 -34
  300. package/dist/src/core/patch-apply.js +16 -76
  301. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  302. package/dist/src/core/patch-artifact-normalize.js +13 -15
  303. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  304. package/dist/src/core/patch-export-metadata.js +13 -4
  305. package/dist/src/core/patch-export-update.d.ts +13 -1
  306. package/dist/src/core/patch-export-update.js +25 -8
  307. package/dist/src/core/patch-export.d.ts +15 -8
  308. package/dist/src/core/patch-export.js +10 -11
  309. package/dist/src/core/patch-files.d.ts +5 -6
  310. package/dist/src/core/patch-files.js +5 -6
  311. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  312. package/dist/src/core/patch-identifier-suggest.js +14 -19
  313. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  314. package/dist/src/core/patch-lint-binary.js +39 -0
  315. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  316. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  317. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  318. package/dist/src/core/patch-lint-checkjs.js +16 -16
  319. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  320. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  321. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  322. package/dist/src/core/patch-lint-creators.js +8 -8
  323. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  324. package/dist/src/core/patch-lint-cross.js +16 -16
  325. package/dist/src/core/patch-lint-css.d.ts +3 -5
  326. package/dist/src/core/patch-lint-css.js +17 -22
  327. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  328. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  329. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  330. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  331. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  332. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  333. package/dist/src/core/patch-lint-observer.js +7 -7
  334. package/dist/src/core/patch-lint.d.ts +38 -29
  335. package/dist/src/core/patch-lint.js +89 -121
  336. package/dist/src/core/patch-lock.d.ts +1 -1
  337. package/dist/src/core/patch-lock.js +45 -9
  338. package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
  339. package/dist/src/core/patch-manifest-consistency.js +25 -27
  340. package/dist/src/core/patch-manifest-io.js +14 -18
  341. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  342. package/dist/src/core/patch-manifest-resolve.js +9 -12
  343. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  344. package/dist/src/core/patch-manifest-validate.js +25 -13
  345. package/dist/src/core/patch-parse.d.ts +24 -13
  346. package/dist/src/core/patch-parse.js +19 -14
  347. package/dist/src/core/patch-policy.d.ts +2 -2
  348. package/dist/src/core/patch-policy.js +2 -2
  349. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  350. package/dist/src/core/patch-registration-refs.js +9 -9
  351. package/dist/src/core/process-cpu-time.d.ts +12 -0
  352. package/dist/src/core/process-cpu-time.js +52 -0
  353. package/dist/src/core/rebase-session.d.ts +38 -26
  354. package/dist/src/core/rebase-session.js +55 -28
  355. package/dist/src/core/register-browser-content.js +9 -74
  356. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  357. package/dist/src/core/register-module.js +10 -43
  358. package/dist/src/core/register-scaffold.d.ts +8 -8
  359. package/dist/src/core/register-scaffold.js +10 -10
  360. package/dist/src/core/register-shared-css.d.ts +9 -12
  361. package/dist/src/core/register-shared-css.js +17 -87
  362. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  363. package/dist/src/core/register-xpcshell-test.js +7 -8
  364. package/dist/src/core/shared-ftl.js +12 -4
  365. package/dist/src/core/state-file.d.ts +45 -0
  366. package/dist/src/core/state-file.js +34 -0
  367. package/dist/src/core/status-binary.d.ts +18 -11
  368. package/dist/src/core/status-binary.js +19 -12
  369. package/dist/src/core/status-classify.d.ts +30 -36
  370. package/dist/src/core/status-classify.js +21 -26
  371. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  372. package/dist/src/core/test-changed-prefs.js +78 -0
  373. package/dist/src/core/test-harness-crash.d.ts +25 -63
  374. package/dist/src/core/test-harness-crash.js +121 -142
  375. package/dist/src/core/test-harness-signature.d.ts +18 -0
  376. package/dist/src/core/test-harness-signature.js +13 -0
  377. package/dist/src/core/test-path-scope.d.ts +12 -15
  378. package/dist/src/core/test-path-scope.js +15 -18
  379. package/dist/src/core/test-stale-check.d.ts +17 -17
  380. package/dist/src/core/test-stale-check.js +50 -43
  381. package/dist/src/core/test-stall-triage.d.ts +51 -0
  382. package/dist/src/core/test-stall-triage.js +126 -0
  383. package/dist/src/core/token-category.js +5 -7
  384. package/dist/src/core/token-coverage.js +9 -9
  385. package/dist/src/core/token-dark-mode.d.ts +9 -11
  386. package/dist/src/core/token-dark-mode.js +9 -11
  387. package/dist/src/core/token-docs.d.ts +2 -0
  388. package/dist/src/core/token-docs.js +2 -0
  389. package/dist/src/core/token-manager.d.ts +10 -2
  390. package/dist/src/core/token-manager.js +17 -8
  391. package/dist/src/core/token-scaffold.d.ts +7 -7
  392. package/dist/src/core/token-scaffold.js +7 -7
  393. package/dist/src/core/token-variant.d.ts +4 -4
  394. package/dist/src/core/token-variant.js +4 -4
  395. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  396. package/dist/src/core/toolchain-preflight.js +28 -31
  397. package/dist/src/core/tree-guard.js +12 -2
  398. package/dist/src/core/tree-store.d.ts +41 -27
  399. package/dist/src/core/tree-store.js +63 -42
  400. package/dist/src/core/typecheck-shim.d.ts +23 -24
  401. package/dist/src/core/typecheck-shim.js +23 -24
  402. package/dist/src/core/typecheck.js +8 -8
  403. package/dist/src/core/wire-destroy.d.ts +3 -3
  404. package/dist/src/core/wire-destroy.js +7 -15
  405. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  406. package/dist/src/core/wire-dom-fragment.js +11 -44
  407. package/dist/src/core/wire-init.d.ts +2 -3
  408. package/dist/src/core/wire-init.js +8 -19
  409. package/dist/src/core/wire-subscript.d.ts +2 -3
  410. package/dist/src/core/wire-subscript.js +4 -13
  411. package/dist/src/core/wire-utils.d.ts +7 -8
  412. package/dist/src/core/wire-utils.js +7 -8
  413. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  414. package/dist/src/core/xpcshell-appdir.js +38 -45
  415. package/dist/src/errors/base.d.ts +37 -16
  416. package/dist/src/errors/base.js +37 -16
  417. package/dist/src/errors/build.d.ts +13 -1
  418. package/dist/src/errors/build.js +14 -2
  419. package/dist/src/errors/codes.d.ts +16 -0
  420. package/dist/src/errors/codes.js +16 -0
  421. package/dist/src/errors/furnace.d.ts +4 -4
  422. package/dist/src/errors/git.d.ts +6 -10
  423. package/dist/src/errors/git.js +6 -10
  424. package/dist/src/errors/patch.d.ts +7 -7
  425. package/dist/src/errors/patch.js +7 -7
  426. package/dist/src/errors/rebase.d.ts +4 -4
  427. package/dist/src/errors/rebase.js +4 -4
  428. package/dist/src/index.d.ts +7 -1
  429. package/dist/src/index.js +5 -0
  430. package/dist/src/types/commands/index.d.ts +2 -2
  431. package/dist/src/types/commands/options.d.ts +88 -70
  432. package/dist/src/types/commands/patches.d.ts +24 -34
  433. package/dist/src/types/commands/project.d.ts +5 -34
  434. package/dist/src/types/config.d.ts +25 -23
  435. package/dist/src/types/config.js +6 -1
  436. package/dist/src/types/furnace.d.ts +37 -13
  437. package/dist/src/types/furnace.js +19 -1
  438. package/dist/src/types/index.d.ts +3 -3
  439. package/dist/src/utils/build-info.d.ts +7 -8
  440. package/dist/src/utils/build-info.js +12 -11
  441. package/dist/src/utils/errors.d.ts +6 -8
  442. package/dist/src/utils/errors.js +6 -8
  443. package/dist/src/utils/logger.d.ts +27 -10
  444. package/dist/src/utils/logger.js +28 -16
  445. package/dist/src/utils/machine-output.d.ts +12 -0
  446. package/dist/src/utils/machine-output.js +33 -0
  447. package/dist/src/utils/options.d.ts +31 -14
  448. package/dist/src/utils/options.js +86 -30
  449. package/dist/src/utils/paths.d.ts +10 -8
  450. package/dist/src/utils/paths.js +10 -8
  451. package/dist/src/utils/platform.d.ts +0 -25
  452. package/dist/src/utils/platform.js +1 -42
  453. package/dist/src/utils/process-group.d.ts +9 -4
  454. package/dist/src/utils/process-group.js +19 -5
  455. package/dist/src/utils/process.d.ts +42 -7
  456. package/dist/src/utils/process.js +44 -17
  457. package/dist/src/utils/ps-duration.d.ts +31 -0
  458. package/dist/src/utils/ps-duration.js +70 -0
  459. package/dist/src/utils/regex.d.ts +9 -10
  460. package/dist/src/utils/regex.js +9 -10
  461. package/dist/src/utils/validation.d.ts +58 -28
  462. package/dist/src/utils/validation.js +60 -33
  463. package/package.json +2 -2
  464. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  465. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  466. package/dist/src/core/manifest-helpers.d.ts +0 -38
  467. package/dist/src/core/manifest-helpers.js +0 -120
  468. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  469. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  470. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -4,24 +4,23 @@
4
4
  *
5
5
  * Without this preflight, an operator who edits engine chrome / packaged
6
6
  * resources (`jar.mn` entries, `.xhtml`/`.mjs`/`.css` under chrome trees,
7
- * pref files) and then runs `fireforge test <path>` only discovers the
8
- * build is stale AFTER xpcshell / mach test starts and errors out with
9
- * `NS_ERROR_FILE_NOT_FOUND` against a `chrome://browser/content/…` URI
10
- * — which reads as a test bug, not a rebuild prompt. The motivating case
11
- * was scaffolding a new top-level chrome document + BrowserGlue-style
12
- * xpcshell test: the test file existed, the manifests were registered,
13
- * but `dist/` still held the pre-edit bundle and chrome URIs resolved
14
- * to nothing.
7
+ * pref files) and then runs `fireforge test <path>` only discovers the build
8
+ * is stale AFTER xpcshell / mach test starts and errors out with
9
+ * `NS_ERROR_FILE_NOT_FOUND` against a `chrome://browser/content/…` URI —
10
+ * which reads as a test bug, not a rebuild prompt. Scaffolding a new
11
+ * top-level chrome document plus an xpcshell test is the canonical case: the
12
+ * test file exists, the manifests are registered, but `dist/` still holds
13
+ * the pre-edit bundle and chrome URIs resolve to nothing.
15
14
  *
16
15
  * This preflight diffs engine HEAD (or workdir) against the last-build
17
16
  * baseline (`.fireforge/last-build.json`), filters to paths that imply
18
17
  * packaging, and returns a compact summary. `fireforge test` prints a
19
- * warning up-front so the operator sees "you edited X, Y, Z since the
20
- * last build — rerun with `--build` to refresh" BEFORE mach test
21
- * launches. Detection stays advisory (warn-only) because a fork that
22
- * rebuilds out-of-band (a separate `./mach build` invocation, an IDE
23
- * plugin, etc.) can legitimately have a fresh `dist/` with no
24
- * FireForge-recorded baseline update.
18
+ * warning up-front so the operator sees "you edited X, Y, Z since the last
19
+ * build — rerun with `--build` to refresh" BEFORE mach test launches.
20
+ * Detection stays advisory (warn-only) because a fork that rebuilds
21
+ * out-of-band (a separate `./mach build` invocation, an IDE plugin) can
22
+ * legitimately have a fresh `dist/` with no FireForge-recorded baseline
23
+ * update.
25
24
  */
26
25
  import { toError } from '../utils/errors.js';
27
26
  import { verbose, warn } from '../utils/logger.js';
@@ -51,17 +50,16 @@ export async function checkStaleBuildForTest(projectRoot, engineDir) {
51
50
  let packageable = changed.filter((path) => isPackageablePath(path)).sort();
52
51
  // Content-hash comparison: when the baseline carries a fingerprint set,
53
52
  // fold each candidate path through a live re-hash and drop paths whose
54
- // current content matches the baseline. Pre-0.16.0 baselines have no
55
- // `packageableFingerprints` field; those fall through and the
56
- // path-only comparison behaves as before (every workdir-dirty
57
- // packageable path is reported as stale). The concrete motivating
58
- // case: a project with imported patches + Furnace-applied components
59
- // always has a persistent workdir diff against HEAD. Before the
60
- // fingerprint layer, `git diff --name-only HEAD` returned that diff
61
- // on every build, so the stale check fired immediately after a
62
- // successful build even though nothing had actually changed. The
63
- // fingerprints capture "these files had this content when the build
64
- // ran"; a path stays stale only when its live hash diverges.
53
+ // current content matches the baseline. Baselines without
54
+ // `packageableFingerprints` fall through to the path-only comparison,
55
+ // where every workdir-dirty packageable path reports as stale.
56
+ //
57
+ // This matters because a project with imported patches plus
58
+ // Furnace-applied components always has a persistent workdir diff against
59
+ // HEAD, so `git diff --name-only HEAD` returns that diff on every build
60
+ // and the stale check fires immediately after a successful one. The
61
+ // fingerprints capture "these files had this content when the build ran";
62
+ // a path stays stale only when its live hash diverges.
65
63
  const fingerprints = baseline.packageableFingerprints;
66
64
  if (fingerprints) {
67
65
  const staleAfterHashCheck = [];
@@ -105,16 +103,16 @@ export const FULL_SUITE_REQUEST = '(entire suite)';
105
103
  * packaging does NOT cover — the runs that would dispatch against missing
106
104
  * `_tests/` support fixtures and hang rather than fail.
107
105
  *
108
- * Coverage semantics: `undefined` (pre-0.37.0 baseline) and `'full'` cover
109
- * everything. A scoped list covers a request path when the request equals a
110
- * covered entry, sits beneath a covered directory entry, or shares a
111
- * manifest granule with a covered entry ({@link toManifestGranule} — a
112
- * scoped `test --build` packages the whole manifest directory, so a
113
- * same-manifest sibling of a covered file is packaged too). Both sides are
114
- * normalized to forward slashes so Windows-style CLI input cannot defeat
115
- * the prefix rule (baseline paths are POSIX by convention). A request with
116
- * no paths is a full-suite run and is never covered by a scoped list — the
117
- * {@link FULL_SUITE_REQUEST} sentinel is returned so the refusal can name it.
106
+ * Coverage semantics: an absent claim and `'full'` cover everything. A
107
+ * scoped list covers a request path when the request equals a covered entry,
108
+ * sits beneath a covered directory entry, or shares a manifest granule with
109
+ * a covered entry ({@link toManifestGranule} — a scoped `test --build`
110
+ * packages the whole manifest directory, so a same-manifest sibling of a
111
+ * covered file is packaged too). Both sides are normalized to forward
112
+ * slashes so Windows-style CLI input cannot defeat the prefix rule (baseline
113
+ * paths are POSIX by convention). A request with no paths is a full-suite
114
+ * run and is never covered by a scoped list — the {@link FULL_SUITE_REQUEST}
115
+ * sentinel is returned so the refusal can name it.
118
116
  */
119
117
  export function findUncoveredRequestPaths(coverage, requestedPaths) {
120
118
  if (coverage === undefined || coverage === 'full') {
@@ -167,8 +165,17 @@ export function formatTestCoverageRefusal(uncovered, coverage) {
167
165
  return head.join(', ') + (truncated > 0 ? `, … (+${truncated} more)` : '');
168
166
  };
169
167
  const rebuildTargets = uncovered.filter((p) => p !== FULL_SUITE_REQUEST);
168
+ // Name --extend-coverage here or it is undiscoverable: a scoped build
169
+ // REPLACES the claim, so under several concurrent sessions a peer's build
170
+ // for an unrelated path erases coverage you legitimately still hold, and
171
+ // the union that fixes it is a flag the operator has no reason to know
172
+ // exists at the moment they need it. The anchor conditions are stated
173
+ // because they are what decides whether it will work.
174
+ const extendHint = rebuildTargets.length > 0
175
+ ? ` Add --extend-coverage to that rebuild to UNION the new paths onto the recorded claim instead of replacing it — it holds while engine HEAD and engine/mozconfig are unchanged since the recorded build.`
176
+ : '';
170
177
  const rebuildHint = rebuildTargets.length > 0
171
- ? `Rerun "fireforge test --build ${rebuildTargets.slice(0, STALE_PATHS_LIMIT).join(' ')}" to package them, or run "fireforge build" for full coverage.`
178
+ ? `Rerun "fireforge test --build ${rebuildTargets.slice(0, STALE_PATHS_LIMIT).join(' ')}" to package them, or run "fireforge build" for full coverage.${extendHint}`
172
179
  : 'Run "fireforge build" (or a path-less "fireforge test --build") for full coverage first.';
173
180
  return (`The packaged test runtime was produced by a scoped "fireforge test --build" covering only: ${cap(coverage)}.\n` +
174
181
  `The requested run needs ${cap(uncovered)}, which that packaging does not cover — support ` +
@@ -180,17 +187,17 @@ export function formatTestCoverageRefusal(uncovered, coverage) {
180
187
  * Probes whether any `components.conf` changed since the last FULL
181
188
  * `fireforge build` — i.e. since the compiled StaticComponents table was
182
189
  * last regenerated. `components.conf` entries bake into compiled code; a
183
- * scoped `test --build` packages the file but the child process resolves
184
- * the OLD table and fails with `NS_ERROR_MALFORMED_URI` that reads as a
185
- * test bug.
190
+ * scoped `test --build` packages the file but the child process resolves the
191
+ * OLD table and fails with `NS_ERROR_MALFORMED_URI` that reads as a test
192
+ * bug.
186
193
  *
187
194
  * The diff anchors to the baseline's `staticComponentsBaseline` (the last
188
- * full build's engine HEAD SHA), NOT the baseline's own `engineHeadSha`
195
+ * full build's engine HEAD SHA), NOT the baseline's own `engineHeadSha`,
189
196
  * which a scoped `test --build` advances. Dirty candidates are hash-checked
190
197
  * against the anchor's fingerprints so only genuine content divergence
191
- * counts. No baseline / no anchor (pre-0.38.0 marker) → fresh. Never
192
- * throws — the probes it composes degrade to verbose lines and empty
193
- * results on git failure, matching {@link checkStaleBuildForTest}.
198
+ * counts. No baseline or no anchor means fresh. Never throws — the probes it
199
+ * composes degrade to verbose lines and empty results on git failure,
200
+ * matching {@link checkStaleBuildForTest}.
194
201
  */
195
202
  export async function checkStaticComponentsStale(engineDir, baseline) {
196
203
  const anchor = baseline?.staticComponentsBaseline;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Operator-facing triage for the `timed out … with no output` / `Ran 0
3
+ * checks` stall — the shape where the harness dies before ANY test output.
4
+ *
5
+ * Split out of `test-harness-crash.ts`, which CLASSIFIES runs; this module
6
+ * only renders advice about one already-classified shape. Keeping the two
7
+ * apart matters because the census below carries claims of unequal
8
+ * evidential strength, and the rules for editing it are not the rules for
9
+ * editing a classifier: a pattern in the classifier is either matched by
10
+ * the output or not, while a cause in the census is an assertion about the
11
+ * world that an operator will act on.
12
+ *
13
+ * Everything here is pure — the platform and the probed display state are
14
+ * injected, so unit tests need no mocking.
15
+ */
16
+ import type { DisplaySleepState } from './display-state.js';
17
+ import type { HarnessCrashSignature } from './test-harness-signature.js';
18
+ /**
19
+ * Optional hint appended to the harness-crash message when a HEADED run on
20
+ * macOS died at the no-output timeout.
21
+ *
22
+ * When `displayState` names a MEASURED display state, the hint states it as
23
+ * fact rather than as one of three possibilities — that is the point of
24
+ * probing: an operator staring at a bare test failure should not have to
25
+ * rediscover that their machine dimmed. `caffeinate` is described accurately
26
+ * (it prevents sleep; it cannot wake an already-sleeping display), so
27
+ * operators are not sent to a command that could not have helped them.
28
+ *
29
+ * Pure — the platform and the probed state are injected so unit tests need
30
+ * no mocking.
31
+ *
32
+ * @param signature - The recognized crash shape
33
+ * @param context - Run mode, platform, and the probed display state
34
+ * @returns The hint text, or undefined when the shape does not apply
35
+ */
36
+ export declare function headedNoOutputTimeoutHint(signature: HarnessCrashSignature, context: {
37
+ headless: boolean;
38
+ platform: string;
39
+ displayState?: DisplaySleepState;
40
+ }): string | undefined;
41
+ /**
42
+ * Verdict-line note for a headed no-output stall whose display was
43
+ * measured asleep. Returned as the parenthetical the verdict line carries,
44
+ * so the one greppable line an automated consumer reads already names the
45
+ * environmental cause instead of a bare `FAIL reason=crash`.
46
+ */
47
+ export declare function headedDisplayAsleepVerdictNote(signature: HarnessCrashSignature, context: {
48
+ headless: boolean;
49
+ platform: string;
50
+ displayState: DisplaySleepState;
51
+ }): string | undefined;
@@ -0,0 +1,126 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Operator-facing triage for the `timed out … with no output` / `Ran 0
4
+ * checks` stall — the shape where the harness dies before ANY test output.
5
+ *
6
+ * Split out of `test-harness-crash.ts`, which CLASSIFIES runs; this module
7
+ * only renders advice about one already-classified shape. Keeping the two
8
+ * apart matters because the census below carries claims of unequal
9
+ * evidential strength, and the rules for editing it are not the rules for
10
+ * editing a classifier: a pattern in the classifier is either matched by
11
+ * the output or not, while a cause in the census is an assertion about the
12
+ * world that an operator will act on.
13
+ *
14
+ * Everything here is pure — the platform and the probed display state are
15
+ * injected, so unit tests need no mocking.
16
+ */
17
+ /**
18
+ * First step for the `timed out … with no output` / `Ran 0 checks`
19
+ * signature, printed ABOVE the cause list. Running a known-good control
20
+ * separates "this test" from "this build" and is the correct opening move
21
+ * for EVERY cause below — it is not specific to any one of them, so
22
+ * attaching it to a single entry made reaching that entry informationally
23
+ * empty.
24
+ */
25
+ const NO_OUTPUT_STALL_CONTROL_STEP = 'First, run a known-good control test. If the control stalls too, the cause is not the test ' +
26
+ 'under investigation, and the list below applies to the build or the host.';
27
+ /**
28
+ * Recorded causes of the `timed out … with no output` / `Ran 0 checks`
29
+ * signature, each paired with the probe that DISCRIMINATES it from the
30
+ * others. Printed verbatim under the hint.
31
+ *
32
+ * Evidence per entry is deliberately unequal, and the text says so:
33
+ *
34
+ * - (1) is MEASURED — `probeDisplaySleepState` reads the display's power
35
+ * state, so the hint states it as fact rather than as a possibility.
36
+ * - (2) is discriminated by `--headless`.
37
+ * - (4) is MECHANICAL and was root-caused downstream: the harness serves
38
+ * its manifest from `server.js` on 8888, and a survivor of an
39
+ * interrupted run keeps the port. Its probe is exact, and the preflight
40
+ * in `mochitest-server-port.ts` now refuses it before a run starts.
41
+ * - (3) is a single downstream report (one consumer, 3/3 reproduce and 3/3
42
+ * restore on one variable) whose MECHANISM was never root-caused. It is
43
+ * stated as the correlation it is. An earlier revision asserted "stalls
44
+ * first paint" as fact; that was a causal story written on top of the
45
+ * correlation, and a doubtful one — a failed image load in Gecko fires
46
+ * `error` and does not gate the document load event, and the harness's
47
+ * browser-ready handshake does not wait on image decode. Do not restore
48
+ * a mechanism claim here without a root cause to cite.
49
+ *
50
+ * Detection (a named signature, as with the module-resolution SIGSEGV) is
51
+ * not specified for (3) because no log line is known to key on. The bar for
52
+ * adding one is the bar `mach-error-hints.ts` states: an established
53
+ * diagnosis, never a plausible guess.
54
+ */
55
+ const NO_OUTPUT_STALL_TRIAGE = [
56
+ ' 1. A sleeping or locked display on an unattended HEADED run (macOS). The browser never ' +
57
+ 'paints and never reaches its first test.',
58
+ ' 2. A headless SWGL compositor failure — re-run with --headless to separate this from (1): ' +
59
+ 'if --headless passes, the stall was display/compositor-side, not product-side.',
60
+ ' 3. Product-side startup: the browser never reaches the state the harness waits for. One ' +
61
+ 'downstream report correlates this stall with a broken `chrome://` image URI on the ' +
62
+ 'startup page (reproduced and un-reproduced on that one variable); the mechanism was ' +
63
+ 'never root-caused, so treat it as a lead, not an explanation. Discriminate with ' +
64
+ '"fireforge run --smoke-exit 60 --headless --capture-console <file>", which launches the ' +
65
+ 'same browser OUTSIDE the test harness: a clean window with no unallowed console errors ' +
66
+ 'means product-side startup is healthy and the stall is harness- or test-side; a hang, a ' +
67
+ 'non-zero exit, or console errors in <file> put it in the startup document.',
68
+ ' 4. A stale mochitest httpd holding the harness server port (127.0.0.1:8888). A fresh ' +
69
+ "browser connects to THAT server, which cannot serve this run's manifest, so the run " +
70
+ 'stalls before TEST_START. Probe with "lsof -nP -iTCP:8888": any listener that is not ' +
71
+ "this run's own is the cause. FireForge now refuses this at preflight, so it should " +
72
+ 'reach a stall only on a host where the port could not be probed.',
73
+ ];
74
+ /**
75
+ * Optional hint appended to the harness-crash message when a HEADED run on
76
+ * macOS died at the no-output timeout.
77
+ *
78
+ * When `displayState` names a MEASURED display state, the hint states it as
79
+ * fact rather than as one of three possibilities — that is the point of
80
+ * probing: an operator staring at a bare test failure should not have to
81
+ * rediscover that their machine dimmed. `caffeinate` is described accurately
82
+ * (it prevents sleep; it cannot wake an already-sleeping display), so
83
+ * operators are not sent to a command that could not have helped them.
84
+ *
85
+ * Pure — the platform and the probed state are injected so unit tests need
86
+ * no mocking.
87
+ *
88
+ * @param signature - The recognized crash shape
89
+ * @param context - Run mode, platform, and the probed display state
90
+ * @returns The hint text, or undefined when the shape does not apply
91
+ */
92
+ export function headedNoOutputTimeoutHint(signature, context) {
93
+ if (context.platform !== 'darwin' || context.headless)
94
+ return undefined;
95
+ if (!signature.reason.includes('no-output timeout'))
96
+ return undefined;
97
+ const lead = context.displayState === 'asleep'
98
+ ? 'Hint: this was a HEADED run on macOS and the display was MEASURED ASLEEP ' +
99
+ '(IODisplayWrangler below its awake power state). A headed browser on a sleeping ' +
100
+ 'display never paints and never starts a test, so this stall is environmental — not a ' +
101
+ 'product or test failure.'
102
+ : context.displayState === 'awake'
103
+ ? 'Hint: this was a HEADED run on macOS that died at the no-output timeout. The display ' +
104
+ 'was measured AWAKE, so the sleeping-display cause below is ruled out for this run.'
105
+ : 'Hint: this was a HEADED run on macOS that died at the no-output timeout. The display ' +
106
+ 'state could not be measured, so all three causes below remain open.';
107
+ const remedy = 'Note that `caffeinate -disu` PREVENTS sleep; it cannot WAKE a display that is already ' +
108
+ 'asleep. Wake the display (or run on an attended machine), or pass --headless.';
109
+ return (`${lead}\n\n${NO_OUTPUT_STALL_CONTROL_STEP}\n\n` +
110
+ `Known causes of this exact signature:\n${NO_OUTPUT_STALL_TRIAGE.join('\n')}\n\n${remedy}`);
111
+ }
112
+ /**
113
+ * Verdict-line note for a headed no-output stall whose display was
114
+ * measured asleep. Returned as the parenthetical the verdict line carries,
115
+ * so the one greppable line an automated consumer reads already names the
116
+ * environmental cause instead of a bare `FAIL reason=crash`.
117
+ */
118
+ export function headedDisplayAsleepVerdictNote(signature, context) {
119
+ if (context.platform !== 'darwin' || context.headless)
120
+ return undefined;
121
+ if (context.displayState !== 'asleep')
122
+ return undefined;
123
+ if (!signature.reason.includes('no-output timeout'))
124
+ return undefined;
125
+ return 'headed run stalled with the display asleep';
126
+ }
@@ -1,15 +1,13 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Category banner and token-declaration helpers for the tokens CSS file
4
- *. Split out of `token-manager.ts` to stay inside the per-file
5
- * line budget.
3
+ * Category banner and token-declaration helpers for the tokens CSS file.
4
+ * Split out of `token-manager.ts` to stay inside the per-file line budget.
6
5
  *
7
6
  * Banner matching is EXACT: the text between the `=` runs (single-line
8
7
  * shape) or on the block line (multi-line shape) must equal the category
9
- * after trimming. The pre-0.40.0 substring match let a TOC comment or a
10
- * longer banner (`Colors — Canvas` for `Colors`) satisfy the lookup, so
11
- * `token add` wrote into the wrong section — or no-oped for 19
12
- * consecutive calls — with exit 0.
8
+ * after trimming. A substring match lets a TOC comment or a longer banner
9
+ * (`Colors — Canvas` for `Colors`) satisfy the lookup, so `token add` writes
10
+ * into the wrong section — or no-ops — with exit 0.
13
11
  */
14
12
  import { join } from 'node:path';
15
13
  import { GeneralError } from '../errors/base.js';
@@ -7,17 +7,17 @@ import { countRawCssColors } from '../utils/regex.js';
7
7
  import { loadFurnaceConfig } from './furnace-config.js';
8
8
  /**
9
9
  * Default platform prefixes treated as allowlisted upstream vars. Any
10
- * `var(--moz-*)` usage in a fork's CSS is a Firefox platform variable
11
- * that the fork does not own and should not be counted as an unknown.
12
- * 2026-04-21 eval (Finding #5): a `furnace override moz-button -t
13
- * css-only` + one fork token produced 1% coverage because the 84
14
- * upstream `--moz-*` vars in the copied baseline counted as unknown.
10
+ * `var(--moz-*)` usage in a fork's CSS is a Firefox platform variable the
11
+ * fork does not own and must not count as an unknown — otherwise a
12
+ * `furnace override moz-button -t css-only` plus one fork token reports 1%
13
+ * coverage, because the ~84 upstream `--moz-*` vars in the copied baseline
14
+ * all count against it.
15
15
  *
16
16
  * Forks that want to opt out can override this via
17
- * `furnace.json.platformPrefixes = []`; forks that want more can
18
- * extend it (e.g. `['--moz-', '--in-content-']`). The config is
19
- * additive — nothing is removed from the defaults unless the operator
20
- * explicitly writes a shorter list.
17
+ * `furnace.json.platformPrefixes = []`; forks that want more can extend it
18
+ * (e.g. `['--moz-', '--in-content-']`). The config is additive — nothing is
19
+ * removed from the defaults unless the operator explicitly writes a shorter
20
+ * list.
21
21
  */
22
22
  const DEFAULT_PLATFORM_PREFIXES = ['--moz-'];
23
23
  /**
@@ -1,17 +1,15 @@
1
1
  /**
2
2
  * Dark-mode insertion helpers for the tokens CSS scaffold.
3
3
  *
4
- * The 2026-04-21 eval reproduced a bug where `fireforge token add
5
- * --mode override --dark-value ...` landed the dark declaration
6
- * AFTER the nested `:root { }` inside the
7
- * `@media (prefers-color-scheme: dark)` block had already closed,
8
- * producing a declaration outside any rule block. The helpers here
9
- * scan the comment-stripped source lines to find the *inner* `:root`
10
- * block's closing `}` and return a line index the caller can splice
11
- * into. When the inner `:root` is missing (a scaffold that drifted
12
- * from the default), the fallback helper returns the outer `@media`
13
- * block's close so the caller can materialise a fresh `:root` wrapper
14
- * rather than dropping the dark value.
4
+ * `fireforge token add --mode override --dark-value ...` must land the dark
5
+ * declaration INSIDE the nested `:root { }` of the
6
+ * `@media (prefers-color-scheme: dark)` block; landing after that block has
7
+ * closed produces a declaration outside any rule. The helpers here scan the
8
+ * comment-stripped source lines to find the *inner* `:root` block's closing
9
+ * `}` and return a line index the caller can splice into. When the inner
10
+ * `:root` is missing (a scaffold that drifted from the default), the
11
+ * fallback helper returns the outer `@media` block's close so the caller can
12
+ * materialise a fresh `:root` wrapper rather than dropping the dark value.
15
13
  */
16
14
  /**
17
15
  * Strips the content of `/* ... *\/` block comments from an array of
@@ -2,17 +2,15 @@
2
2
  /**
3
3
  * Dark-mode insertion helpers for the tokens CSS scaffold.
4
4
  *
5
- * The 2026-04-21 eval reproduced a bug where `fireforge token add
6
- * --mode override --dark-value ...` landed the dark declaration
7
- * AFTER the nested `:root { }` inside the
8
- * `@media (prefers-color-scheme: dark)` block had already closed,
9
- * producing a declaration outside any rule block. The helpers here
10
- * scan the comment-stripped source lines to find the *inner* `:root`
11
- * block's closing `}` and return a line index the caller can splice
12
- * into. When the inner `:root` is missing (a scaffold that drifted
13
- * from the default), the fallback helper returns the outer `@media`
14
- * block's close so the caller can materialise a fresh `:root` wrapper
15
- * rather than dropping the dark value.
5
+ * `fireforge token add --mode override --dark-value ...` must land the dark
6
+ * declaration INSIDE the nested `:root { }` of the
7
+ * `@media (prefers-color-scheme: dark)` block; landing after that block has
8
+ * closed produces a declaration outside any rule. The helpers here scan the
9
+ * comment-stripped source lines to find the *inner* `:root` block's closing
10
+ * `}` and return a line index the caller can splice into. When the inner
11
+ * `:root` is missing (a scaffold that drifted from the default), the
12
+ * fallback helper returns the outer `@media` block's close so the caller can
13
+ * materialise a fresh `:root` wrapper rather than dropping the dark value.
16
14
  */
17
15
  /**
18
16
  * Strips the content of `/* ... *\/` block comments from an array of
@@ -21,6 +21,8 @@ export interface TokenDocInput {
21
21
  * against a freshly parsed view of the document so that splice indices
22
22
  * stay valid as rewrites are layered.
23
23
  *
24
+ * @param engineDir - Absolute path to the engine checkout
25
+ * @param options - Token name, category and description to document
24
26
  * @param annotation - The mode annotation string the caller already computed
25
27
  * (kept here as a parameter so this module needs no dependency on
26
28
  * token-manager's `getModeAnnotation`).
@@ -26,6 +26,8 @@ function stripInlineCode(cell) {
26
26
  * against a freshly parsed view of the document so that splice indices
27
27
  * stay valid as rewrites are layered.
28
28
  *
29
+ * @param engineDir - Absolute path to the engine checkout
30
+ * @param options - Token name, category and description to document
29
31
  * @param annotation - The mode annotation string the caller already computed
30
32
  * (kept here as a parameter so this module needs no dependency on
31
33
  * token-manager's `getModeAnnotation`).
@@ -1,8 +1,16 @@
1
1
  import { type TokenDeclarationLocation } from './token-category.js';
2
2
  /**
3
- * Dark mode behavior for a token.
3
+ * Dark mode behaviour for a token.
4
+ *
5
+ * Derived from {@link TOKEN_MODES} so the runtime allowlist and the type
6
+ * cannot drift: adding a member here without updating the list (or the
7
+ * reverse) is no longer possible, because there is only one list.
4
8
  */
5
- export type TokenMode = 'auto' | 'static' | 'override';
9
+ export declare const TOKEN_MODES: readonly ["auto", "static", "override"];
10
+ /** Dark mode behaviour for a token. */
11
+ export type TokenMode = (typeof TOKEN_MODES)[number];
12
+ /** Narrows an arbitrary string to a {@link TokenMode}. */
13
+ export declare const isTokenMode: (value: string) => value is "override" | "auto" | "static";
6
14
  /**
7
15
  * Options for adding a token.
8
16
  */
@@ -5,13 +5,23 @@ import { FurnaceError } from '../errors/furnace.js';
5
5
  import { toError } from '../utils/errors.js';
6
6
  import { pathExists, readText, writeText } from '../utils/fs.js';
7
7
  import { info, warn } from '../utils/logger.js';
8
- import { validateTokenName } from '../utils/validation.js';
8
+ import { describeTokenNameProblem, makeEnumGuard } from '../utils/validation.js';
9
9
  import { getProjectPaths, loadConfig } from './config.js';
10
10
  import { loadFurnaceConfig } from './furnace-config.js';
11
11
  import { assertTokenCategoryExists, categoryHeaderExists, declareCategoryBanner, findCategorySection, findTokenDeclarationInRoot, } from './token-category.js';
12
12
  import { findDarkMediaCloseIndex, findDarkRootInsertionIndex } from './token-dark-mode.js';
13
13
  import { addTokenToDocs } from './token-docs.js';
14
14
  import { insertVariantDeclaration, validateVariantSelector, variantBlockExists, variantBlockHasToken, } from './token-variant.js';
15
+ /**
16
+ * Dark mode behaviour for a token.
17
+ *
18
+ * Derived from {@link TOKEN_MODES} so the runtime allowlist and the type
19
+ * cannot drift: adding a member here without updating the list (or the
20
+ * reverse) is no longer possible, because there is only one list.
21
+ */
22
+ export const TOKEN_MODES = ['auto', 'static', 'override'];
23
+ /** Narrows an arbitrary string to a {@link TokenMode}. */
24
+ export const isTokenMode = makeEnumGuard(TOKEN_MODES);
15
25
  /** Returns the token CSS path relative to engine root for a given binary name. */
16
26
  export function getTokensCssPath(binaryName) {
17
27
  return `browser/themes/shared/${binaryName}-tokens.css`;
@@ -59,7 +69,7 @@ async function validateTokenPrefix(root, options) {
59
69
  }
60
70
  }
61
71
  function validateTokenNameSyntax(tokenName) {
62
- const error = validateTokenName(tokenName);
72
+ const error = describeTokenNameProblem(tokenName);
63
73
  if (error) {
64
74
  throw new InvalidArgumentError(error, 'tokenName');
65
75
  }
@@ -117,11 +127,10 @@ async function addVariantTokenToCSS(engineDir, options, tokensCssPath, variant)
117
127
  return { added: true };
118
128
  }
119
129
  /**
120
- * Evaluates base-`:root` idempotency for one add: a token
121
- * already declared in the TARGET category skips; a token declared
122
- * anywhere else in the base block refuses loud — the pre-0.40.0
123
- * whole-file substring check silently skipped (and discarded
124
- * `--create-category`) in that case, exit 0.
130
+ * Evaluates base-`:root` idempotency for one add: a token already declared
131
+ * in the TARGET category skips; a token declared anywhere else in the base
132
+ * block refuses loud. A whole-file substring check instead skips silently —
133
+ * discarding `--create-category` — and exits 0.
125
134
  */
126
135
  function evaluateBaseTokenIdempotency(lines, options, tokensCssPath) {
127
136
  const existing = findTokenDeclarationInRoot(lines, options.tokenName);
@@ -241,7 +250,7 @@ export async function addToken(root, options) {
241
250
  * pair the media query with `:root[data-theme="dark"]` /
242
251
  * `:root[data-theme="light"]` blocks (viewer-toggle theming) require every
243
252
  * themed list to declare identical token sets, so an override add that only
244
- * wrote the media block was a guaranteed half-finished edit.
253
+ * wrote the media block would be a guaranteed half-finished edit.
245
254
  */
246
255
  const THEME_ATTRIBUTE_VARIANTS = [
247
256
  { variant: '[data-theme="dark"]', pick: 'dark' },
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * Scaffolds the default tokens CSS file consumed by `fireforge token add`.
3
3
  *
4
- * Before 0.16.0 `fireforge furnace init` wrote `furnace.json` but not the
5
- * tokens CSS — every project's first `fireforge token add` hit
4
+ * Without it, `fireforge furnace init` writes `furnace.json` but not the
5
+ * tokens CSS, and every project's first `fireforge token add` hits
6
6
  * `Token CSS file not found: browser/themes/shared/<binaryName>-tokens.css`.
7
- * The 0.16.0 init now calls into this module to write a canonical
8
- * `:root { … }` shell with a seed set of category headers that
9
- * `assertTokenCategoryExists` recognises, and registers the tokens CSS
10
- * path in `patchLint.rawColorAllowlist` so the first token that's an
11
- * actual color value does not instantly fail `fireforge lint`.
7
+ * Init calls into this module to write a canonical `:root { … }` shell with
8
+ * a seed set of category headers that `assertTokenCategoryExists`
9
+ * recognises, and registers the tokens CSS path in
10
+ * `patchLint.rawColorAllowlist` so the first token that is an actual color
11
+ * value does not instantly fail `fireforge lint`.
12
12
  */
13
13
  import type { ProjectLicense } from '../types/config.js';
14
14
  /**
@@ -2,14 +2,14 @@
2
2
  /**
3
3
  * Scaffolds the default tokens CSS file consumed by `fireforge token add`.
4
4
  *
5
- * Before 0.16.0 `fireforge furnace init` wrote `furnace.json` but not the
6
- * tokens CSS — every project's first `fireforge token add` hit
5
+ * Without it, `fireforge furnace init` writes `furnace.json` but not the
6
+ * tokens CSS, and every project's first `fireforge token add` hits
7
7
  * `Token CSS file not found: browser/themes/shared/<binaryName>-tokens.css`.
8
- * The 0.16.0 init now calls into this module to write a canonical
9
- * `:root { … }` shell with a seed set of category headers that
10
- * `assertTokenCategoryExists` recognises, and registers the tokens CSS
11
- * path in `patchLint.rawColorAllowlist` so the first token that's an
12
- * actual color value does not instantly fail `fireforge lint`.
8
+ * Init calls into this module to write a canonical `:root { … }` shell with
9
+ * a seed set of category headers that `assertTokenCategoryExists`
10
+ * recognises, and registers the tokens CSS path in
11
+ * `patchLint.rawColorAllowlist` so the first token that is an actual color
12
+ * value does not instantly fail `fireforge lint`.
13
13
  */
14
14
  import { getLicenseHeader } from './license-headers.js';
15
15
  /**
@@ -2,10 +2,10 @@
2
2
  * Attribute-variant block helpers for the tokens CSS scaffold.
3
3
  *
4
4
  * `fireforge token add --mode` can author the base `:root { }` block and the
5
- * dark `@media (prefers-color-scheme: dark)` block, but there was no way to
6
- * target an attribute-keyed selector such as `:root[data-skin="precision"]`
7
- * or `:root[data-private]` — forcing those override blocks to be hand-edited.
8
- * These helpers locate (or compute the insertion point for) a top-level
5
+ * dark `@media (prefers-color-scheme: dark)` block, but not an
6
+ * attribute-keyed selector such as `:root[data-skin="precision"]` or
7
+ * `:root[data-private]`, which would otherwise have to be hand-edited. These
8
+ * helpers locate (or compute the insertion point for) a top-level
9
9
  * `:root<variant>` block so `token-manager.ts` can splice a declaration into
10
10
  * it, keeping all token authoring in the CLI.
11
11
  */
@@ -3,10 +3,10 @@
3
3
  * Attribute-variant block helpers for the tokens CSS scaffold.
4
4
  *
5
5
  * `fireforge token add --mode` can author the base `:root { }` block and the
6
- * dark `@media (prefers-color-scheme: dark)` block, but there was no way to
7
- * target an attribute-keyed selector such as `:root[data-skin="precision"]`
8
- * or `:root[data-private]` — forcing those override blocks to be hand-edited.
9
- * These helpers locate (or compute the insertion point for) a top-level
6
+ * dark `@media (prefers-color-scheme: dark)` block, but not an
7
+ * attribute-keyed selector such as `:root[data-skin="precision"]` or
8
+ * `:root[data-private]`, which would otherwise have to be hand-edited. These
9
+ * helpers locate (or compute the insertion point for) a top-level
10
10
  * `:root<variant>` block so `token-manager.ts` can splice a declaration into
11
11
  * it, keeping all token authoring in the CLI.
12
12
  */