@hominis/fireforge 0.43.0 → 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 +127 -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 +62 -19
  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
@@ -1,19 +1,17 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * `fireforge typecheck` — whole-project TypeScript type checking
4
- * driven by user-supplied jsconfig.json paths.
3
+ * `fireforge typecheck` — whole-project TypeScript type checking driven by
4
+ * user-supplied jsconfig.json paths.
5
5
  *
6
- * Distinct from `patchLint.checkJs`: that pass is patch-hygiene
7
- * (scoped to patch-owned `.sys.mjs`, run automatically by
8
- * `fireforge lint`); this command is CI-grade — it runs whole
9
- * projects with the user's own compiler options and is intended as
10
- * a CI gate. The two share their Firefox-globals shim and the same
11
- * suppressed-diagnostic set so a file that lints clean cannot fail
12
- * typecheck for a reason the operator could not have inferred from
13
- * the docs.
6
+ * Distinct from `patchLint.checkJs`: that pass is patch-hygiene (scoped to
7
+ * patch-owned `.sys.mjs`, run automatically by `fireforge lint`); this
8
+ * command is CI-grade — it runs whole projects with the user's own compiler
9
+ * options. The two share their Firefox-globals shim and the same
10
+ * suppressed-diagnostic set so a file that lints clean cannot fail typecheck
11
+ * for a reason the operator could not have inferred from the docs.
14
12
  *
15
- * Exits non-zero on any error-severity diagnostic. Warnings print
16
- * but do not fail. Designed for CI use.
13
+ * Exits non-zero on any error-severity diagnostic. Warnings print but do not
14
+ * fail.
17
15
  */
18
16
  import { Command } from 'commander';
19
17
  import { getProjectPaths, loadConfig } from '../core/config.js';
@@ -22,7 +20,7 @@ import { findJsconfigPathsDrift, syncFurnaceJsconfigPaths } from '../core/furnac
22
20
  import { withPrivateGitIndex } from '../core/git-readonly-index.js';
23
21
  import { buildPatchQueueContext } from '../core/patch-lint.js';
24
22
  import { relativeForDisplay, runTypecheck } from '../core/typecheck.js';
25
- import { GeneralError } from '../errors/base.js';
23
+ import { GeneralError, InvalidArgumentError } from '../errors/base.js';
26
24
  import { pathExists } from '../utils/fs.js';
27
25
  import { info, intro, outro, success, warn } from '../utils/logger.js';
28
26
  import { buildPerRunCheckJs } from './lint-per-run-checkjs.js';
@@ -34,7 +32,7 @@ import { buildPerRunCheckJs } from './lint-per-run-checkjs.js';
34
32
  export function resolveTypecheckProjects(configTypecheck, override) {
35
33
  if (override !== undefined) {
36
34
  if (override.trim() === '') {
37
- throw new GeneralError('--project requires a non-empty path');
35
+ throw new InvalidArgumentError('--project requires a non-empty path', '--project');
38
36
  }
39
37
  return {
40
38
  projects: [override],
@@ -69,8 +67,8 @@ function formatIssue(projectRoot, issue) {
69
67
  */
70
68
  export async function typecheckCommand(projectRoot, options) {
71
69
  intro('FireForge typecheck');
72
- // Read-only to the operator, an index WRITER to git without this scope
73
- //: the Furnace jsconfig reconciler and the project resolution
70
+ // Read-only to the operator, an index WRITER to git without this scope:
71
+ // the Furnace jsconfig reconciler and the project resolution
74
72
  // below touch `engine/`, and any git plumbing they reach would refresh
75
73
  // the primary checkout's index under a concurrent `fireforge test`.
76
74
  return withPrivateGitIndex(getProjectPaths(projectRoot).engine, () => runTypecheckCommandBody(projectRoot, options));
@@ -84,10 +82,9 @@ async function runTypecheckCommandBody(projectRoot, options) {
84
82
  const config = await loadConfig(projectRoot);
85
83
  const cfg = resolveTypecheckProjects(config.typecheck, options.project);
86
84
  // Regenerate a stale Furnace-managed jsconfig before running: the generated
87
- // `compilerOptions.paths` shim drifts when components are added/renamed
85
+ // `compilerOptions.paths` shim drifts when components are added or renamed
88
86
  // without a re-deploy, and a stale shim reports type errors in files the
89
- // session never touched (e.g. 47 phantom errors from an out-of-date
90
- // chrome-module mapping). Run the same reconciler `furnace deploy`/`sync`
87
+ // session never touched. Run the same reconciler `furnace deploy`/`sync`
91
88
  // use so typecheck checks against the current workspace.
92
89
  await regenerateStaleGeneratedJsconfig(projectRoot);
93
90
  info(`Running typecheck across ${String(cfg.projects.length)} project(s): ${cfg.projects.join(', ')}`);
@@ -95,11 +92,11 @@ async function runTypecheckCommandBody(projectRoot, options) {
95
92
  // Fold the EXPORT-TIME authority into this pass. Per-patch lint runs
96
93
  // checkJs over the queue's patch-owned modules in relative isolation and
97
94
  // resolves imported typedefs differently from the whole-project pass, so
98
- // `typecheck` could report 0 errors across every
99
- // project while the very next `export` failed per-patch lint with
100
- // `checkjs-type-error` findings. Two authorities that disagree, with the
101
- // stricter one speaking only at export time, is not a usable CI gate:
102
- // running both here makes `typecheck` green MEAN export-clean types.
95
+ // `typecheck` can report 0 errors across every project while the very next
96
+ // `export` fails per-patch lint with `checkjs-type-error` findings. Two
97
+ // authorities that disagree, with the stricter one speaking only at export
98
+ // time, is not a usable CI gate: running both here makes `typecheck` green
99
+ // MEAN export-clean types.
103
100
  const patchIssues = await collectPatchLintCheckJsIssues(projectRoot);
104
101
  reportResults(projectRoot, results, patchIssues);
105
102
  }
@@ -154,9 +151,9 @@ async function regenerateStaleGeneratedJsconfig(projectRoot) {
154
151
  export function reportResults(projectRoot, results, patchLintIssues = []) {
155
152
  let totalErrors = 0;
156
153
  let totalWarnings = 0;
157
- // Per-patch checkJs findings are reported in the SAME tally:
158
- // a split report would let an operator read "0 errors" off the project
159
- // summary and still be refused at export.
154
+ // Per-patch checkJs findings are reported in the SAME tally: a split
155
+ // report would let an operator read "0 errors" off the project summary
156
+ // and still be refused at export.
160
157
  for (const issue of patchLintIssues) {
161
158
  if (issue.severity === 'error')
162
159
  totalErrors += 1;
@@ -42,12 +42,12 @@ import { info, intro, outro, success, warn } from '../utils/logger.js';
42
42
  * install time.
43
43
  */
44
44
  async function detectDanglingRegistrations(patchesDir, engineDir, patches) {
45
- // Aggregate the set of all paths that any patch in the queue is
46
- // responsible for (per `filesAffected`). We deliberately do NOT parse
47
- // individual patch bodies for new-file creations here: `filesAffected`
48
- // is already the contract manifest callers rely on, and
49
- // `validatePatchesManifestConsistency` has already ensured the two
50
- // are in sync. Using that list keeps this validator fast.
45
+ // Aggregate the set of all paths any patch in the queue is responsible for
46
+ // (per `filesAffected`). Individual patch bodies are deliberately NOT
47
+ // parsed for new-file creations here: `filesAffected` is already the
48
+ // contract manifest callers rely on, and
49
+ // `validatePatchesManifestConsistency` has already ensured the two are in
50
+ // sync. Using that list keeps this validator fast.
51
51
  const coveredByPatches = new Set();
52
52
  for (const patch of patches) {
53
53
  for (const file of patch.filesAffected) {
@@ -74,12 +74,11 @@ async function detectDanglingRegistrations(patchesDir, engineDir, patches) {
74
74
  for (const ref of refs) {
75
75
  if (coveredByPatches.has(ref.targetPath))
76
76
  continue;
77
- // Engine existence check: if the target file is already present
78
- // in engine/ (e.g. upstream Firefox ships it, or a separate
79
- // baseline branch has it), the registration is not dangling.
80
- // We cannot sanely probe "is this tracked by git" without a git
81
- // round-trip; existence on disk is a close-enough proxy for
82
- // verify's read-only context.
77
+ // Engine existence check: if the target file is already present in
78
+ // engine/ (upstream Firefox ships it, or a separate baseline branch
79
+ // has it), the registration is not dangling. "Is this tracked by git"
80
+ // cannot be probed without a git round-trip; existence on disk is a
81
+ // close-enough proxy for verify's read-only context.
83
82
  if (await pathExists(join(engineDir, ref.targetPath)))
84
83
  continue;
85
84
  issues.push({
@@ -171,9 +170,8 @@ export async function collectPatchQueueHealth(projectRoot) {
171
170
  }
172
171
  // Engine-aware module-resolution preflight. The queue-level
173
172
  // `unregistered-system-module` rule only sees modules a patch NEWLY
174
- // CREATES; this asks the same question of the engine, so an import
175
- // ADDED to an existing module — the shape that recurred and cost a
176
- // rebuild cycle — is named as text instead of surfacing later as a
173
+ // CREATES; this asks the same question of the engine, so an import ADDED
174
+ // to an existing module is named as text instead of surfacing later as a
177
175
  // bare `xpcshell return code: -11` with zero output.
178
176
  if (await pathExists(paths.engine)) {
179
177
  const unresolved = await findUnresolvedSystemModuleImports(paths.engine, manifest.patches.flatMap((patch) => patch.filesAffected));
@@ -2,13 +2,13 @@
2
2
  import { delimiter, dirname } from 'node:path';
3
3
  import { Command } from 'commander';
4
4
  import { getProjectPaths, loadConfig } from '../core/config.js';
5
+ import { assertEngineExists } from '../core/engine-precondition.js';
5
6
  import { warnIfFurnaceStale } from '../core/furnace-staleness.js';
6
7
  import { generateMozconfig, hasBuildArtifacts, hasRunnableBundle, watchWithOutput, } from '../core/mach.js';
7
8
  import { assertBuildArtifacts } from '../core/mach-build-artifacts.js';
8
9
  import { GeneralError } from '../errors/base.js';
9
10
  import { BuildError } from '../errors/build.js';
10
11
  import { toError } from '../utils/errors.js';
11
- import { pathExists } from '../utils/fs.js';
12
12
  import { info, intro, outro, spinner, verbose } from '../utils/logger.js';
13
13
  import { exec, findExecutable } from '../utils/process.js';
14
14
  const WATCHMAN_PROBE_TIMEOUT_MS = 5000;
@@ -56,15 +56,18 @@ function buildWatchmanConfigureTimeMessage() {
56
56
  return ('Watch mode cannot use the current obj-* build because watchman was not available when Firefox was configured.\n\n' +
57
57
  'Install watchman, delete the current obj-* directory, run "fireforge build" again, then retry "fireforge watch".');
58
58
  }
59
+ function hasWatchPermissionFailure(output) {
60
+ return /Operation not permitted|EPERM|EACCES/i.test(output);
61
+ }
59
62
  /**
60
63
  * Builds the generic unsupported-watch failure message.
64
+ *
61
65
  * @param exitCode - Exit code returned by `mach watch`
62
- * @param watchmanPath - Optional absolute path to the resolved watchman binary; surfaced in the guidance so the operator can see whether FireForge actually found one.
66
+ * @param watchmanPath - Optional absolute path to the resolved watchman
67
+ * binary; surfaced in the guidance so the operator can see whether
68
+ * FireForge actually found one.
63
69
  * @returns User-facing failure guidance
64
70
  */
65
- function hasWatchPermissionFailure(output) {
66
- return /Operation not permitted|EPERM|EACCES/i.test(output);
67
- }
68
71
  function buildUnsupportedWatchMessage(exitCode, watchmanPath, output = '') {
69
72
  const watchmanLine = watchmanPath
70
73
  ? ` - FireForge resolved watchman at ${watchmanPath} and prepended its directory to the mach subprocess PATH. If mach still did not see it, ensure that path is stable between runs.\n`
@@ -101,18 +104,14 @@ export async function watchCommand(projectRoot) {
101
104
  const config = await loadConfig(projectRoot);
102
105
  const paths = getProjectPaths(projectRoot);
103
106
  // Check if engine exists
104
- if (!(await pathExists(paths.engine))) {
105
- throw new GeneralError('Firefox source not found. Run "fireforge download" first.');
106
- }
107
- // Resolve the watchman binary to an absolute path up-front so we can
108
- // (a) refuse fast when it is missing AND (b) prepend its directory to
109
- // the mach subprocess PATH. 2026-04-24 eval Finding 12: on macOS,
110
- // `which watchman` from the interactive shell returns
111
- // `/opt/homebrew/bin/watchman`, but the Node subprocess PATH
112
- // frequently omits `/opt/homebrew/bin`, so the shell probe passed and
113
- // mach's `watch-project` call then timed out because its own PATH
114
- // lookup for watchman failed. Threading the directory through the
115
- // subprocess env fixes it.
107
+ await assertEngineExists(paths.engine);
108
+ // Resolve the watchman binary to an absolute path up-front so we can (a)
109
+ // refuse fast when it is missing AND (b) prepend its directory to the mach
110
+ // subprocess PATH. On macOS, `which watchman` from an interactive shell
111
+ // returns `/opt/homebrew/bin/watchman`, but the Node subprocess PATH
112
+ // frequently omits `/opt/homebrew/bin` — so the shell probe passes and
113
+ // mach's `watch-project` call then times out on its own failed PATH
114
+ // lookup. Threading the directory through the subprocess env fixes it.
116
115
  const watchmanPath = await findExecutable('watchman');
117
116
  if (!watchmanPath) {
118
117
  throw new GeneralError('Watch mode requires watchman to be installed and available in PATH.\n\n' +
@@ -166,12 +165,11 @@ export async function watchCommand(projectRoot) {
166
165
  info('Starting watch mode...');
167
166
  info('Press Ctrl+C to stop\n');
168
167
  // Compose the subprocess env: start from the parent process env, then
169
- // prepend the resolved watchman directory to PATH so the mach
170
- // subprocess sees the same binary our probe just validated. Without
171
- // this, a watchman install on `/opt/homebrew/bin` (the default
172
- // homebrew prefix on Apple Silicon) is absent from the PATH Node
173
- // inherits on spawn, and `mach watch` fails at the `watch-project`
174
- // subscription step.
168
+ // prepend the resolved watchman directory to PATH so the mach subprocess
169
+ // sees the same binary the probe just validated. Without it, a watchman
170
+ // install under `/opt/homebrew/bin` is absent from the PATH Node inherits
171
+ // on spawn and `mach watch` fails at the `watch-project` subscription
172
+ // step.
175
173
  const watchmanDir = dirname(watchmanPath);
176
174
  const existingPath = process.env['PATH'] ?? '';
177
175
  const pathSegments = existingPath.split(delimiter).filter((segment) => segment.length > 0);
@@ -19,10 +19,9 @@ function printWireDryRun(engineDir, name, subscriptDir, domFilePath, domTargetPa
19
19
  info(` source: ${subscriptDir}/${name}.js`);
20
20
  info(` browser-main.js: loadSubScript("chrome://browser/content/${name}.js")`);
21
21
  if (options.init) {
22
- // Show the coerced form so the preview matches the emitted block.
23
- // Before 0.16.0 the preview echoed the raw input ("EvalStartup.init"),
24
- // which did not reflect that the real run writes `EvalStartup.init();`
25
- // to browser-init.js.
22
+ // Show the coerced form so the preview matches the emitted block —
23
+ // echoing the raw input ("X.init") does not reflect that the real run
24
+ // writes `X.init();` to browser-init.js.
26
25
  info(` browser-init.js: ${coerceToCall(options.init)}`);
27
26
  }
28
27
  if (options.destroy) {
@@ -85,14 +84,13 @@ function validateWireName(name) {
85
84
  }
86
85
  }
87
86
  /**
88
- * Asserts that the resolved chrome document both exists on disk AND
89
- * exposes an insertion anchor (`#include browser-sets.inc` or
90
- * `<html:body>`) that `addDomFragment` can splice into. Fires the same
91
- * check in dry-run and real-run mode, so the preview and execution
92
- * agree on whether the target is wireable before any disk mutations
93
- * happen. Before 0.16.0 this check only ran on the real branch, which
94
- * let the dry-run produce a plausible-looking plan that the real run
95
- * then refused with `Could not find insertion point in chrome document`.
87
+ * Asserts that the resolved chrome document both exists on disk AND exposes
88
+ * an insertion anchor (`#include browser-sets.inc` or `<html:body>`) that
89
+ * `addDomFragment` can splice into. Fires in dry-run and real-run mode
90
+ * alike, so the preview and execution agree on whether the target is
91
+ * wireable before any disk mutations happen. Running it only on the real
92
+ * branch lets the dry-run produce a plausible-looking plan the real run then
93
+ * refuses with `Could not find insertion point in chrome document`.
96
94
  */
97
95
  async function assertDomTargetIsWireable(projectRoot, domFilePath, domTargetPath) {
98
96
  const paths = getProjectPaths(projectRoot);
@@ -151,37 +149,35 @@ async function ensureSubscriptSourceExists(projectRoot, subscriptDir, name, dryR
151
149
  * engine/. Returns undefined when `--dom` was not supplied.
152
150
  */
153
151
  async function resolveDomFragmentPath(projectRoot, dom) {
154
- // Validate DOM fragment file exists and compute path relative to engine root.
155
- //
156
- // Accepts three shapes:
152
+ // Validate the DOM fragment file exists and compute its path relative to
153
+ // the engine root. Accepts three shapes:
157
154
  // - Absolute paths (`/project/engine/browser/base/content/foo.inc.xhtml`)
158
155
  // - Repo-root-relative forms (`engine/browser/base/content/foo.inc.xhtml`)
159
156
  // - Engine-relative forms (`browser/base/content/foo.inc.xhtml`)
160
157
  //
161
- // Before the engine-prefix normalization, passing an `engine/…`-prefixed
162
- // relative path from the repo root double-rooted through
163
- // `toRootRelativePath(engineDir, …)` — `resolve(engineDir, 'engine/…')`
164
- // landed at `engineDir/engine/…`, which is still "inside" engineDir but
165
- // named as a second-level `engine/…` entry. The computed `#include`
166
- // then read `../../../engine/browser/base/content/foo.inc.xhtml`,
167
- // packaging-breaking nonsense. For absolute inputs this pre-existing
168
- // contract was fine — `toRootRelativePath` handles absolute candidates
169
- // correctly — so we only strip the prefix when the input is relative.
158
+ // Without the engine-prefix normalization, an `engine/…`-prefixed relative
159
+ // path from the repo root double-roots through
160
+ // `toRootRelativePath(engineDir, …)`: `resolve(engineDir, 'engine/…')`
161
+ // lands at `engineDir/engine/…`, still "inside" engineDir but named as a
162
+ // second-level `engine/…` entry, and the computed `#include` then reads
163
+ // `../../../engine/browser/base/content/foo.inc.xhtml`. Absolute inputs are
164
+ // already handled correctly by `toRootRelativePath`, so the prefix is only
165
+ // stripped when the input is relative.
170
166
  if (!dom)
171
167
  return undefined;
172
168
  {
173
169
  const paths = getProjectPaths(projectRoot);
174
170
  const domCandidate = isExplicitAbsolutePath(dom) ? dom : stripEnginePrefix(dom);
175
- // `pathExists` resolves relative paths against CWD, so an engine-
176
- // relative `domCandidate` (e.g. `browser/base/content/foo.inc.xhtml`)
177
- // would be probed inside the operator's shell directory rather than
178
- // the engine root and fail "DOM fragment file not found" even when
179
- // the file is sitting at engine/<path>. Mirror `register.ts`: probe
180
- // the absolute path as-is, otherwise join with `paths.engine` first.
181
- // The `isPathInsideRoot` / `toRootRelativePath` calls below keep
182
- // operating on `domCandidate` because they internally resolve
183
- // relative candidates against the engine root, which matches the
184
- // probe path we just built.
171
+ // `pathExists` resolves relative paths against CWD, so an
172
+ // engine-relative `domCandidate` (e.g.
173
+ // `browser/base/content/foo.inc.xhtml`) would be probed inside the
174
+ // operator's shell directory rather than the engine root and fail "DOM
175
+ // fragment file not found" even when the file is sitting at
176
+ // engine/<path>. Mirror `register.ts`: probe the absolute path as-is,
177
+ // otherwise join with `paths.engine` first. The `isPathInsideRoot` /
178
+ // `toRootRelativePath` calls below keep operating on `domCandidate`
179
+ // because they internally resolve relative candidates against the engine
180
+ // root, matching the probe path built here.
185
181
  const domProbePath = isExplicitAbsolutePath(domCandidate)
186
182
  ? domCandidate
187
183
  : join(paths.engine, domCandidate);
@@ -281,15 +277,11 @@ export async function wireCommand(projectRoot, name, options = {}) {
281
277
  // --after and have it forwarded unchanged to the lookup layer.
282
278
  validateWireName(options.after);
283
279
  }
284
- // Validate init/destroy expressions BEFORE the dry-run/real fork so
285
- // both paths enforce the same contract. Pre-0.16.0, validation only
286
- // ran inside `addInitToBrowserInit`/`addDestroyToBrowserInit` (the
287
- // real-execution path), so `--dry-run --init 'void 0'` succeeded and
288
- // rendered a plausible-looking preview even though the real run would
289
- // reject the same arguments. Dropping `void 0` into the template
290
- // silently (or breaking out of the string literal) was already
291
- // prevented downstream — this hoist just makes the failure surface
292
- // identical in preview mode.
280
+ // Validate init/destroy expressions BEFORE the dry-run/real fork so both
281
+ // paths enforce the same contract. Validating only inside
282
+ // `addInitToBrowserInit`/`addDestroyToBrowserInit` — the real-execution
283
+ // path — lets `--dry-run --init 'void 0'` succeed and render a plausible
284
+ // preview even though the real run rejects the same arguments.
293
285
  if (options.init !== undefined) {
294
286
  validateWireExpression(options.init, 'init expression');
295
287
  }
@@ -299,14 +291,15 @@ export async function wireCommand(projectRoot, name, options = {}) {
299
291
  consumeParserFallbackEvents();
300
292
  const subscriptDir = await resolveWireSubscriptDir(projectRoot, options);
301
293
  const domFilePath = await resolveDomFragmentPath(projectRoot, options.dom);
302
- // Resolve the chrome document the `#include` directive will land in.
303
- // Only consulted when `--dom` is supplied — we still resolve it here so
304
- // the dry-run plan can print the target accurately.
294
+ // Resolve the chrome document the `#include` directive will land in. Only
295
+ // consulted when `--dom` is supplied — resolved here anyway so the dry-run
296
+ // plan can print the target accurately.
305
297
  //
306
- // `stripEnginePrefix` is applied so `--target engine/browser/base/browser.xhtml`
307
- // and `--target browser/base/browser.xhtml` are treated identically,
308
- // matching the `--dom` normalization above. Absolute `--target` paths
309
- // stay absolute (the containment check downstream rejects them).
298
+ // `stripEnginePrefix` is applied so
299
+ // `--target engine/browser/base/browser.xhtml` and
300
+ // `--target browser/base/browser.xhtml` are treated identically, matching
301
+ // the `--dom` normalization above. Absolute `--target` paths stay absolute
302
+ // (the containment check downstream rejects them).
310
303
  const normalizedTarget = options.target !== undefined && !isExplicitAbsolutePath(options.target)
311
304
  ? stripEnginePrefix(options.target)
312
305
  : options.target;
@@ -317,19 +310,16 @@ export async function wireCommand(projectRoot, name, options = {}) {
317
310
  if (domFilePath) {
318
311
  await assertDomTargetIsWireable(projectRoot, domFilePath, domTargetPath);
319
312
  }
320
- // Verify the subscript file exists in engine/ (skip for dry-run:
321
- // dry-run is meant to preview the mutation plan without requiring
322
- // the subscript to already exist, matching the "plan before write"
323
- // pattern operators rely on for setup scripts).
313
+ // Verify the subscript file exists in engine/, skipping for dry-run:
314
+ // preview is meant to show the mutation plan without requiring the
315
+ // subscript to already exist, matching the "plan before write" pattern
316
+ // setup scripts rely on.
324
317
  //
325
- // Dry-run keeps the existence check advisory rather than fatal: the
326
- // "wire first, create file after" workflow is a legitimate use of
327
- // preview, but operators who run dry-run over a typo were surprised
328
- // when the real command then refused with `Subscript file not
329
- // found`. 2026-04-23 eval (Finding in eval 2): dry-run produced a
330
- // plausible plan and the non-dry-run invocation then errored. The
331
- // info line surfaces the mismatch in preview mode so the operator
332
- // can act on the warning before re-running without --dry-run.
318
+ // The check stays advisory rather than fatal in dry-run because
319
+ // "wire first, create file after" is a legitimate use of preview — but a
320
+ // dry-run over a typo would otherwise produce a plausible plan and the
321
+ // real command then refuse with `Subscript file not found`. The info line
322
+ // surfaces the mismatch in preview mode.
333
323
  await ensureSubscriptSourceExists(projectRoot, subscriptDir, name, options.dryRun ?? false);
334
324
  if (options.dryRun) {
335
325
  printWireDryRun(getProjectPaths(projectRoot).engine, name, subscriptDir, domFilePath, domTargetPath, options);
@@ -36,14 +36,15 @@ export declare function parseModule(content: string, onComment?: acorn.Comment[]
36
36
  *
37
37
  * **Caller obligation: you must already have discriminated on `node.type`.**
38
38
  * This performs no runtime check — it exists to attach acorn's `start`/`end`
39
- * offsets to a node the caller has *already* narrowed, typically inside a
40
- * `if (node.type === 'CallExpression')` branch or an equivalent walker guard.
41
- * Calling it on an undiscriminated node produces a value whose type is a lie.
39
+ * offsets to a node the caller has *already* narrowed, typically inside an
40
+ * `if (node.type === 'CallExpression')` branch or an equivalent walker
41
+ * guard. Calling it on an undiscriminated node produces a value whose type
42
+ * is a lie.
42
43
  *
43
- * A runtime `type` assertion was considered and rejected: every call site sits
44
- * in the hot loop of a lint or registration walker, and all of them are
45
- * already post-narrowing, so the check would cost traversal time on every node
46
- * to re-prove something the enclosing branch established.
44
+ * No runtime `type` assertion: every call site sits in the hot loop of a lint
45
+ * or registration walker and is already post-narrowing, so the check would
46
+ * cost traversal time on every node to re-prove what the enclosing branch
47
+ * established.
47
48
  */
48
49
  export declare function asEstree<T extends estree.Node>(node: estree.Node): AcornESTreeNode<T>;
49
50
  /**
@@ -55,14 +55,15 @@ export function parseModule(content, onComment) {
55
55
  *
56
56
  * **Caller obligation: you must already have discriminated on `node.type`.**
57
57
  * This performs no runtime check — it exists to attach acorn's `start`/`end`
58
- * offsets to a node the caller has *already* narrowed, typically inside a
59
- * `if (node.type === 'CallExpression')` branch or an equivalent walker guard.
60
- * Calling it on an undiscriminated node produces a value whose type is a lie.
58
+ * offsets to a node the caller has *already* narrowed, typically inside an
59
+ * `if (node.type === 'CallExpression')` branch or an equivalent walker
60
+ * guard. Calling it on an undiscriminated node produces a value whose type
61
+ * is a lie.
61
62
  *
62
- * A runtime `type` assertion was considered and rejected: every call site sits
63
- * in the hot loop of a lint or registration walker, and all of them are
64
- * already post-narrowing, so the check would cost traversal time on every node
65
- * to re-prove something the enclosing branch established.
63
+ * No runtime `type` assertion: every call site sits in the hot loop of a lint
64
+ * or registration walker and is already post-narrowing, so the check would
65
+ * cost traversal time on every node to re-prove what the enclosing branch
66
+ * established.
66
67
  */
67
68
  export function asEstree(node) {
68
69
  return node;
@@ -15,12 +15,10 @@ export declare class BrandingError extends FireForgeError {
15
15
  * fails deep inside moz.build resolution with a confusing "path does not
16
16
  * exist" message. Surface it as an actionable preflight instead.
17
17
  *
18
- * The root cause is that setup renders templates under `configs/` with
19
- * `${binaryName}` baked in at setup time; a subsequent edit to
20
- * `fireforge.json`'s `binaryName` (or a re-setup without re-templating)
21
- * leaves those baked-in names stale while `setupBranding` continues to use
22
- * the current `config.binaryName`. Both directions (mozconfig ahead of
23
- * config, config ahead of mozconfig) produce the same class of build break.
18
+ * Setup renders templates under `configs/` with `${binaryName}` baked in; a
19
+ * later edit to `fireforge.json`'s `binaryName` (or a re-setup without
20
+ * re-templating) leaves those names stale while `setupBranding` keeps using
21
+ * the current value. Both directions produce the same class of build break.
24
22
  */
25
23
  export declare class BrandingMozconfigMismatchError extends FireForgeError {
26
24
  readonly expectedBrandingDir: string;
@@ -46,9 +44,8 @@ export interface BrandingConfig {
46
44
  * Project license (from fireforge.json). Used to stamp the generated
47
45
  * `configure.sh`, `brand.properties`, and `brand.ftl` files with the
48
46
  * matching header so `patch-lint` does not flag them for
49
- * `missing-license-header` when the project is not MPL-2.0. Optional for
50
- * backwards compatibility with pre-0.16 callers that did not thread the
51
- * license through — falls back to {@link DEFAULT_LICENSE}.
47
+ * `missing-license-header` when the project is not MPL-2.0. Optional;
48
+ * falls back to {@link DEFAULT_LICENSE}.
52
49
  */
53
50
  license?: ProjectLicense;
54
51
  }
@@ -56,12 +53,10 @@ export interface BrandingConfig {
56
53
  * Splits the reverse-domain `appId` for macOS bundle identity. Upstream
57
54
  * `toolkit/moz.configure` composes `CFBundleIdentifier` as
58
55
  * `<--with-distribution-id>.<MOZ_MACBUNDLE_ID>` (the distribution id
59
- * defaults to `org.mozilla`), so branding `configure.sh` must carry only
60
- * the LEAF segment while the generated mozconfig carries the remainder as
56
+ * defaults to `org.mozilla`), so branding `configure.sh` must carry only the
57
+ * LEAF segment while the generated mozconfig carries the remainder as
61
58
  * `--with-distribution-id`. Writing the full appId into `MOZ_MACBUNDLE_ID`
62
- * double-prefixes the shipped bundle id (observed:
63
- * `org.mozilla.org.hominis.browser`, and with a distribution-id flag,
64
- * `org.hominis.org.hominis.browser`). Config validation guarantees a
59
+ * double-prefixes the shipped bundle id. Config validation guarantees a
65
60
  * reverse-domain id, so the split always has both halves.
66
61
  */
67
62
  export declare function splitAppId(appId: string): {
@@ -22,12 +22,10 @@ export class BrandingError extends FireForgeError {
22
22
  * fails deep inside moz.build resolution with a confusing "path does not
23
23
  * exist" message. Surface it as an actionable preflight instead.
24
24
  *
25
- * The root cause is that setup renders templates under `configs/` with
26
- * `${binaryName}` baked in at setup time; a subsequent edit to
27
- * `fireforge.json`'s `binaryName` (or a re-setup without re-templating)
28
- * leaves those baked-in names stale while `setupBranding` continues to use
29
- * the current `config.binaryName`. Both directions (mozconfig ahead of
30
- * config, config ahead of mozconfig) produce the same class of build break.
25
+ * Setup renders templates under `configs/` with `${binaryName}` baked in; a
26
+ * later edit to `fireforge.json`'s `binaryName` (or a re-setup without
27
+ * re-templating) leaves those names stale while `setupBranding` keeps using
28
+ * the current value. Both directions produce the same class of build break.
31
29
  */
32
30
  export class BrandingMozconfigMismatchError extends FireForgeError {
33
31
  expectedBrandingDir;
@@ -57,12 +55,10 @@ export class BrandingMozconfigMismatchError extends FireForgeError {
57
55
  * Splits the reverse-domain `appId` for macOS bundle identity. Upstream
58
56
  * `toolkit/moz.configure` composes `CFBundleIdentifier` as
59
57
  * `<--with-distribution-id>.<MOZ_MACBUNDLE_ID>` (the distribution id
60
- * defaults to `org.mozilla`), so branding `configure.sh` must carry only
61
- * the LEAF segment while the generated mozconfig carries the remainder as
58
+ * defaults to `org.mozilla`), so branding `configure.sh` must carry only the
59
+ * LEAF segment while the generated mozconfig carries the remainder as
62
60
  * `--with-distribution-id`. Writing the full appId into `MOZ_MACBUNDLE_ID`
63
- * double-prefixes the shipped bundle id (observed:
64
- * `org.mozilla.org.hominis.browser`, and with a distribution-id flag,
65
- * `org.hominis.org.hominis.browser`). Config validation guarantees a
61
+ * double-prefixes the shipped bundle id. Config validation guarantees a
66
62
  * reverse-domain id, so the split always has both halves.
67
63
  */
68
64
  export function splitAppId(appId) {
@@ -1,4 +1,4 @@
1
- import type { RegisterResult } from './manifest-register.js';
1
+ import type { RegisterResult } from './moz-manifest-register.js';
2
2
  export declare const DEFAULT_BROWSER_SUBSCRIPT_DIR = "browser/base/content";
3
3
  /**
4
4
  * Result of a wire operation.
@@ -6,7 +6,7 @@ import { verbose } from '../utils/logger.js';
6
6
  import { toRootRelativePath } from '../utils/paths.js';
7
7
  import { getProjectPaths, loadConfig } from './config.js';
8
8
  import { assertSnapshotted, createRollbackJournal, restoreRollbackJournal, snapshotFile, } from './furnace-rollback.js';
9
- import { registerBrowserContent } from './manifest-register.js';
9
+ import { registerBrowserContent } from './moz-manifest-register.js';
10
10
  import { DEFAULT_DOM_TARGET } from './wire-dom-fragment.js';
11
11
  import { addDestroyToBrowserInit, addDomFragment, addInitToBrowserInit, addSubscriptToBrowserMain, } from './wire-targets.js';
12
12
  export const DEFAULT_BROWSER_SUBSCRIPT_DIR = 'browser/base/content';
@@ -41,17 +41,14 @@ export async function wireSubscript(root, name, options = {}) {
41
41
  },
42
42
  };
43
43
  }
44
- // Snapshot every file the five mutation steps might touch so a mid-sequence
45
- // failure (most commonly the chrome-document insertion not finding an
46
- // anchor) does not leave a half-wired browser behind. Before the rollback
47
- // journal landed here, a failed `wire` would still have written new
48
- // `loadSubScript` calls into browser-main.js, new init/destroy expressions
49
- // into browser-init.js, and a new entry into browser/base/jar.mn — the
50
- // operator then had to grep the engine tree for the partial mutation and
51
- // hand-revert, or re-download. The snapshots cover the targets on every
52
- // code path (init/destroy/DOM are conditional, so we snapshot only when
53
- // the corresponding option would fire a write) plus the two files every
54
- // wire touches.
44
+ // Snapshot every file the five mutation steps might touch so a
45
+ // mid-sequence failure (most commonly the chrome-document insertion not
46
+ // finding an anchor) does not leave a half-wired browser behind: new
47
+ // `loadSubScript` calls in browser-main.js, new init/destroy expressions
48
+ // in browser-init.js, and a new entry in browser/base/jar.mn, with no way
49
+ // back but a hand-revert or a re-download. Init/destroy/DOM are
50
+ // conditional, so those targets are snapshotted only when the
51
+ // corresponding option would fire a write.
55
52
  const journal = createRollbackJournal();
56
53
  const effectiveDomTargetPath = options.domFilePath
57
54
  ? toRootRelativePath(engineDir, options.domTargetPath ?? DEFAULT_DOM_TARGET)
@@ -64,14 +61,12 @@ export async function wireSubscript(root, name, options = {}) {
64
61
  await snapshotFile(journal, join(engineDir, effectiveDomTargetPath));
65
62
  }
66
63
  await snapshotFile(journal, join(engineDir, 'browser/base/jar.mn'));
67
- // Compute the project-scoped patch-lint marker (`// <BINARY>:`) so
68
- // every wire mutator can stamp it into the emitted comment block.
69
- // Without this, `lintModificationComments` trips
70
- // `missing-modification-comment` on wire-generated edits the next
71
- // time the operator exports — the same tool wrote the code and a
72
- // sibling tool then rejected it (eval 1 Finding #9). A broken config
64
+ // Compute the project-scoped patch-lint marker (`// <BINARY>:`) so every
65
+ // wire mutator can stamp it into the emitted comment block. Without it,
66
+ // `lintModificationComments` trips `missing-modification-comment` on
67
+ // wire-generated edits the next time the operator exports. A broken config
73
68
  // should not block the wire, so the fallback marker keeps the
74
- // previous lint-friendly default when the config cannot be loaded.
69
+ // lint-friendly default when the config cannot be loaded.
75
70
  let marker = 'FIREFORGE:';
76
71
  try {
77
72
  const config = await loadConfig(root);