@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,30 +1,29 @@
1
1
  /**
2
2
  * Toolchain-minimum awareness for Firefox source hops.
3
3
  *
4
- * When `fireforge download --force` moves the engine to a new Firefox
5
- * MAJOR version, the tree's declared toolchain minimums (cbindgen, Rust)
6
- * frequently move with it — and the first `fireforge build` then dies a
7
- * few seconds into `mach configure` with a message whose remediation
8
- * text names `./mach bootstrap`, the wrong tool for a FireForge-managed
9
- * repo (152.0b7 → 153.0b8 source-refresh drill: `ERROR: cbindgen version
10
- * 0.29.1 is too old. At least version 0.29.4 is required.`).
4
+ * When `fireforge download --force` moves the engine to a new Firefox MAJOR
5
+ * version, the tree's declared toolchain minimums (cbindgen, Rust)
6
+ * frequently move with it — and the first `fireforge build` then dies a few
7
+ * seconds into `mach configure` with a message whose remediation text names
8
+ * `./mach bootstrap`, the wrong tool for a FireForge-managed repo (e.g.
9
+ * `ERROR: cbindgen version 0.29.1 is too old. At least version 0.29.4 is
10
+ * required.`).
11
11
  *
12
12
  * Two layers:
13
- * 1. {@link formatMajorVersionHopNotice} — a post-download nudge when
14
- * the downloaded major differs from the previously downloaded one.
15
- * 2. {@link runToolchainPreflight} — a cheap pre-build probe comparing
16
- * the minimums the tree itself declares against the host binaries
13
+ * 1. {@link formatMajorVersionHopNotice} — a post-download nudge when the
14
+ * downloaded major differs from the previously downloaded one.
15
+ * 2. {@link runToolchainPreflight} — a cheap pre-build probe comparing the
16
+ * minimums the tree itself declares against the host binaries
17
17
  * `mach configure` will resolve, probing configure's own candidate
18
- * order: env override first, then the `~/.mozbuild` state-directory
19
- * copy bootstrap installs, then PATH (0.35.0 probed env-or-PATH
20
- * only, blocking builds whose current tool lived in the state dir
21
- * behind a stale PATH copy). Deliberately FAIL-SOFT: it reports a
22
- * mismatch only when a minimum was positively parsed AND at least
23
- * one candidate resolved AND every resolved candidate is
24
- * definitively lower. Any uncertainty (file moved upstream,
25
- * unparseable output, no candidate found) skips silently — the
26
- * mach-error-hints translator still catches the real configure
27
- * failure downstream.
18
+ * order: env override first, then the `~/.mozbuild` state-directory copy
19
+ * bootstrap installs, then PATH. Probing env-or-PATH alone blocks builds
20
+ * whose current tool lives in the state dir behind a stale PATH copy.
21
+ * Deliberately FAIL-SOFT: it reports a mismatch only when a minimum was
22
+ * positively parsed AND at least one candidate resolved AND every
23
+ * resolved candidate is definitively lower. Any uncertainty (file moved
24
+ * upstream, unparseable output, no candidate found) skips silently — the
25
+ * mach-error-hints translator still catches the real configure failure
26
+ * downstream.
28
27
  */
29
28
  /** Tools the preflight knows how to probe. */
30
29
  export type ToolchainTool = 'cbindgen' | 'rustc';
@@ -2,30 +2,29 @@
2
2
  /**
3
3
  * Toolchain-minimum awareness for Firefox source hops.
4
4
  *
5
- * When `fireforge download --force` moves the engine to a new Firefox
6
- * MAJOR version, the tree's declared toolchain minimums (cbindgen, Rust)
7
- * frequently move with it — and the first `fireforge build` then dies a
8
- * few seconds into `mach configure` with a message whose remediation
9
- * text names `./mach bootstrap`, the wrong tool for a FireForge-managed
10
- * repo (152.0b7 → 153.0b8 source-refresh drill: `ERROR: cbindgen version
11
- * 0.29.1 is too old. At least version 0.29.4 is required.`).
5
+ * When `fireforge download --force` moves the engine to a new Firefox MAJOR
6
+ * version, the tree's declared toolchain minimums (cbindgen, Rust)
7
+ * frequently move with it — and the first `fireforge build` then dies a few
8
+ * seconds into `mach configure` with a message whose remediation text names
9
+ * `./mach bootstrap`, the wrong tool for a FireForge-managed repo (e.g.
10
+ * `ERROR: cbindgen version 0.29.1 is too old. At least version 0.29.4 is
11
+ * required.`).
12
12
  *
13
13
  * Two layers:
14
- * 1. {@link formatMajorVersionHopNotice} — a post-download nudge when
15
- * the downloaded major differs from the previously downloaded one.
16
- * 2. {@link runToolchainPreflight} — a cheap pre-build probe comparing
17
- * the minimums the tree itself declares against the host binaries
14
+ * 1. {@link formatMajorVersionHopNotice} — a post-download nudge when the
15
+ * downloaded major differs from the previously downloaded one.
16
+ * 2. {@link runToolchainPreflight} — a cheap pre-build probe comparing the
17
+ * minimums the tree itself declares against the host binaries
18
18
  * `mach configure` will resolve, probing configure's own candidate
19
- * order: env override first, then the `~/.mozbuild` state-directory
20
- * copy bootstrap installs, then PATH (0.35.0 probed env-or-PATH
21
- * only, blocking builds whose current tool lived in the state dir
22
- * behind a stale PATH copy). Deliberately FAIL-SOFT: it reports a
23
- * mismatch only when a minimum was positively parsed AND at least
24
- * one candidate resolved AND every resolved candidate is
25
- * definitively lower. Any uncertainty (file moved upstream,
26
- * unparseable output, no candidate found) skips silently — the
27
- * mach-error-hints translator still catches the real configure
28
- * failure downstream.
19
+ * order: env override first, then the `~/.mozbuild` state-directory copy
20
+ * bootstrap installs, then PATH. Probing env-or-PATH alone blocks builds
21
+ * whose current tool lives in the state dir behind a stale PATH copy.
22
+ * Deliberately FAIL-SOFT: it reports a mismatch only when a minimum was
23
+ * positively parsed AND at least one candidate resolved AND every
24
+ * resolved candidate is definitively lower. Any uncertainty (file moved
25
+ * upstream, unparseable output, no candidate found) skips silently — the
26
+ * mach-error-hints translator still catches the real configure failure
27
+ * downstream.
29
28
  */
30
29
  import { execFile } from 'node:child_process';
31
30
  import { homedir } from 'node:os';
@@ -61,16 +60,14 @@ const MINIMUM_DECLARATIONS = {
61
60
  /**
62
61
  * How each tool's host binary is resolved and its version parsed.
63
62
  *
64
- * `stateDirRelPaths` are the mach-state-directory locations `fireforge
65
- * bootstrap` (via mozboot) installs the tool to. mach's configure tries
66
- * the state directory BEFORE the PATH candidates (bindgen.configure's
67
- * toolchain search path lists `~/.mozbuild/cbindgen/cbindgen` first — a
68
- * configure log shows `trying cbindgen: ~/.mozbuild/cbindgen/cbindgen`
69
- * ahead of PATH), so the probe must too. 0.35.0 probed only env-or-PATH,
70
- * which failed a build configure would have accepted whenever an old
71
- * `~/.cargo/bin/cbindgen` shadowed a current bootstrap-installed copy
72
- * (field report: PATH 0.29.1 vs mozbuild 0.29.4, minimum 0.29.4). Rust
73
- * has no state-dir install — rustup owns it — so its list is empty.
63
+ * `stateDirRelPaths` are the mach-state-directory locations
64
+ * `fireforge bootstrap` (via mozboot) installs the tool to. mach's configure
65
+ * tries the state directory BEFORE the PATH candidates —
66
+ * bindgen.configure's toolchain search path lists `~/.mozbuild/cbindgen/
67
+ * cbindgen` first — so the probe must too. Probing only env-or-PATH fails a
68
+ * build configure would have accepted whenever an old `~/.cargo/bin/
69
+ * cbindgen` shadows a current bootstrap-installed copy. Rust has no
70
+ * state-dir install — rustup owns it — so its list is empty.
74
71
  */
75
72
  const HOST_PROBES = {
76
73
  // `mach configure` honours the CBINDGEN env option (bindgen.configure's
@@ -15,7 +15,7 @@
15
15
  import { existsSync } from 'node:fs';
16
16
  import { dirname, join, resolve } from 'node:path';
17
17
  import { GeneralError } from '../errors/base.js';
18
- import { getTreeMarkerPath, readTreeMarkerState, } from './tree-store.js';
18
+ import { getTreeMarkerPath, readTreeMarker, } from './tree-store.js';
19
19
  /**
20
20
  * Per-command verdicts. `allowed` runs unconditionally; `refused` never
21
21
  * runs in a tree; `conditional` consults `TREE_CONDITIONAL_CHECKS` with
@@ -135,7 +135,7 @@ export async function runTreeGuardHook(rootCommandName, actionCommand) {
135
135
  let current = resolve(process.cwd());
136
136
  for (let depth = 0; depth < 50; depth++) {
137
137
  if (existsSync(join(current, 'fireforge.json'))) {
138
- return { root: current, state: await readTreeMarkerState(current) };
138
+ return { root: current, state: await readTreeMarker(current) };
139
139
  }
140
140
  const parent = dirname(current);
141
141
  if (parent === current)
@@ -153,6 +153,16 @@ export async function runTreeGuardHook(rootCommandName, actionCommand) {
153
153
  // evidence that we cannot tell. Treating it as "not a tree" would grant the
154
154
  // full mutating command set to a snapshot on the strength of a file that
155
155
  // failed to parse, which is exactly backwards for a default-deny guard.
156
+ // A marker from a NEWER FireForge is not damaged, so the corrupt branch's
157
+ // remedies — recreate the tree, delete the stray marker — are actively
158
+ // wrong for it. Refuse with the upgrade instruction instead, and do NOT
159
+ // offer --ignore-corrupt-tree-marker: proceeding would mean acting on a
160
+ // marker whose fields this build does not understand.
161
+ if (state.kind === 'unsupported') {
162
+ if (TREE_COMMAND_VERDICTS[commandName] === 'allowed')
163
+ return;
164
+ throw new GeneralError(`Refusing "${[commandName, ...subcommands].join(' ')}": ${state.reason}`);
165
+ }
156
166
  if (state.kind === 'corrupt') {
157
167
  if (options['ignoreCorruptTreeMarker'] === true)
158
168
  return;
@@ -33,13 +33,13 @@ export declare function withTreeLifecycleLock<T>(primaryRoot: string, operation:
33
33
  * Outcome of reading a tree marker.
34
34
  *
35
35
  * The three states must stay distinct because they carry opposite safety
36
- * meanings. `absent` means "this directory is not a tree", which is what lets
37
- * every mutating command run. `corrupt` means "this directory claims to be a
38
- * tree but we cannot read the claim" — collapsing it into `absent` (as a bare
39
- * `undefined` return does) hands a snapshot the full mutating command set on
40
- * the strength of a file we failed to parse, inverting `tree-guard.ts`'s
41
- * default-deny design. Deleting one field from a marker was enough to run
42
- * `reset` inside a clone.
36
+ * meanings. `absent` means "this directory is not a tree", which is what
37
+ * lets every mutating command run. `corrupt` means "this directory claims to
38
+ * be a tree but we cannot read the claim" — collapsing it into `absent` (as
39
+ * a bare `undefined` return does) hands a snapshot the full mutating command
40
+ * set on the strength of a file we failed to parse, inverting
41
+ * `tree-guard.ts`'s default-deny design. Deleting one field from a marker is
42
+ * enough to make `reset` runnable inside a clone.
43
43
  */
44
44
  export type TreeMarkerRead = {
45
45
  kind: 'absent';
@@ -49,31 +49,45 @@ export type TreeMarkerRead = {
49
49
  } | {
50
50
  kind: 'corrupt';
51
51
  reason: string;
52
+ }
53
+ /**
54
+ * Written by a NEWER FireForge. Distinct from `corrupt` because the remedy
55
+ * is the opposite: upgrade, do not delete.
56
+ */
57
+ | {
58
+ kind: 'unsupported';
59
+ reason: string;
52
60
  };
53
61
  /** Absolute path of a root's tree marker. */
54
62
  export declare function getTreeMarkerPath(root: string): string;
55
63
  /**
56
64
  * Reads the tree marker for a project root, distinguishing "not a tree" from
57
- * "a tree whose marker we could not read". Callers that make a safety decision
58
- * (the guard hook, the no-nesting refusal) must use this rather than
59
- * {@link readTreeMarker}.
65
+ * "a tree whose marker we could not read". Callers that make a safety
66
+ * decision (the guard hook, the no-nesting refusal) must use this rather
67
+ * than {@link tryReadTreeMarker}.
60
68
  *
61
69
  * Only ENOENT/ENOTDIR mean `absent`: any other probe failure (EACCES on the
62
70
  * `.fireforge` directory, EIO, …) reports `corrupt`, because "we cannot read
63
71
  * the marker" is not evidence that there is no marker — a `pathExists`
64
- * pre-check here classified a tree with an unreadable `.fireforge` as
65
- * `absent` and handed it the full mutating command set.
72
+ * pre-check classifies a tree with an unreadable `.fireforge` as `absent`
73
+ * and hands it the full mutating command set.
66
74
  */
67
- export declare function readTreeMarkerState(root: string): Promise<TreeMarkerRead>;
75
+ /**
76
+ * Naming convention for state-file readers:
77
+ * - `readX(): Promise<XRead>` — the TRI-STATE read: absent, corrupt, or
78
+ * valid.
79
+ * - `tryReadX(): Promise<X | undefined>` — collapses absent and corrupt.
80
+ */
81
+ export declare function readTreeMarker(root: string): Promise<TreeMarkerRead>;
68
82
  /**
69
83
  * Reads the tree marker for a project root, or undefined when it is absent
70
84
  * OR unreadable.
71
85
  *
72
86
  * For display and best-effort paths only (`tree list` renders an unreadable
73
87
  * marker as staleness 'unknown'). Anything that decides whether a mutation may
74
- * proceed must call {@link readTreeMarkerState} and handle `corrupt`.
88
+ * proceed must call {@link readTreeMarker} and handle `corrupt`.
75
89
  */
76
- export declare function readTreeMarker(root: string): Promise<TreeMarker | undefined>;
90
+ export declare function tryReadTreeMarker(root: string): Promise<TreeMarker | undefined>;
77
91
  /**
78
92
  * Refuses a build-less in-tree `test` when the objdir preflight found is not
79
93
  * the one this tree's marker vouched for as rewritten-and-reconfigured. A
@@ -92,18 +106,18 @@ export declare function computePrimaryFingerprint(primaryRoot: string): Promise<
92
106
  /** Validates a tree name: one path segment, no traversal. */
93
107
  export declare function assertValidTreeName(name: string): void;
94
108
  /**
95
- * Materialises the tree at `treeRoot` from `primaryRoot` using
96
- * `capability` ('none' = plain copy, already gated on --force-copy by
97
- * the caller). The engine is cloned one TOP-LEVEL entry at a time so unwanted
98
- * `obj-*` directories are never traversed or materialised. That distinction
99
- * is substantial on Firefox trees: even CoW-cloning and deleting an objdir
100
- * touches metadata for millions of build outputs. With `withObjdir` exactly
101
- * that objdir is included — after {@link assertCloneSafeObjdir}
102
- * refuses symlinked or engine-escaping objdirs before any copying —
103
- * rewritten to the tree (see below), and
104
- * reconfigured in-tree via the caller-supplied `reconfigure` hook. A
105
- * fresh `.fireforge/` is created with only `state.json` (when present),
106
- * the last-build baseline (withObjdir only), and the tree marker.
109
+ * Materialises the tree at `treeRoot` from `primaryRoot` using `capability`
110
+ * ('none' = plain copy, already gated on --force-copy by the caller).
111
+ *
112
+ * The engine is cloned one TOP-LEVEL entry at a time so unwanted `obj-*`
113
+ * directories are never traversed or materialised — on a Firefox tree, even
114
+ * CoW-cloning and then deleting an objdir touches metadata for millions of
115
+ * build outputs. With `withObjdir` exactly that objdir is included (after
116
+ * {@link assertCloneSafeObjdir} refuses symlinked or engine-escaping objdirs
117
+ * before any copying), rewritten to the tree, and reconfigured in-tree via
118
+ * the caller-supplied `reconfigure` hook. A fresh `.fireforge/` is created
119
+ * with only `state.json` (when present), the last-build baseline (withObjdir
120
+ * only), and the tree marker.
107
121
  */
108
122
  export declare function cloneTree(args: {
109
123
  primaryRoot: string;
@@ -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))
@@ -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) {
@@ -89,8 +89,8 @@ export async function runTypecheck(projectRoot, cfg) {
89
89
  // override (a path, or `null` to opt out) when present, else the shared
90
90
  // top-level extraShim. A project that narrows `lib`/`types` can opt out of
91
91
  // 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.
92
+ // not injected identically everywhere. Compositions are cached by the
93
+ // resolved extraShim path so projects sharing a shim do not recompose it.
94
94
  const shimCache = new Map();
95
95
  const composeForProject = async (extraShim) => {
96
96
  const key = extraShim ?? '';
@@ -222,12 +222,12 @@ async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource,
222
222
  noEmit: true,
223
223
  allowJs: parsed.options.allowJs ?? true,
224
224
  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.
225
+ // No incremental sidecar, ever. A user jsconfig under `engine/` that sets
226
+ // `incremental` (or names a `tsBuildInfoFile`) would have this command
227
+ // drop a `.tsbuildinfo` inside the primary engine checkout — a second
228
+ // writer that invalidates a concurrent `fireforge test`'s engine
229
+ // fingerprint. This command emits nothing, so the sidecar buys nothing
230
+ // either.
231
231
  incremental: false,
232
232
  // skipLibCheck is not forced; the user owns it via their jsconfig.
233
233
  };