@hominis/fireforge 0.43.1 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +3 -3
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +13 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-patch-manifest.d.ts +8 -0
  22. package/dist/src/commands/doctor-patch-manifest.js +155 -0
  23. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  24. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  25. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  26. package/dist/src/commands/doctor-working-tree.js +11 -18
  27. package/dist/src/commands/doctor.d.ts +1 -1
  28. package/dist/src/commands/doctor.js +64 -96
  29. package/dist/src/commands/download.js +32 -48
  30. package/dist/src/commands/export-all.js +29 -33
  31. package/dist/src/commands/export-flow.js +6 -6
  32. package/dist/src/commands/export-placement-conflicts.js +10 -9
  33. package/dist/src/commands/export-placement-gate.js +5 -5
  34. package/dist/src/commands/export-shared.d.ts +30 -33
  35. package/dist/src/commands/export-shared.js +45 -43
  36. package/dist/src/commands/export.js +21 -27
  37. package/dist/src/commands/furnace/apply.js +14 -23
  38. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  39. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  40. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  41. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  42. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  43. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  44. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  45. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  46. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  47. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  48. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  49. package/dist/src/commands/furnace/create-readback.js +12 -13
  50. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  51. package/dist/src/commands/furnace/create-templates.js +35 -30
  52. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  53. package/dist/src/commands/furnace/create.js +33 -23
  54. package/dist/src/commands/furnace/deploy.js +16 -24
  55. package/dist/src/commands/furnace/diff.js +15 -10
  56. package/dist/src/commands/furnace/init.js +33 -36
  57. package/dist/src/commands/furnace/override.js +23 -25
  58. package/dist/src/commands/furnace/preview.js +47 -67
  59. package/dist/src/commands/furnace/refresh.js +12 -16
  60. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  61. package/dist/src/commands/furnace/remove-mutations.js +14 -17
  62. package/dist/src/commands/furnace/remove-state.js +1 -1
  63. package/dist/src/commands/furnace/remove.js +33 -38
  64. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  65. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  66. package/dist/src/commands/furnace/rename.js +59 -69
  67. package/dist/src/commands/furnace/scan.js +19 -33
  68. package/dist/src/commands/furnace/status.js +12 -9
  69. package/dist/src/commands/furnace/sync.js +9 -16
  70. package/dist/src/commands/furnace/validate.js +20 -20
  71. package/dist/src/commands/import.js +48 -37
  72. package/dist/src/commands/lint-per-patch.js +15 -10
  73. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  74. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  75. package/dist/src/commands/lint-report.js +6 -7
  76. package/dist/src/commands/lint.d.ts +15 -16
  77. package/dist/src/commands/lint.js +86 -102
  78. package/dist/src/commands/package.js +6 -11
  79. package/dist/src/commands/patch/compact.js +1 -1
  80. package/dist/src/commands/patch/delete.js +24 -33
  81. package/dist/src/commands/patch/index.d.ts +5 -6
  82. package/dist/src/commands/patch/index.js +10 -12
  83. package/dist/src/commands/patch/lint-ignore.js +14 -13
  84. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  85. package/dist/src/commands/patch/move-files-create.js +8 -8
  86. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  87. package/dist/src/commands/patch/move-files-into.js +8 -8
  88. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  89. package/dist/src/commands/patch/patch-context.js +2 -3
  90. package/dist/src/commands/patch/rename.d.ts +10 -11
  91. package/dist/src/commands/patch/rename.js +11 -12
  92. package/dist/src/commands/patch/reorder.js +8 -9
  93. package/dist/src/commands/patch/split-plan.js +1 -1
  94. package/dist/src/commands/patch/split.d.ts +8 -10
  95. package/dist/src/commands/patch/split.js +9 -11
  96. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  97. package/dist/src/commands/patch/staged-dependency.js +7 -3
  98. package/dist/src/commands/patch/tier.d.ts +9 -9
  99. package/dist/src/commands/patch/tier.js +18 -15
  100. package/dist/src/commands/re-export-adjacent.js +9 -8
  101. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  102. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  103. package/dist/src/commands/re-export-drift.js +10 -10
  104. package/dist/src/commands/re-export-files.d.ts +6 -7
  105. package/dist/src/commands/re-export-files.js +34 -44
  106. package/dist/src/commands/re-export-lint.d.ts +10 -13
  107. package/dist/src/commands/re-export-lint.js +16 -14
  108. package/dist/src/commands/re-export-options.d.ts +6 -6
  109. package/dist/src/commands/re-export-options.js +6 -6
  110. package/dist/src/commands/re-export-register.d.ts +4 -10
  111. package/dist/src/commands/re-export-register.js +5 -11
  112. package/dist/src/commands/re-export-scan.js +1 -1
  113. package/dist/src/commands/re-export-single.d.ts +3 -3
  114. package/dist/src/commands/re-export-single.js +33 -25
  115. package/dist/src/commands/re-export.js +13 -21
  116. package/dist/src/commands/rebase/abort.js +3 -3
  117. package/dist/src/commands/rebase/confirm.js +2 -1
  118. package/dist/src/commands/rebase/continue.d.ts +1 -1
  119. package/dist/src/commands/rebase/continue.js +14 -9
  120. package/dist/src/commands/rebase/index.js +11 -11
  121. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  122. package/dist/src/commands/rebase/patch-loop.js +60 -39
  123. package/dist/src/commands/rebase/summary.js +1 -1
  124. package/dist/src/commands/register.js +5 -7
  125. package/dist/src/commands/reset.js +2 -1
  126. package/dist/src/commands/resolve.d.ts +16 -13
  127. package/dist/src/commands/resolve.js +30 -33
  128. package/dist/src/commands/run.js +33 -35
  129. package/dist/src/commands/setup-support.js +15 -19
  130. package/dist/src/commands/setup.js +13 -9
  131. package/dist/src/commands/status-check.d.ts +6 -6
  132. package/dist/src/commands/status-json.d.ts +6 -6
  133. package/dist/src/commands/status-json.js +5 -0
  134. package/dist/src/commands/status-output.d.ts +5 -5
  135. package/dist/src/commands/status-output.js +6 -6
  136. package/dist/src/commands/status-ownership.d.ts +16 -14
  137. package/dist/src/commands/status-ownership.js +16 -14
  138. package/dist/src/commands/status.js +42 -34
  139. package/dist/src/commands/test-build-phase.js +26 -13
  140. package/dist/src/commands/test-diagnose.js +44 -44
  141. package/dist/src/commands/test-register.js +1 -0
  142. package/dist/src/commands/test-run.d.ts +14 -16
  143. package/dist/src/commands/test-run.js +21 -13
  144. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  145. package/dist/src/commands/test-stale-gate.js +15 -16
  146. package/dist/src/commands/test-verdict.d.ts +20 -3
  147. package/dist/src/commands/test-verdict.js +30 -0
  148. package/dist/src/commands/test.js +83 -76
  149. package/dist/src/commands/token-coverage.js +3 -4
  150. package/dist/src/commands/token.js +16 -18
  151. package/dist/src/commands/tree.js +47 -31
  152. package/dist/src/commands/typecheck.d.ts +10 -12
  153. package/dist/src/commands/typecheck.js +24 -27
  154. package/dist/src/commands/verify.js +13 -15
  155. package/dist/src/commands/watch.js +21 -23
  156. package/dist/src/commands/wire.js +52 -62
  157. package/dist/src/core/ast-utils.d.ts +8 -7
  158. package/dist/src/core/ast-utils.js +8 -7
  159. package/dist/src/core/branding.d.ts +9 -14
  160. package/dist/src/core/branding.js +7 -11
  161. package/dist/src/core/browser-wire.d.ts +1 -1
  162. package/dist/src/core/browser-wire.js +14 -19
  163. package/dist/src/core/build-audit-platform.js +25 -33
  164. package/dist/src/core/build-audit-registration.js +17 -25
  165. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  166. package/dist/src/core/build-audit-resolve.js +39 -36
  167. package/dist/src/core/build-audit-transforms.js +18 -19
  168. package/dist/src/core/build-audit.js +28 -42
  169. package/dist/src/core/build-baseline-types.d.ts +29 -35
  170. package/dist/src/core/build-baseline.d.ts +5 -4
  171. package/dist/src/core/build-baseline.js +14 -14
  172. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  173. package/dist/src/core/build-overwrite-guard.js +17 -27
  174. package/dist/src/core/build-prepare.d.ts +2 -2
  175. package/dist/src/core/build-prepare.js +8 -9
  176. package/dist/src/core/config-mutate.js +20 -19
  177. package/dist/src/core/config-state.js +12 -4
  178. package/dist/src/core/config-validate.js +8 -5
  179. package/dist/src/core/config.d.ts +5 -8
  180. package/dist/src/core/config.js +7 -16
  181. package/dist/src/core/coverage-extend.d.ts +15 -13
  182. package/dist/src/core/coverage-extend.js +15 -13
  183. package/dist/src/core/destructive.d.ts +31 -9
  184. package/dist/src/core/destructive.js +29 -26
  185. package/dist/src/core/diff-hunks.js +10 -12
  186. package/dist/src/core/discard-baseline.d.ts +8 -8
  187. package/dist/src/core/discard-baseline.js +16 -15
  188. package/dist/src/core/display-state.d.ts +12 -14
  189. package/dist/src/core/display-state.js +12 -14
  190. package/dist/src/core/engine-changes.d.ts +2 -4
  191. package/dist/src/core/engine-changes.js +2 -4
  192. package/dist/src/core/engine-precondition.d.ts +28 -13
  193. package/dist/src/core/engine-precondition.js +25 -10
  194. package/dist/src/core/engine-session-lock.d.ts +47 -21
  195. package/dist/src/core/engine-session-lock.js +168 -33
  196. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  197. package/dist/src/core/export-moved-code-shape.js +10 -10
  198. package/dist/src/core/file-lock.d.ts +62 -5
  199. package/dist/src/core/file-lock.js +196 -59
  200. package/dist/src/core/firefox-cache.js +1 -3
  201. package/dist/src/core/firefox-extract.js +10 -14
  202. package/dist/src/core/firefox.d.ts +7 -5
  203. package/dist/src/core/firefox.js +4 -5
  204. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  205. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  206. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  207. package/dist/src/core/furnace-apply-ftl.js +16 -13
  208. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  209. package/dist/src/core/furnace-apply-helpers.js +30 -21
  210. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  211. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  212. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  213. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  214. package/dist/src/core/furnace-apply.d.ts +5 -8
  215. package/dist/src/core/furnace-apply.js +19 -24
  216. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  217. package/dist/src/core/furnace-checksum-utils.js +16 -0
  218. package/dist/src/core/furnace-config.d.ts +21 -30
  219. package/dist/src/core/furnace-config.js +32 -54
  220. package/dist/src/core/furnace-constants.d.ts +8 -0
  221. package/dist/src/core/furnace-constants.js +10 -2
  222. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  223. package/dist/src/core/furnace-css-fragments.js +5 -5
  224. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  225. package/dist/src/core/furnace-jsconfig.js +11 -12
  226. package/dist/src/core/furnace-marker.d.ts +7 -8
  227. package/dist/src/core/furnace-marker.js +7 -8
  228. package/dist/src/core/furnace-operation.d.ts +31 -0
  229. package/dist/src/core/furnace-operation.js +54 -17
  230. package/dist/src/core/furnace-precondition.d.ts +61 -0
  231. package/dist/src/core/furnace-precondition.js +67 -0
  232. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  233. package/dist/src/core/furnace-registration-remove.js +6 -7
  234. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  235. package/dist/src/core/furnace-registration-validate.js +20 -1
  236. package/dist/src/core/furnace-registration.d.ts +5 -6
  237. package/dist/src/core/furnace-registration.js +10 -12
  238. package/dist/src/core/furnace-rollback.js +7 -7
  239. package/dist/src/core/furnace-scanner.d.ts +1 -0
  240. package/dist/src/core/furnace-scanner.js +1 -2
  241. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  242. package/dist/src/core/furnace-stale-export.js +10 -10
  243. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  244. package/dist/src/core/furnace-state-persist.js +6 -8
  245. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  246. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  247. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  248. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  249. package/dist/src/core/furnace-validate-helpers.js +0 -491
  250. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  251. package/dist/src/core/furnace-validate-registration.js +115 -41
  252. package/dist/src/core/furnace-validate.d.ts +16 -0
  253. package/dist/src/core/furnace-validate.js +188 -145
  254. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  255. package/dist/src/core/furnace-version-drift.js +10 -11
  256. package/dist/src/core/git-base.d.ts +21 -9
  257. package/dist/src/core/git-base.js +24 -9
  258. package/dist/src/core/git-diff.d.ts +20 -9
  259. package/dist/src/core/git-diff.js +148 -63
  260. package/dist/src/core/git-file-ops.d.ts +19 -19
  261. package/dist/src/core/git-file-ops.js +19 -19
  262. package/dist/src/core/git-readonly-index.d.ts +53 -19
  263. package/dist/src/core/git-readonly-index.js +75 -31
  264. package/dist/src/core/git-status.d.ts +5 -6
  265. package/dist/src/core/git-status.js +5 -6
  266. package/dist/src/core/git.d.ts +9 -10
  267. package/dist/src/core/git.js +57 -71
  268. package/dist/src/core/license-headers.d.ts +17 -23
  269. package/dist/src/core/license-headers.js +17 -23
  270. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  271. package/dist/src/core/mach-build-artifacts.js +57 -19
  272. package/dist/src/core/mach-error-hints.js +42 -29
  273. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  274. package/dist/src/core/mach-known-noise-filter.js +18 -20
  275. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  276. package/dist/src/core/mach-mozconfig.js +30 -0
  277. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  278. package/dist/src/core/mach-resource-shim.js +50 -67
  279. package/dist/src/core/mach.d.ts +37 -41
  280. package/dist/src/core/mach.js +50 -51
  281. package/dist/src/core/marionette-port.d.ts +36 -1
  282. package/dist/src/core/marionette-port.js +96 -31
  283. package/dist/src/core/marionette-preflight.d.ts +8 -12
  284. package/dist/src/core/marionette-preflight.js +86 -52
  285. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  286. package/dist/src/core/mochitest-server-port.js +119 -0
  287. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  288. package/dist/src/core/module-resolution-preflight.js +9 -11
  289. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  290. package/dist/src/core/moz-manifest-helpers.js +163 -0
  291. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  292. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  293. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  294. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  295. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  296. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  297. package/dist/src/core/ownership-table.d.ts +14 -16
  298. package/dist/src/core/ownership-table.js +14 -16
  299. package/dist/src/core/parser-fallback.d.ts +15 -1
  300. package/dist/src/core/parser-fallback.js +22 -3
  301. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  302. package/dist/src/core/patch-apply-fuzz.js +15 -18
  303. package/dist/src/core/patch-apply.d.ts +13 -34
  304. package/dist/src/core/patch-apply.js +16 -76
  305. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  306. package/dist/src/core/patch-artifact-normalize.js +13 -15
  307. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  308. package/dist/src/core/patch-export-metadata.js +13 -4
  309. package/dist/src/core/patch-export-update.d.ts +13 -1
  310. package/dist/src/core/patch-export-update.js +25 -8
  311. package/dist/src/core/patch-export.d.ts +15 -8
  312. package/dist/src/core/patch-export.js +10 -11
  313. package/dist/src/core/patch-files.d.ts +5 -6
  314. package/dist/src/core/patch-files.js +5 -6
  315. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  316. package/dist/src/core/patch-identifier-suggest.js +14 -19
  317. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  318. package/dist/src/core/patch-lint-binary.js +39 -0
  319. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  320. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  321. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  322. package/dist/src/core/patch-lint-checkjs.js +41 -20
  323. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  324. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  325. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  326. package/dist/src/core/patch-lint-creators.js +8 -8
  327. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  328. package/dist/src/core/patch-lint-cross.js +16 -16
  329. package/dist/src/core/patch-lint-css.d.ts +3 -5
  330. package/dist/src/core/patch-lint-css.js +17 -22
  331. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  332. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  333. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  334. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  335. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  336. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  337. package/dist/src/core/patch-lint-observer.js +7 -7
  338. package/dist/src/core/patch-lint.d.ts +38 -29
  339. package/dist/src/core/patch-lint.js +89 -121
  340. package/dist/src/core/patch-lock.d.ts +1 -1
  341. package/dist/src/core/patch-lock.js +45 -9
  342. package/dist/src/core/patch-manifest-consistency.d.ts +57 -6
  343. package/dist/src/core/patch-manifest-consistency.js +111 -40
  344. package/dist/src/core/patch-manifest-files-affected.d.ts +43 -0
  345. package/dist/src/core/patch-manifest-files-affected.js +77 -0
  346. package/dist/src/core/patch-manifest-io.js +14 -18
  347. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  348. package/dist/src/core/patch-manifest-resolve.js +9 -12
  349. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  350. package/dist/src/core/patch-manifest-validate.js +25 -13
  351. package/dist/src/core/patch-manifest.d.ts +2 -1
  352. package/dist/src/core/patch-manifest.js +2 -1
  353. package/dist/src/core/patch-parse.d.ts +24 -13
  354. package/dist/src/core/patch-parse.js +19 -14
  355. package/dist/src/core/patch-policy.d.ts +2 -2
  356. package/dist/src/core/patch-policy.js +2 -2
  357. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  358. package/dist/src/core/patch-registration-refs.js +9 -9
  359. package/dist/src/core/process-cpu-time.d.ts +12 -0
  360. package/dist/src/core/process-cpu-time.js +52 -0
  361. package/dist/src/core/rebase-session.d.ts +38 -26
  362. package/dist/src/core/rebase-session.js +55 -28
  363. package/dist/src/core/register-browser-content.js +9 -74
  364. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  365. package/dist/src/core/register-module.js +10 -43
  366. package/dist/src/core/register-scaffold.d.ts +8 -8
  367. package/dist/src/core/register-scaffold.js +10 -10
  368. package/dist/src/core/register-shared-css.d.ts +9 -12
  369. package/dist/src/core/register-shared-css.js +17 -87
  370. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  371. package/dist/src/core/register-xpcshell-test.js +7 -8
  372. package/dist/src/core/shared-ftl.js +12 -4
  373. package/dist/src/core/state-file.d.ts +45 -0
  374. package/dist/src/core/state-file.js +34 -0
  375. package/dist/src/core/status-binary.d.ts +18 -11
  376. package/dist/src/core/status-binary.js +19 -12
  377. package/dist/src/core/status-classify.d.ts +30 -36
  378. package/dist/src/core/status-classify.js +21 -26
  379. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  380. package/dist/src/core/test-changed-prefs.js +78 -0
  381. package/dist/src/core/test-harness-crash.d.ts +25 -63
  382. package/dist/src/core/test-harness-crash.js +121 -142
  383. package/dist/src/core/test-harness-signature.d.ts +18 -0
  384. package/dist/src/core/test-harness-signature.js +13 -0
  385. package/dist/src/core/test-path-scope.d.ts +12 -15
  386. package/dist/src/core/test-path-scope.js +15 -18
  387. package/dist/src/core/test-stale-check.d.ts +17 -17
  388. package/dist/src/core/test-stale-check.js +50 -43
  389. package/dist/src/core/test-stall-triage.d.ts +51 -0
  390. package/dist/src/core/test-stall-triage.js +126 -0
  391. package/dist/src/core/token-category.js +66 -14
  392. package/dist/src/core/token-coverage.js +9 -9
  393. package/dist/src/core/token-dark-mode.d.ts +9 -11
  394. package/dist/src/core/token-dark-mode.js +29 -13
  395. package/dist/src/core/token-docs.d.ts +2 -0
  396. package/dist/src/core/token-docs.js +3 -1
  397. package/dist/src/core/token-manager.d.ts +10 -2
  398. package/dist/src/core/token-manager.js +17 -8
  399. package/dist/src/core/token-scaffold.d.ts +7 -7
  400. package/dist/src/core/token-scaffold.js +7 -7
  401. package/dist/src/core/token-variant.d.ts +4 -4
  402. package/dist/src/core/token-variant.js +28 -6
  403. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  404. package/dist/src/core/toolchain-preflight.js +28 -31
  405. package/dist/src/core/tree-guard.js +12 -2
  406. package/dist/src/core/tree-store.d.ts +41 -27
  407. package/dist/src/core/tree-store.js +68 -43
  408. package/dist/src/core/typecheck-shim.d.ts +23 -24
  409. package/dist/src/core/typecheck-shim.js +23 -24
  410. package/dist/src/core/typecheck.js +15 -9
  411. package/dist/src/core/wire-destroy.d.ts +3 -3
  412. package/dist/src/core/wire-destroy.js +7 -15
  413. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  414. package/dist/src/core/wire-dom-fragment.js +11 -44
  415. package/dist/src/core/wire-init.d.ts +2 -3
  416. package/dist/src/core/wire-init.js +8 -19
  417. package/dist/src/core/wire-subscript.d.ts +2 -3
  418. package/dist/src/core/wire-subscript.js +4 -13
  419. package/dist/src/core/wire-utils.d.ts +7 -8
  420. package/dist/src/core/wire-utils.js +7 -8
  421. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  422. package/dist/src/core/xpcshell-appdir.js +38 -45
  423. package/dist/src/errors/base.d.ts +37 -16
  424. package/dist/src/errors/base.js +37 -16
  425. package/dist/src/errors/build.d.ts +13 -1
  426. package/dist/src/errors/build.js +14 -2
  427. package/dist/src/errors/codes.d.ts +16 -0
  428. package/dist/src/errors/codes.js +16 -0
  429. package/dist/src/errors/furnace.d.ts +4 -4
  430. package/dist/src/errors/git.d.ts +6 -10
  431. package/dist/src/errors/git.js +6 -10
  432. package/dist/src/errors/patch.d.ts +7 -7
  433. package/dist/src/errors/patch.js +7 -7
  434. package/dist/src/errors/rebase.d.ts +4 -4
  435. package/dist/src/errors/rebase.js +4 -4
  436. package/dist/src/index.d.ts +7 -1
  437. package/dist/src/index.js +5 -0
  438. package/dist/src/types/commands/index.d.ts +2 -2
  439. package/dist/src/types/commands/options.d.ts +111 -70
  440. package/dist/src/types/commands/patches.d.ts +24 -34
  441. package/dist/src/types/commands/project.d.ts +5 -34
  442. package/dist/src/types/config.d.ts +25 -23
  443. package/dist/src/types/config.js +6 -1
  444. package/dist/src/types/furnace.d.ts +37 -13
  445. package/dist/src/types/furnace.js +19 -1
  446. package/dist/src/types/index.d.ts +3 -3
  447. package/dist/src/utils/build-info.d.ts +7 -8
  448. package/dist/src/utils/build-info.js +12 -11
  449. package/dist/src/utils/errors.d.ts +6 -8
  450. package/dist/src/utils/errors.js +6 -8
  451. package/dist/src/utils/logger.d.ts +27 -10
  452. package/dist/src/utils/logger.js +28 -16
  453. package/dist/src/utils/machine-output.d.ts +12 -0
  454. package/dist/src/utils/machine-output.js +33 -0
  455. package/dist/src/utils/options.d.ts +31 -14
  456. package/dist/src/utils/options.js +86 -30
  457. package/dist/src/utils/paths.d.ts +10 -8
  458. package/dist/src/utils/paths.js +10 -8
  459. package/dist/src/utils/platform.d.ts +0 -25
  460. package/dist/src/utils/platform.js +1 -42
  461. package/dist/src/utils/process-group.d.ts +9 -4
  462. package/dist/src/utils/process-group.js +19 -5
  463. package/dist/src/utils/process.d.ts +42 -7
  464. package/dist/src/utils/process.js +44 -17
  465. package/dist/src/utils/ps-duration.d.ts +31 -0
  466. package/dist/src/utils/ps-duration.js +70 -0
  467. package/dist/src/utils/regex.d.ts +9 -10
  468. package/dist/src/utils/regex.js +9 -10
  469. package/dist/src/utils/validation.d.ts +58 -28
  470. package/dist/src/utils/validation.js +60 -33
  471. package/package.json +3 -3
  472. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  473. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  474. package/dist/src/core/manifest-helpers.d.ts +0 -38
  475. package/dist/src/core/manifest-helpers.js +0 -120
  476. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  477. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  478. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { createHash } from 'node:crypto';
15
15
  import { existsSync } from 'node:fs';
16
- import { lstat, readdir, readFile, realpath, rm } from 'node:fs/promises';
16
+ import { cp, lstat, mkdir, readdir, readFile, realpath, rm } from 'node:fs/promises';
17
17
  import { basename, join, resolve, sep } from 'node:path';
18
18
  import { GeneralError } from '../errors/base.js';
19
19
  import { mapWithConcurrency } from '../utils/concurrency.js';
@@ -26,6 +26,7 @@ import { LOCK_PID_FILE, withFileLock } from './file-lock.js';
26
26
  import { git } from './git-base.js';
27
27
  import { getAllDiff } from './git-diff.js';
28
28
  import { attemptMozinfoRewrite } from './mach-build-artifacts.js';
29
+ import { checkDocumentVersion, describeNewerDocument } from './state-file.js';
29
30
  import { cloneEntry } from './tree-cow.js';
30
31
  const TREE_MARKER_FILENAME = 'tree.json';
31
32
  const TREES_DIRNAME = 'trees';
@@ -56,16 +57,18 @@ export async function withTreeLifecycleLock(primaryRoot, operation) {
56
57
  /**
57
58
  * Validates every field of a tree marker.
58
59
  *
59
- * The read below checked only `schemaVersion` and `name` and asserted the
60
- * rest, but the unvalidated fields are consumed unguarded: `primaryRoot`
61
- * reaches a user-facing refusal message (`tree-guard.ts:105`), and
60
+ * Checking only `schemaVersion` and `name` and asserting the rest is not
61
+ * enough: the unvalidated fields are consumed unguarded. `primaryRoot`
62
+ * reaches a user-facing refusal message in `tree-guard.ts`, and
62
63
  * `engineHead`/`patchesFingerprint` feed the staleness compare, where an
63
64
  * `undefined` from a truncated marker reports every tree as stale.
64
65
  */
66
+ /** Schema version this build writes and understands. */
67
+ const TREE_MARKER_SCHEMA_VERSION = 1;
65
68
  function isTreeMarker(value) {
66
69
  if (!isObject(value))
67
70
  return false;
68
- return (value['schemaVersion'] === 1 &&
71
+ return (value['schemaVersion'] === TREE_MARKER_SCHEMA_VERSION &&
69
72
  typeof value['name'] === 'string' &&
70
73
  typeof value['primaryRoot'] === 'string' &&
71
74
  typeof value['createdAt'] === 'string' &&
@@ -82,20 +85,39 @@ export function getTreeMarkerPath(root) {
82
85
  }
83
86
  /**
84
87
  * Reads the tree marker for a project root, distinguishing "not a tree" from
85
- * "a tree whose marker we could not read". Callers that make a safety decision
86
- * (the guard hook, the no-nesting refusal) must use this rather than
87
- * {@link readTreeMarker}.
88
+ * "a tree whose marker we could not read". Callers that make a safety
89
+ * decision (the guard hook, the no-nesting refusal) must use this rather
90
+ * than {@link tryReadTreeMarker}.
88
91
  *
89
92
  * Only ENOENT/ENOTDIR mean `absent`: any other probe failure (EACCES on the
90
93
  * `.fireforge` directory, EIO, …) reports `corrupt`, because "we cannot read
91
94
  * the marker" is not evidence that there is no marker — a `pathExists`
92
- * pre-check here classified a tree with an unreadable `.fireforge` as
93
- * `absent` and handed it the full mutating command set.
95
+ * pre-check classifies a tree with an unreadable `.fireforge` as `absent`
96
+ * and hands it the full mutating command set.
94
97
  */
95
- export async function readTreeMarkerState(root) {
98
+ /**
99
+ * Naming convention for state-file readers:
100
+ * - `readX(): Promise<XRead>` — the TRI-STATE read: absent, corrupt, or
101
+ * valid.
102
+ * - `tryReadX(): Promise<X | undefined>` — collapses absent and corrupt.
103
+ */
104
+ export async function readTreeMarker(root) {
96
105
  const markerPath = getTreeMarkerPath(root);
97
106
  try {
98
107
  const raw = await readJson(markerPath);
108
+ // Version FIRST, and reported distinctly. Folding the schemaVersion
109
+ // check into `isTreeMarker` makes a marker from a NEWER FireForge read
110
+ // as "missing or mistypes a required field" — and `tree-guard.ts` is
111
+ // default-deny on corrupt, so the operator is locked out of every
112
+ // mutating command inside the tree by a message claiming the file is
113
+ // malformed when it is merely newer.
114
+ const version = checkDocumentVersion(raw, 'schemaVersion', TREE_MARKER_SCHEMA_VERSION);
115
+ if (version.kind === 'newer') {
116
+ return {
117
+ kind: 'unsupported',
118
+ reason: describeNewerDocument('tree marker', version.found, TREE_MARKER_SCHEMA_VERSION),
119
+ };
120
+ }
99
121
  if (!isTreeMarker(raw)) {
100
122
  verbose(`Malformed tree marker at ${markerPath}`);
101
123
  return { kind: 'corrupt', reason: 'the marker is missing or mistypes a required field' };
@@ -116,10 +138,10 @@ export async function readTreeMarkerState(root) {
116
138
  *
117
139
  * For display and best-effort paths only (`tree list` renders an unreadable
118
140
  * marker as staleness 'unknown'). Anything that decides whether a mutation may
119
- * proceed must call {@link readTreeMarkerState} and handle `corrupt`.
141
+ * proceed must call {@link readTreeMarker} and handle `corrupt`.
120
142
  */
121
- export async function readTreeMarker(root) {
122
- const state = await readTreeMarkerState(root);
143
+ export async function tryReadTreeMarker(root) {
144
+ const state = await readTreeMarker(root);
123
145
  return state.kind === 'valid' ? state.marker : undefined;
124
146
  }
125
147
  /**
@@ -131,7 +153,7 @@ export async function readTreeMarker(root) {
131
153
  * No-op outside a tree; a corrupt marker is already refused by the guard.
132
154
  */
133
155
  export async function assertObjdirMatchesTreeMarker(projectRoot, objDir) {
134
- const state = await readTreeMarkerState(projectRoot);
156
+ const state = await readTreeMarker(projectRoot);
135
157
  if (state.kind !== 'valid' || state.marker.clonedObjdir === undefined)
136
158
  return;
137
159
  if (objDir !== state.marker.clonedObjdir) {
@@ -235,22 +257,21 @@ async function assertCloneSafeObjdir(engineDir, objDir, role) {
235
257
  }
236
258
  }
237
259
  /**
238
- * Materialises the tree at `treeRoot` from `primaryRoot` using
239
- * `capability` ('none' = plain copy, already gated on --force-copy by
240
- * the caller). The engine is cloned one TOP-LEVEL entry at a time so unwanted
241
- * `obj-*` directories are never traversed or materialised. That distinction
242
- * is substantial on Firefox trees: even CoW-cloning and deleting an objdir
243
- * touches metadata for millions of build outputs. With `withObjdir` exactly
244
- * that objdir is included — after {@link assertCloneSafeObjdir}
245
- * refuses symlinked or engine-escaping objdirs before any copying —
246
- * rewritten to the tree (see below), and
247
- * reconfigured in-tree via the caller-supplied `reconfigure` hook. A
248
- * fresh `.fireforge/` is created with only `state.json` (when present),
249
- * the last-build baseline (withObjdir only), and the tree marker.
260
+ * Materialises the tree at `treeRoot` from `primaryRoot` using `capability`
261
+ * ('none' = plain copy, already gated on --force-copy by the caller).
262
+ *
263
+ * The engine is cloned one TOP-LEVEL entry at a time so unwanted `obj-*`
264
+ * directories are never traversed or materialised — on a Firefox tree, even
265
+ * CoW-cloning and then deleting an objdir touches metadata for millions of
266
+ * build outputs. With `withObjdir` exactly that objdir is included (after
267
+ * {@link assertCloneSafeObjdir} refuses symlinked or engine-escaping objdirs
268
+ * before any copying), rewritten to the tree, and reconfigured in-tree via
269
+ * the caller-supplied `reconfigure` hook. A fresh `.fireforge/` is created
270
+ * with only `state.json` (when present), the last-build baseline (withObjdir
271
+ * only), and the tree marker.
250
272
  */
251
273
  export async function cloneTree(args) {
252
274
  const { primaryRoot, treeRoot, name, capability, createdAt, withObjdir } = args;
253
- const { mkdir, cp } = await import('node:fs/promises');
254
275
  if (withObjdir) {
255
276
  // Refuse a symlinked/escaping primary objdir BEFORE any copying: the
256
277
  // clone would carry the symlink and every later write would land in
@@ -303,7 +324,7 @@ export async function cloneTree(args) {
303
324
  }
304
325
  const { engineHead, engineFingerprint, patchesFingerprint } = await computePrimaryFingerprint(primaryRoot);
305
326
  const marker = {
306
- schemaVersion: 1,
327
+ schemaVersion: TREE_MARKER_SCHEMA_VERSION,
307
328
  name,
308
329
  primaryRoot,
309
330
  createdAt,
@@ -352,7 +373,7 @@ export async function listTrees(primaryRoot) {
352
373
  if (name.endsWith('.lock'))
353
374
  continue;
354
375
  const path = join(treesDir, name);
355
- const marker = await readTreeMarker(path);
376
+ const marker = await tryReadTreeMarker(path);
356
377
  if (!marker) {
357
378
  entries.push({ name, path, createdAt: '(no marker)', staleness: 'unknown' });
358
379
  continue;
@@ -376,19 +397,19 @@ export async function listTrees(primaryRoot) {
376
397
  * file-lock internals.
377
398
  *
378
399
  * Liveness comes from the shared {@link isProcessAlive}, which treats EPERM
379
- * as alive. The local copy this replaced returned `false` for EPERM, so a
380
- * tree whose build lock was held by a live process running under a different
381
- * uid passed the guard below and was `rm -rf`'d mid-build.
400
+ * as alive. Returning `false` for EPERM lets a tree whose build lock is held
401
+ * by a live process running under a different uid pass the guard below and
402
+ * get `rm -rf`'d mid-build.
382
403
  *
383
- * The `unknown` state is not a theoretical case. `withFileLock` takes the lock
384
- * by creating the directory and only *then* writes the owner file, treating a
385
- * write failure as non-fatal — so every acquisition passes through a window in
386
- * which the lock is genuinely held and has no readable PID, and a read-only or
387
- * full filesystem leaves it that way for the lock's whole life. Reporting that
388
- * as `free` let `removeTree` recursively delete a tree out from under a live
389
- * build. `file-lock.ts` reaches the same conclusion for its own stale
390
- * recovery, where an unreadable PID falls back to an age-only heuristic rather
391
- * than assuming the lock is abandoned.
404
+ * The `unknown` state is not theoretical. `withFileLock` takes the lock by
405
+ * creating the directory and only *then* writes the owner file, treating a
406
+ * write failure as non-fatal — so every acquisition passes through a window
407
+ * in which the lock is genuinely held and has no readable PID, and a
408
+ * read-only or full filesystem leaves it that way for the lock's whole life.
409
+ * Reporting that as `free` lets `removeTree` recursively delete a tree out
410
+ * from under a live build. `file-lock.ts` reaches the same conclusion for
411
+ * its own stale recovery, where an unreadable PID falls back to an age-only
412
+ * heuristic rather than assuming the lock is abandoned.
392
413
  */
393
414
  async function inspectTreeLock(lockPath) {
394
415
  if (!existsSync(lockPath))
@@ -422,7 +443,11 @@ async function inspectTreeLock(lockPath) {
422
443
  */
423
444
  export async function removeTree(primaryRoot, name, options = {}) {
424
445
  assertValidTreeName(name);
425
- const treesDir = getTreesDir(primaryRoot);
446
+ // Both sides resolved: the containment prefix has to be in the same form as
447
+ // the path it guards. `getTreesDir` is a `join`, so on Windows it yields a
448
+ // drive-less path while `resolve` below adds the drive letter — the prefix
449
+ // test then failed for EVERY tree and refused each removal as an escape.
450
+ const treesDir = resolve(getTreesDir(primaryRoot));
426
451
  const treeRoot = resolve(treesDir, name);
427
452
  if (!treeRoot.startsWith(treesDir + sep) || basename(treeRoot) !== name) {
428
453
  throw new GeneralError(`Refusing to remove "${name}": resolved path escapes the trees directory.`);
@@ -40,13 +40,12 @@ export declare const TEST_HARNESS_SHIM = "\n// \u2500\u2500 FireForge test-harne
40
40
  export declare const SUPPRESSED_DIAGNOSTIC_CODES: ReadonlySet<number>;
41
41
  /**
42
42
  * Undefined-free-identifier codes, split out of
43
- * {@link SUPPRESSED_DIAGNOSTIC_CODES}. Unconditional
44
- * suppression let a module reference a name with no import or declaration
45
- * anywhere and still typecheck with 0 errors — the failure then surfaced
46
- * as a runtime `ReferenceError`. Both flows now report these at a
47
- * configurable severity (default `'warning'`: visible without breaking
48
- * gates; genuine shim gaps are silenced by adding the global to
49
- * `extraShim`, or per-run via the `'off'` setting).
43
+ * {@link SUPPRESSED_DIAGNOSTIC_CODES}. Suppressing them unconditionally lets
44
+ * a module reference a name with no import or declaration anywhere and still
45
+ * typecheck with 0 errors, so the failure surfaces as a runtime
46
+ * `ReferenceError`. Both flows report these at a configurable severity
47
+ * (default `'warning'`: visible without breaking gates; genuine shim gaps
48
+ * are silenced by adding the global to `extraShim`, or per-run via `'off'`).
50
49
  */
51
50
  export declare const UNDEFINED_IDENTIFIER_CODES: ReadonlySet<number>;
52
51
  /** Hint appended to reported undefined-identifier diagnostics. */
@@ -61,25 +60,25 @@ export interface ComposedShim {
61
60
  extraShimAppended: boolean;
62
61
  }
63
62
  /**
64
- * Composes the synthetic shim source by concatenating the built-in
65
- * Firefox globals shim with the contents of an optional user-supplied
66
- * `.d.ts` file. The user file is appended verbatim — the augment
67
- * direction is intentional (declarations later in concat order
68
- * augment earlier ones), so a project that wants to refine `Services`
69
- * with a more specific type can do so by declaring it in the extra
70
- * shim, and members can be ADDED to the structured globals by merging
71
- * their interfaces (`interface ChromeUtilsShim { newMember(): any }` —
72
- * see the module doc comment). Any triple-slash
73
- * `/// <reference path="…">` directives inside the
74
- * extra shim are inlined (resolved against the extra shim's own directory)
75
- * so they are not silently dropped at the synthetic shim path.
63
+ * Composes the synthetic shim source by concatenating the built-in Firefox
64
+ * globals shim with the contents of an optional user-supplied `.d.ts` file.
65
+ * The user file is appended verbatim — the augment direction is intentional
66
+ * (declarations later in concat order augment earlier ones), so a project
67
+ * that wants to refine `Services` with a more specific type can do so in the
68
+ * extra shim, and members can be ADDED to the structured globals by merging
69
+ * their interfaces (`interface ChromeUtilsShim { newMember(): any }` — see
70
+ * the module doc comment). Any triple-slash `/// <reference path="…">`
71
+ * directives inside the extra shim are inlined (resolved against the extra
72
+ * shim's own directory) so they are not silently dropped at the synthetic
73
+ * shim path.
76
74
  *
77
- * Missing extra-shim files raise a clear error rather than failing
78
- * silently with a confusing "type not found" downstream — this is the
79
- * one config-driven path where a user typo in `fireforge.json`
80
- * produces a runtime error, so it needs to be unmistakable.
75
+ * Missing extra-shim files raise a clear error rather than failing silently
76
+ * with a confusing "type not found" downstream — this is the one
77
+ * config-driven path where a user typo in `fireforge.json` produces a
78
+ * runtime error, so it needs to be unmistakable.
81
79
  *
82
- * @param projectRoot - Absolute project root, used to resolve the relative shim path
80
+ * @param projectRoot - Absolute project root, used to resolve the relative
81
+ * shim path
83
82
  * @param extraShimPath - Optional project-relative path to an extra `.d.ts`
84
83
  */
85
84
  export declare function composeShimSource(projectRoot: string, extraShimPath: string | undefined): Promise<ComposedShim>;
@@ -189,13 +189,12 @@ export const SUPPRESSED_DIAGNOSTIC_CODES = new Set([
189
189
  ]);
190
190
  /**
191
191
  * Undefined-free-identifier codes, split out of
192
- * {@link SUPPRESSED_DIAGNOSTIC_CODES}. Unconditional
193
- * suppression let a module reference a name with no import or declaration
194
- * anywhere and still typecheck with 0 errors — the failure then surfaced
195
- * as a runtime `ReferenceError`. Both flows now report these at a
196
- * configurable severity (default `'warning'`: visible without breaking
197
- * gates; genuine shim gaps are silenced by adding the global to
198
- * `extraShim`, or per-run via the `'off'` setting).
192
+ * {@link SUPPRESSED_DIAGNOSTIC_CODES}. Suppressing them unconditionally lets
193
+ * a module reference a name with no import or declaration anywhere and still
194
+ * typecheck with 0 errors, so the failure surfaces as a runtime
195
+ * `ReferenceError`. Both flows report these at a configurable severity
196
+ * (default `'warning'`: visible without breaking gates; genuine shim gaps
197
+ * are silenced by adding the global to `extraShim`, or per-run via `'off'`).
199
198
  */
200
199
  export const UNDEFINED_IDENTIFIER_CODES = new Set([
201
200
  2304, // Cannot find name '{0}'.
@@ -242,25 +241,25 @@ async function inlineTripleSlashReferences(source, baseDir, seen) {
242
241
  return out.join('\n');
243
242
  }
244
243
  /**
245
- * Composes the synthetic shim source by concatenating the built-in
246
- * Firefox globals shim with the contents of an optional user-supplied
247
- * `.d.ts` file. The user file is appended verbatim — the augment
248
- * direction is intentional (declarations later in concat order
249
- * augment earlier ones), so a project that wants to refine `Services`
250
- * with a more specific type can do so by declaring it in the extra
251
- * shim, and members can be ADDED to the structured globals by merging
252
- * their interfaces (`interface ChromeUtilsShim { newMember(): any }` —
253
- * see the module doc comment). Any triple-slash
254
- * `/// <reference path="…">` directives inside the
255
- * extra shim are inlined (resolved against the extra shim's own directory)
256
- * so they are not silently dropped at the synthetic shim path.
244
+ * Composes the synthetic shim source by concatenating the built-in Firefox
245
+ * globals shim with the contents of an optional user-supplied `.d.ts` file.
246
+ * The user file is appended verbatim — the augment direction is intentional
247
+ * (declarations later in concat order augment earlier ones), so a project
248
+ * that wants to refine `Services` with a more specific type can do so in the
249
+ * extra shim, and members can be ADDED to the structured globals by merging
250
+ * their interfaces (`interface ChromeUtilsShim { newMember(): any }` — see
251
+ * the module doc comment). Any triple-slash `/// <reference path="…">`
252
+ * directives inside the extra shim are inlined (resolved against the extra
253
+ * shim's own directory) so they are not silently dropped at the synthetic
254
+ * shim path.
257
255
  *
258
- * Missing extra-shim files raise a clear error rather than failing
259
- * silently with a confusing "type not found" downstream — this is the
260
- * one config-driven path where a user typo in `fireforge.json`
261
- * produces a runtime error, so it needs to be unmistakable.
256
+ * Missing extra-shim files raise a clear error rather than failing silently
257
+ * with a confusing "type not found" downstream — this is the one
258
+ * config-driven path where a user typo in `fireforge.json` produces a
259
+ * runtime error, so it needs to be unmistakable.
262
260
  *
263
- * @param projectRoot - Absolute project root, used to resolve the relative shim path
261
+ * @param projectRoot - Absolute project root, used to resolve the relative
262
+ * shim path
264
263
  * @param extraShimPath - Optional project-relative path to an extra `.d.ts`
265
264
  */
266
265
  export async function composeShimSource(projectRoot, extraShimPath) {
@@ -22,6 +22,7 @@ import { dirname, isAbsolute, relative, resolve } from 'node:path';
22
22
  import { toError } from '../utils/errors.js';
23
23
  import { pathExists } from '../utils/fs.js';
24
24
  import { verbose } from '../utils/logger.js';
25
+ import { normalizePathSlashes } from '../utils/paths.js';
25
26
  import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
26
27
  /**
27
28
  * Sentinel string surfaced as a `TypecheckIssue.message` when the
@@ -89,8 +90,8 @@ export async function runTypecheck(projectRoot, cfg) {
89
90
  // override (a path, or `null` to opt out) when present, else the shared
90
91
  // top-level extraShim. A project that narrows `lib`/`types` can opt out of
91
92
  // a Gecko-lib shim hub that another project needs, so the composed shim is
92
- // no longer injected identically everywhere. Compositions are cached by the
93
- // resolved extraShim path so projects sharing a shim don't recompose it.
93
+ // not injected identically everywhere. Compositions are cached by the
94
+ // resolved extraShim path so projects sharing a shim do not recompose it.
94
95
  const shimCache = new Map();
95
96
  const composeForProject = async (extraShim) => {
96
97
  const key = extraShim ?? '';
@@ -222,12 +223,12 @@ async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource,
222
223
  noEmit: true,
223
224
  allowJs: parsed.options.allowJs ?? true,
224
225
  checkJs: parsed.options.checkJs ?? true,
225
- // No incremental sidecar, ever. A user jsconfig under `engine/` that
226
- // sets `incremental` (or names a `tsBuildInfoFile`)
227
- // would have this command drop a `.tsbuildinfo` inside the primary
228
- // engine checkout — a second writer that invalidates a concurrent
229
- // `fireforge test`'s engine fingerprint. This command emits nothing,
230
- // so the sidecar buys nothing either.
226
+ // No incremental sidecar, ever. A user jsconfig under `engine/` that sets
227
+ // `incremental` (or names a `tsBuildInfoFile`) would have this command
228
+ // drop a `.tsbuildinfo` inside the primary engine checkout — a second
229
+ // writer that invalidates a concurrent `fireforge test`'s engine
230
+ // fingerprint. This command emits nothing, so the sidecar buys nothing
231
+ // either.
231
232
  incremental: false,
232
233
  // skipLibCheck is not forced; the user owns it via their jsconfig.
233
234
  };
@@ -239,7 +240,12 @@ async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource,
239
240
  // file — and never write it to disk. The CompilerHost below serves
240
241
  // it from `shimSource` for `fileExists`/`readFile`/`getSourceFile`.
241
242
  const projectDir = dirname(absConfig);
242
- const shimPath = resolve(projectDir, `.fireforge-${SHIM_FILENAME}`);
243
+ // Forward slashes deliberately: TypeScript normalizes every `fileName` it
244
+ // hands a CompilerHost, on every platform. A shim path carrying Windows
245
+ // separators never matches those callbacks, so the shim is not served (its
246
+ // globals report as undefined identifiers) and its own diagnostics are not
247
+ // filtered out below — the pass reports failures that do not exist.
248
+ const shimPath = normalizePathSlashes(resolve(projectDir, `.fireforge-${SHIM_FILENAME}`));
243
249
  const rootFiles = [...parsed.fileNames, shimPath];
244
250
  const defaultHost = ts.createCompilerHost(options);
245
251
  const host = {
@@ -5,9 +5,9 @@
5
5
  * AST-based implementation: finds onUnload()/uninit() method body and
6
6
  * inserts the destroy block at the top (LIFO ordering).
7
7
  *
8
- * `marker` is prefixed to the generated comment so wire-generated
9
- * edits carry the patch-lint `// <MARKER>:` signature
10
- * `lintModificationComments` looks for (eval 1 Finding #9).
8
+ * `marker` is prefixed to the generated comment so wire-generated edits
9
+ * carry the patch-lint `// <MARKER>:` signature `lintModificationComments`
10
+ * looks for.
11
11
  */
12
12
  export declare function addDestroyAST(content: string, expression: string, marker?: string): string;
13
13
  /**
@@ -9,7 +9,7 @@ import { BuildError } from '../errors/build.js';
9
9
  import { pathExists, readText, writeText } from '../utils/fs.js';
10
10
  import { escapeRegex } from '../utils/regex.js';
11
11
  import { asEstree, detectIndent, parseScript } from './ast-utils.js';
12
- import { withParserFallback } from './parser-fallback.js';
12
+ import { isInternalInvariantFailure, withParserFallback } from './parser-fallback.js';
13
13
  import { assertBraceBalancePreserved, coerceToCall, extractNameFromExpression, findMethodBody, findMethodBraceIndex, validateWireName, } from './wire-utils.js';
14
14
  const BROWSER_INIT_JS = 'browser/base/content/browser-init.js';
15
15
  const DEFAULT_MARKER = 'FIREFORGE:';
@@ -17,9 +17,9 @@ const DEFAULT_MARKER = 'FIREFORGE:';
17
17
  * AST-based implementation: finds onUnload()/uninit() method body and
18
18
  * inserts the destroy block at the top (LIFO ordering).
19
19
  *
20
- * `marker` is prefixed to the generated comment so wire-generated
21
- * edits carry the patch-lint `// <MARKER>:` signature
22
- * `lintModificationComments` looks for (eval 1 Finding #9).
20
+ * `marker` is prefixed to the generated comment so wire-generated edits
21
+ * carry the patch-lint `// <MARKER>:` signature `lintModificationComments`
22
+ * looks for.
23
23
  */
24
24
  export function addDestroyAST(content, expression, marker = DEFAULT_MARKER) {
25
25
  const name = extractNameFromExpression(expression);
@@ -110,22 +110,14 @@ export async function addDestroyToBrowserInit(engineDir, expression, marker = DE
110
110
  const content = await readText(filePath);
111
111
  // Idempotency check — look for the coerced (call) form because that is
112
112
  // what the emitter writes. Matching against the raw input would miss a
113
- // previous `EvalStartup.destroy` invocation that the 0.16.0 coercion
114
- // already persisted as `EvalStartup.destroy()`.
113
+ // bare `X.destroy` invocation that coercion already persisted as
114
+ // `X.destroy()`.
115
115
  const callExpression = coerceToCall(expression);
116
116
  const destroyPattern = new RegExp(`(?:^|\\W)${escapeRegex(callExpression)}\\s*;?\\s*$`, 'm');
117
117
  if (destroyPattern.test(content)) {
118
118
  return false;
119
119
  }
120
- const { value, usedFallback } = withParserFallback(() => addDestroyAST(content, expression, marker), () => legacyAddDestroy(content, expression, marker), BROWSER_INIT_JS,
121
- // Rethrow only the internal-invariant GeneralErrors ("Unexpected empty
122
- // …array"): those are programming bugs, and retrying the legacy scanner
123
- // cannot fix a broken invariant — it just buries the stack. Everything
124
- // else still falls back, which is load-bearing: the AST path raises a raw
125
- // acorn SyntaxError on chrome sources acorn cannot parse (preprocessor
126
- // directives), and BuildError when the file's shape is unexpected. Both
127
- // are exactly what the legacy scanner is here to handle.
128
- (error) => error instanceof GeneralError);
120
+ const { value, usedFallback } = withParserFallback(() => addDestroyAST(content, expression, marker), () => legacyAddDestroy(content, expression, marker), BROWSER_INIT_JS, isInternalInvariantFailure);
129
121
  if (usedFallback) {
130
122
  assertBraceBalancePreserved(content, value, BROWSER_INIT_JS);
131
123
  }
@@ -13,24 +13,16 @@ export declare const DEFAULT_DOM_TARGET = "browser/base/content/browser.xhtml";
13
13
  */
14
14
  export declare function addDomFragmentTokenized(content: string, includeDirective: string): string;
15
15
  /**
16
- * Legacy line-based implementation preserved as fallback.
17
- */
18
- export declare function legacyAddDomFragment(content: string, includeDirective: string): string;
19
- /**
20
- * Dry-run precheck for `addDomFragment`. Reads the resolved chrome
21
- * document and verifies it either already contains the `#include`
22
- * directive (the idempotent-skip case) OR offers a locatable insertion
23
- * point via {@link addDomFragmentTokenized} / {@link legacyAddDomFragment}.
24
- * Throws the same `Could not find insertion point in chrome document`
25
- * error the real run would throw when neither condition holds.
16
+ * Dry-run precheck for `addDomFragment`. Reads the resolved chrome document
17
+ * and verifies it either already contains the `#include` directive (the
18
+ * idempotent-skip case) OR offers a locatable insertion point via
19
+ * {@link addDomFragmentTokenized} / {@link legacyAddDomFragment}. Throws the
20
+ * same `Could not find insertion point in chrome document` error the real
21
+ * run would throw when neither condition holds.
26
22
  *
27
- * Motivating case (2026-04-21 eval, Finding #12): `fireforge wire ...
28
- * --dry-run` previewed a plausible mutation plan against
29
- * `tokenHostDocuments[0]`, then `fireforge wire ...` without
30
- * `--dry-run` threw `Could not find insertion point in chrome document`
31
- * on the same arguments. The real run had always called the insertion
32
- * helpers; dry-run did not. This helper runs the same check in the
33
- * preview pass so plan and execution disagree less.
23
+ * Without it, `wire --dry-run` previews a plausible mutation plan while the
24
+ * real run throws on the same arguments, because only the real run called
25
+ * the insertion helpers.
34
26
  */
35
27
  export declare function probeDomFragmentInsertionPoint(engineDir: string, domFilePath: string, targetPath?: string): Promise<void>;
36
28
  /**
@@ -13,7 +13,6 @@ import { GeneralError } from '../errors/base.js';
13
13
  import { pathExists, readText, writeText } from '../utils/fs.js';
14
14
  import { toRootRelativePath } from '../utils/paths.js';
15
15
  import { escapeRegex } from '../utils/regex.js';
16
- import { withParserFallback } from './parser-fallback.js';
17
16
  import { tokenizeXhtml } from './wire-utils.js';
18
17
  export const DEFAULT_DOM_TARGET = 'browser/base/content/browser.xhtml';
19
18
  /**
@@ -48,48 +47,16 @@ export function addDomFragmentTokenized(content, includeDirective) {
48
47
  return lines.join('\n');
49
48
  }
50
49
  /**
51
- * Legacy line-based implementation preserved as fallback.
52
- */
53
- export function legacyAddDomFragment(content, includeDirective) {
54
- const lines = content.split('\n');
55
- let insertIndex = -1;
56
- for (let i = 0; i < lines.length; i++) {
57
- const line = lines[i] ?? '';
58
- if (/browser-sets\.inc/.test(line)) {
59
- insertIndex = i;
60
- break;
61
- }
62
- }
63
- if (insertIndex === -1) {
64
- for (let i = 0; i < lines.length; i++) {
65
- const line = lines[i] ?? '';
66
- if (/<html:body/.test(line)) {
67
- insertIndex = i + 1;
68
- break;
69
- }
70
- }
71
- }
72
- if (insertIndex === -1) {
73
- throw new GeneralError('Could not find insertion point in chrome document');
74
- }
75
- lines.splice(insertIndex, 0, includeDirective);
76
- return lines.join('\n');
77
- }
78
- /**
79
- * Dry-run precheck for `addDomFragment`. Reads the resolved chrome
80
- * document and verifies it either already contains the `#include`
81
- * directive (the idempotent-skip case) OR offers a locatable insertion
82
- * point via {@link addDomFragmentTokenized} / {@link legacyAddDomFragment}.
83
- * Throws the same `Could not find insertion point in chrome document`
84
- * error the real run would throw when neither condition holds.
50
+ * Dry-run precheck for `addDomFragment`. Reads the resolved chrome document
51
+ * and verifies it either already contains the `#include` directive (the
52
+ * idempotent-skip case) OR offers a locatable insertion point via
53
+ * {@link addDomFragmentTokenized} / {@link legacyAddDomFragment}. Throws the
54
+ * same `Could not find insertion point in chrome document` error the real
55
+ * run would throw when neither condition holds.
85
56
  *
86
- * Motivating case (2026-04-21 eval, Finding #12): `fireforge wire ...
87
- * --dry-run` previewed a plausible mutation plan against
88
- * `tokenHostDocuments[0]`, then `fireforge wire ...` without
89
- * `--dry-run` threw `Could not find insertion point in chrome document`
90
- * on the same arguments. The real run had always called the insertion
91
- * helpers; dry-run did not. This helper runs the same check in the
92
- * preview pass so plan and execution disagree less.
57
+ * Without it, `wire --dry-run` previews a plausible mutation plan while the
58
+ * real run throws on the same arguments, because only the real run called
59
+ * the insertion helpers.
93
60
  */
94
61
  export async function probeDomFragmentInsertionPoint(engineDir, domFilePath, targetPath = DEFAULT_DOM_TARGET) {
95
62
  const targetAbsPath = join(engineDir, targetPath);
@@ -113,7 +80,7 @@ export async function probeDomFragmentInsertionPoint(engineDir, domFilePath, tar
113
80
  // Check the tokenised and legacy insertion paths symmetrically with
114
81
  // the real run. Either helper returning without throwing is sufficient
115
82
  // evidence that the real run can land the directive.
116
- withParserFallback(() => addDomFragmentTokenized(content, includeDirective), () => legacyAddDomFragment(content, includeDirective), targetPath);
83
+ addDomFragmentTokenized(content, includeDirective);
117
84
  }
118
85
  /**
119
86
  * Inserts a `#include` directive for an `.inc.xhtml` file into the top-level
@@ -177,7 +144,7 @@ export async function addDomFragment(engineDir, domFilePath, targetPath = DEFAUL
177
144
  }
178
145
  }
179
146
  // Normal insertion
180
- const { value } = withParserFallback(() => addDomFragmentTokenized(content, includeDirective), () => legacyAddDomFragment(content, includeDirective), targetPath);
147
+ const value = addDomFragmentTokenized(content, includeDirective);
181
148
  await writeText(targetAbsPath, value);
182
149
  return true;
183
150
  }
@@ -8,9 +8,8 @@
8
8
  *
9
9
  * `marker` is prepended (uppercased) to the generated comment line so the
10
10
  * emitted block carries the patch-lint `// <MARKER>:` signature that
11
- * `lintModificationComments` looks for. Otherwise the first export after
12
- * `wire` trips `missing-modification-comment` on wire-generated edits —
13
- * exactly the eval 1 Finding #9 regression.
11
+ * `lintModificationComments` looks for; otherwise the first export after
12
+ * `wire` trips `missing-modification-comment` on wire-generated edits.
14
13
  */
15
14
  export declare function addInitAST(content: string, expression: string, after?: string, marker?: string): string;
16
15
  /**