@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
@@ -7,15 +7,14 @@
7
7
  * Every helper here degrades gracefully: if the locale jar.mn is missing or
8
8
  * the FTL tree is non-standard, apply logs an ADVISORY `stepError`
9
9
  * (`advisory: true`) rather than aborting the whole command. Advisory step
10
- * errors are reported as warnings and never trigger rollback — missing
11
- * jar.mn on a fork without a locale package should not block a working
12
- * `.mjs`/`.css` from shipping (the blocking/advisory split exists because
13
- * this contract used to be contradicted: any FTL step error rolled back
14
- * the whole apply).
10
+ * errors are reported as warnings and never trigger rollback — a missing
11
+ * jar.mn on a fork without a locale package must not block a working
12
+ * `.mjs`/`.css` from shipping.
15
13
  */
16
14
  import { join, relative } from 'node:path';
17
15
  import { toError } from '../utils/errors.js';
18
16
  import { copyFile, pathExists, readText } from '../utils/fs.js';
17
+ import { normalizePathSlashes } from '../utils/paths.js';
19
18
  import { escapeRegex } from '../utils/regex.js';
20
19
  import { resolveFtlChromeSubPath, resolveFtlLocaleJarMnPath } from './furnace-constants.js';
21
20
  import { addLocaleFtlJarMnEntry, removeLocaleFtlJarMnEntry } from './furnace-registration.js';
@@ -46,10 +45,9 @@ function resolveSharedFtlPruneTarget(name, ftlDir) {
46
45
  * A `localized: true` widget that opts into a feature-scoped `sharedFtl`
47
46
  * bundle (its strings live under `browser/...` and load via
48
47
  * `insertFTLIfNeeded`) must NOT carry a per-widget
49
- * `locale/@AB_CD@/<chromeSubPath>/<name>.ftl` line. Such a line — written by
50
- * an older FireForge before the sharedFtl apply guard, or by a layout
51
- * migration — points at a `.ftl` that does not exist, so `mach build` fails
52
- * hard (`Cannot find <chromeSubPath>/<name>.ftl`) and blocks every build.
48
+ * `locale/@AB_CD@/<chromeSubPath>/<name>.ftl` line. Such a line points at a
49
+ * `.ftl` that does not exist, so `mach build` fails hard (`Cannot find
50
+ * <chromeSubPath>/<name>.ftl`) and blocks every build.
53
51
  *
54
52
  * The pruned line is the per-widget toolkit entry only; the shared bundle's
55
53
  * own line (a different chrome sub-path / base name) is never matched, so
@@ -83,7 +81,8 @@ async function pruneSharedFtlPerWidgetLocaleEntry(engineDir, name, ftlDir, confi
83
81
  * records the affected path / step error in the caller's collectors, mirroring
84
82
  * {@link applyCustomFtlFile}'s contract so the main apply helper stays terse.
85
83
  */
86
- export async function applySharedFtlPrune(engineDir, name, ftlDir, config, affectedPaths, stepErrors, rollbackJournal) {
84
+ export async function applySharedFtlPrune(ctx, config, affectedPaths, stepErrors, rollbackJournal) {
85
+ const { engineDir, name, ftlDir } = ctx;
87
86
  try {
88
87
  const prunedPath = await pruneSharedFtlPerWidgetLocaleEntry(engineDir, name, ftlDir, config, rollbackJournal);
89
88
  if (prunedPath)
@@ -98,7 +97,8 @@ export async function applySharedFtlPrune(engineDir, name, ftlDir, config, affec
98
97
  * returns an action when a dangling per-widget locale entry exists for a
99
98
  * `sharedFtl` widget, else `undefined`.
100
99
  */
101
- export async function describeSharedFtlPrune(engineDir, name, ftlDir, config) {
100
+ export async function describeSharedFtlPrune(ctx, config) {
101
+ const { engineDir, name, ftlDir } = ctx;
102
102
  if (!config.sharedFtl)
103
103
  return undefined;
104
104
  const target = resolveSharedFtlPruneTarget(name, ftlDir);
@@ -123,7 +123,8 @@ export async function describeSharedFtlPrune(engineDir, name, ftlDir, config) {
123
123
  * stepErrors rather than thrown — a well-formed `.mjs`/`.css` must never be
124
124
  * blocked by a broken locale path.
125
125
  */
126
- export async function applyCustomFtlFile(engineDir, name, componentDir, ftlDir, affectedPaths, stepErrors, rollbackJournal) {
126
+ export async function applyCustomFtlFile(ctx, affectedPaths, stepErrors, rollbackJournal) {
127
+ const { engineDir, name, componentDir, ftlDir } = ctx;
127
128
  const ftlFile = `${name}.ftl`;
128
129
  const ftlSrc = join(componentDir, ftlFile);
129
130
  if (!(await pathExists(ftlSrc)))
@@ -133,7 +134,9 @@ export async function applyCustomFtlFile(engineDir, name, componentDir, ftlDir,
133
134
  await snapshotFile(rollbackJournal, ftlDest);
134
135
  }
135
136
  await copyFile(ftlSrc, ftlDest);
136
- affectedPaths.push(relative(engineDir, ftlDest));
137
+ // Sibling pushes on this list are POSIX literals (`localeJarRel`); keep
138
+ // the computed one in the same spelling.
139
+ affectedPaths.push(normalizePathSlashes(relative(engineDir, ftlDest)));
137
140
  const chromeSubPath = resolveFtlChromeSubPath(ftlDir);
138
141
  const localeJarRel = resolveFtlLocaleJarMnPath(ftlDir);
139
142
  if (chromeSubPath === undefined || localeJarRel === undefined)
@@ -1,4 +1,4 @@
1
- import type { CustomComponentConfig, DryRunAction, OverrideComponentConfig, StepError } from '../types/furnace.js';
1
+ import type { ComponentApplyContext, CustomComponentConfig, DryRunAction, OverrideComponentConfig, StepError } from '../types/furnace.js';
2
2
  import { type RollbackJournal } from './furnace-rollback.js';
3
3
  interface DirectoryEntry {
4
4
  isFile(): boolean;
@@ -7,8 +7,8 @@ interface DirectoryEntry {
7
7
  }
8
8
  /**
9
9
  * True for a plain-file directory entry — symlinks and directories are
10
- * never copy candidates. Exported for the patch-owned overwrite probe
11
- *, which walks the same override copy-candidate set as apply.
10
+ * never copy candidates. Exported for the patch-owned overwrite probe,
11
+ * which walks the same override copy-candidate set as apply.
12
12
  */
13
13
  export declare function isRegularFile(entry: DirectoryEntry): boolean;
14
14
  /**
@@ -86,14 +86,14 @@ export declare function hasComponentChanged(componentDir: string, previousChecks
86
86
  * the comparison when the engine hash still matches, which is the common case
87
87
  * for projects with many components.
88
88
  */
89
- export declare function hasOverrideEngineDrift(engineDir: string, componentDir: string, config: OverrideComponentConfig, ftlDir: string, cachedEngineChecksums?: Record<string, string>): Promise<boolean>;
89
+ export declare function hasOverrideEngineDrift(ctx: Pick<ComponentApplyContext, 'engineDir' | 'componentDir' | 'ftlDir'>, config: OverrideComponentConfig, cachedEngineChecksums?: Record<string, string>): Promise<boolean>;
90
90
  /**
91
91
  * Detects whether a custom component's deployed copies, jar.mn entries, or
92
92
  * customElements.js registration are missing from the engine or out of sync.
93
93
  * Delegates to `checkRegistrationConsistency` so the oracle stays aligned with
94
94
  * the validate command.
95
95
  */
96
- export declare function hasCustomEngineDrift(root: string, name: string, componentDir: string, config: CustomComponentConfig, ftlDir: string): Promise<boolean>;
96
+ export declare function hasCustomEngineDrift(ctx: Pick<ComponentApplyContext, 'root' | 'name' | 'componentDir' | 'ftlDir'>, config: CustomComponentConfig): Promise<boolean>;
97
97
  /** Extra knobs threaded into `applyCustomComponent` from the project config. */
98
98
  export interface CustomApplyOptions {
99
99
  /**
@@ -104,13 +104,13 @@ export interface CustomApplyOptions {
104
104
  markerComment?: string;
105
105
  }
106
106
  /** Applies a custom component into the engine tree and captures registration step errors. */
107
- export declare function applyCustomComponent(engineDir: string, name: string, componentDir: string, config: CustomComponentConfig, ftlDir: string, dryRun?: boolean, rollbackJournal?: RollbackJournal, applyOptions?: CustomApplyOptions): Promise<{
107
+ export declare function applyCustomComponent(ctx: Pick<ComponentApplyContext, 'engineDir' | 'name' | 'componentDir' | 'ftlDir'>, config: CustomComponentConfig, dryRun?: boolean, rollbackJournal?: RollbackJournal, applyOptions?: CustomApplyOptions): Promise<{
108
108
  affectedPaths: string[];
109
109
  stepErrors: StepError[];
110
110
  actions?: DryRunAction[];
111
111
  }>;
112
112
  /** Applies an override component by copying its matching files onto the engine tree. */
113
- export declare function applyOverrideComponent(engineDir: string, name: string, componentDir: string, config: OverrideComponentConfig, ftlDir: string, dryRun?: boolean, rollbackJournal?: RollbackJournal): Promise<{
113
+ export declare function applyOverrideComponent(ctx: Pick<ComponentApplyContext, 'engineDir' | 'name' | 'componentDir' | 'ftlDir'>, config: OverrideComponentConfig, dryRun?: boolean, rollbackJournal?: RollbackJournal): Promise<{
114
114
  affectedPaths: string[];
115
115
  actions?: DryRunAction[];
116
116
  }>;
@@ -6,8 +6,10 @@ import { FurnaceError } from '../errors/furnace.js';
6
6
  import { toError } from '../utils/errors.js';
7
7
  import { copyFile, ensureDir, pathExists, readText, removeFile } from '../utils/fs.js';
8
8
  import { verbose } from '../utils/logger.js';
9
+ import { normalizePathSlashes } from '../utils/paths.js';
9
10
  import { buildCustomDryRunActions } from './furnace-apply-dry-run.js';
10
11
  import { applyCustomFtlFile, applySharedFtlPrune, removeCustomFtlJarMnEntry, } from './furnace-apply-ftl.js';
12
+ import { normalizeForChecksum } from './furnace-checksum-utils.js';
11
13
  import { CUSTOM_ELEMENTS_JS, JAR_MN } from './furnace-constants.js';
12
14
  import { deployFileWithFragments, SHARED_FRAGMENTS_DIR } from './furnace-css-fragments.js';
13
15
  import { addCustomElementRegistration, addJarMnEntries } from './furnace-registration.js';
@@ -17,8 +19,8 @@ import { isGitRepository } from './git.js';
17
19
  import { fileExistsInHead, restoreTrackedPath } from './git-file-ops.js';
18
20
  /**
19
21
  * True for a plain-file directory entry — symlinks and directories are
20
- * never copy candidates. Exported for the patch-owned overwrite probe
21
- *, which walks the same override copy-candidate set as apply.
22
+ * never copy candidates. Exported for the patch-owned overwrite probe,
23
+ * which walks the same override copy-candidate set as apply.
22
24
  */
23
25
  export function isRegularFile(entry) {
24
26
  if (!entry.isFile())
@@ -69,7 +71,12 @@ export function getOverrideEngineTargetPath(engineDir, config, fileName, ftlDir)
69
71
  * caller should treat that as a successful no-op rather than an error.
70
72
  */
71
73
  export async function restoreOverrideFileToBaseline(engineDir, enginePath, journal) {
72
- const relPath = relative(engineDir, enginePath);
74
+ // Engine-relative paths are IDENTIFIERS here, not filesystem arguments:
75
+ // they are handed to git, recorded in furnace state, and compared against
76
+ // the POSIX paths furnace.json and jar.mn already carry. `relative()`
77
+ // returns backslashes on Windows, so without this the same file has two
78
+ // spellings and every cross-check misses.
79
+ const relPath = normalizePathSlashes(relative(engineDir, enginePath));
73
80
  // Snapshot before mutation so a later rollback can undo both restoration
74
81
  // (writes whatever content we removed back) and deletion (recreates the
75
82
  // file). Snapshotting a missing path records `{ existed: false }`, which
@@ -98,8 +105,7 @@ export async function computeComponentChecksums(componentDir) {
98
105
  if (!isChecksummedComponentFile(entry.name))
99
106
  continue;
100
107
  const content = await readText(join(componentDir, entry.name));
101
- const normalized = content.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
102
- const hash = createHash('sha256').update(normalized).digest('hex');
108
+ const hash = createHash('sha256').update(normalizeForChecksum(content)).digest('hex');
103
109
  checksums[entry.name] = hash;
104
110
  }
105
111
  return checksums;
@@ -129,7 +135,7 @@ export async function undeployCustomFiles(engineDir, config, deletedFiles, ftlDi
129
135
  }
130
136
  if (await pathExists(enginePath)) {
131
137
  await removeFile(enginePath);
132
- removed.push(relative(engineDir, enginePath));
138
+ removed.push(normalizePathSlashes(relative(engineDir, enginePath)));
133
139
  }
134
140
  // When an `.ftl` is deleted from the workspace the corresponding locale
135
141
  // jar.mn entry must also be dropped — otherwise the chrome URI points at
@@ -173,7 +179,7 @@ export async function undeployOverrideFiles(engineDir, config, deletedFiles, ftl
173
179
  for (const fileName of deletedFiles) {
174
180
  const enginePath = getOverrideEngineTargetPath(engineDir, config, fileName, ftlDir);
175
181
  const action = await restoreOverrideFileToBaseline(engineDir, enginePath, rollbackJournal);
176
- const relPath = relative(engineDir, enginePath);
182
+ const relPath = normalizePathSlashes(relative(engineDir, enginePath));
177
183
  if (action === 'restored')
178
184
  restored.push(relPath);
179
185
  else if (action === 'removed')
@@ -200,9 +206,6 @@ function componentChecksumsChanged(current, previousChecksums) {
200
206
  }
201
207
  return false;
202
208
  }
203
- function normalizeForChecksum(content) {
204
- return content.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
205
- }
206
209
  /**
207
210
  * Detects whether an override component's deployed files are missing from the
208
211
  * engine or differ from the source. Used as a guard before skipping apply on a
@@ -215,7 +218,8 @@ function normalizeForChecksum(content) {
215
218
  * the comparison when the engine hash still matches, which is the common case
216
219
  * for projects with many components.
217
220
  */
218
- export async function hasOverrideEngineDrift(engineDir, componentDir, config, ftlDir, cachedEngineChecksums) {
221
+ export async function hasOverrideEngineDrift(ctx, config, cachedEngineChecksums) {
222
+ const { engineDir, componentDir, ftlDir } = ctx;
219
223
  const entries = await readdir(componentDir, { withFileTypes: true, encoding: 'utf8' });
220
224
  for (const entry of entries) {
221
225
  if (!isRegularFile(entry))
@@ -251,7 +255,8 @@ export async function hasOverrideEngineDrift(engineDir, componentDir, config, ft
251
255
  * Delegates to `checkRegistrationConsistency` so the oracle stays aligned with
252
256
  * the validate command.
253
257
  */
254
- export async function hasCustomEngineDrift(root, name, componentDir, config, ftlDir) {
258
+ export async function hasCustomEngineDrift(ctx, config) {
259
+ const { root, name, componentDir, ftlDir } = ctx;
255
260
  const status = await checkRegistrationConsistency(root, name, config, ftlDir);
256
261
  if (!status.targetExists || !status.filesInSync) {
257
262
  return true;
@@ -289,7 +294,10 @@ export async function hasCustomEngineDrift(root, name, componentDir, config, ftl
289
294
  return false;
290
295
  }
291
296
  /** Applies a custom component into the engine tree and captures registration step errors. */
292
- export async function applyCustomComponent(engineDir, name, componentDir, config, ftlDir, dryRun = false, rollbackJournal, applyOptions = {}) {
297
+ export async function applyCustomComponent(ctx, config, dryRun = false, rollbackJournal, applyOptions = {}) {
298
+ // `ftlDir` stays on the context (the FTL and dry-run callees below read
299
+ // it) but is not needed by name here.
300
+ const { engineDir, name, componentDir } = ctx;
293
301
  if (!/^[a-z][a-z0-9-]*$/.test(name)) {
294
302
  throw new FurnaceError(`Invalid component name "${name}": must match /^[a-z][a-z0-9-]*$/`);
295
303
  }
@@ -300,7 +308,7 @@ export async function applyCustomComponent(engineDir, name, componentDir, config
300
308
  verbose(`Skipped ${customSymlinks.length} symlink(s) in "${name}": ${customSymlinks.map((e) => e.name).join(', ')}`);
301
309
  }
302
310
  if (dryRun) {
303
- const { actions, stepErrors } = await buildCustomDryRunActions(name, componentDir, engineDir, config, targetDir, entries, ftlDir);
311
+ const { actions, stepErrors } = await buildCustomDryRunActions(ctx, config, targetDir, entries);
304
312
  return { affectedPaths: [], stepErrors, actions };
305
313
  }
306
314
  if (rollbackJournal && !(await pathExists(targetDir))) {
@@ -323,27 +331,27 @@ export async function applyCustomComponent(engineDir, name, componentDir, config
323
331
  }
324
332
  // Copy phase (parallel — independent file writes to different paths).
325
333
  // CSS files carrying @fireforge-include directives are written as their
326
- // fragment-expanded form (field report D2); the workspace source keeps
327
- // only the directive, so shared CSS stays single-sourced.
334
+ // fragment-expanded form; the workspace source keeps only the directive,
335
+ // so shared CSS stays single-sourced.
328
336
  const sharedDir = join(componentDir, '..', '..', SHARED_FRAGMENTS_DIR);
329
337
  await Promise.all(filesToCopy.map(async (entry) => {
330
338
  const src = join(componentDir, entry.name);
331
339
  const dest = join(targetDir, entry.name);
332
340
  await deployFileWithFragments(src, dest, sharedDir);
333
- affectedPaths.push(relative(engineDir, dest));
341
+ affectedPaths.push(normalizePathSlashes(relative(engineDir, dest)));
334
342
  copiedFileNames.push(entry.name);
335
343
  }));
336
344
  // See buildCustomDryRunActions for the rationale: when `sharedFtl` is set
337
345
  // the shared bundle is owned elsewhere and FireForge must not copy or
338
346
  // register a per-component `.ftl` on its behalf.
339
347
  if (config.localized && !config.sharedFtl) {
340
- await applyCustomFtlFile(engineDir, name, componentDir, ftlDir, affectedPaths, stepErrors, rollbackJournal);
348
+ await applyCustomFtlFile(ctx, affectedPaths, stepErrors, rollbackJournal);
341
349
  }
342
350
  else if (config.localized && config.sharedFtl) {
343
351
  // Drop any dangling per-widget locale jar.mn entry that would point at a
344
352
  // non-existent `<chromeSubPath>/<name>.ftl` and fail `mach build`. The
345
353
  // shared bundle (a different chrome path/base name) is never touched.
346
- await applySharedFtlPrune(engineDir, name, ftlDir, config, affectedPaths, stepErrors, rollbackJournal);
354
+ await applySharedFtlPrune(ctx, config, affectedPaths, stepErrors, rollbackJournal);
347
355
  }
348
356
  if (config.register) {
349
357
  try {
@@ -383,7 +391,8 @@ export async function applyCustomComponent(engineDir, name, componentDir, config
383
391
  return { affectedPaths, stepErrors };
384
392
  }
385
393
  /** Applies an override component by copying its matching files onto the engine tree. */
386
- export async function applyOverrideComponent(engineDir, name, componentDir, config, ftlDir, dryRun = false, rollbackJournal) {
394
+ export async function applyOverrideComponent(ctx, config, dryRun = false, rollbackJournal) {
395
+ const { engineDir, name, componentDir, ftlDir } = ctx;
387
396
  const targetDir = join(engineDir, config.basePath);
388
397
  if (!(await pathExists(targetDir))) {
389
398
  throw new FurnaceError(`Override target path not found in engine: ${config.basePath}`, name);
@@ -422,7 +431,7 @@ export async function applyOverrideComponent(engineDir, name, componentDir, conf
422
431
  const src = join(componentDir, entry.name);
423
432
  const dest = getOverrideEngineTargetPath(engineDir, config, entry.name, ftlDir);
424
433
  await copyFile(src, dest);
425
- affectedPaths.push(relative(engineDir, dest));
434
+ affectedPaths.push(normalizePathSlashes(relative(engineDir, dest)));
426
435
  }));
427
436
  if (affectedPaths.length === 0) {
428
437
  throw new FurnaceError(`No matching files found in override directory for "${name}"`, name);
@@ -2,19 +2,18 @@
2
2
  * Patch-owned overwrite warnings for `furnace apply`.
3
3
  *
4
4
  * For Furnace-managed components, apply OVERWRITES the deployed engine
5
- * copies with the `components/` sources. A fix made directly in `engine/`
6
- * and exported into a patch — but never back-ported to the component
7
- * source — is silently undone by the next apply, and the only prior
8
- * signal was a drift line that read like "someone's uncommitted work".
9
- * This module detects that exact case BEFORE the copy: the deployed
10
- * bytes differ from the component source AND the file is patch-owned,
11
- * and produces a loud per-file warning naming the file, the owning
5
+ * copies with the `components/` sources. A fix made directly in `engine/` and
6
+ * exported into a patch — but never back-ported to the component source — is
7
+ * silently undone by the next apply, and a plain drift line reads like
8
+ * "someone's uncommitted work". This module detects that exact case BEFORE
9
+ * the copy (deployed bytes differ from the component source AND the file is
10
+ * patch-owned) and produces a per-file warning naming the file, the owning
12
11
  * patch, and the consequence.
13
12
  *
14
13
  * The per-file byte comparison already exists —
15
14
  * `checkRegistrationConsistency` for custom components (fragment- and
16
- * ftl-aware) and the copy-candidate walk for overrides — this module
17
- * only surfaces what was previously computed and thrown away.
15
+ * ftl-aware) and the copy-candidate walk for overrides — so this module only
16
+ * surfaces what was previously computed and thrown away.
18
17
  */
19
18
  import type { CustomComponentConfig, OverrideComponentConfig } from '../types/furnace.js';
20
19
  /** One deployed, patch-owned file about to be overwritten with different bytes. */
@@ -3,19 +3,18 @@
3
3
  * Patch-owned overwrite warnings for `furnace apply`.
4
4
  *
5
5
  * For Furnace-managed components, apply OVERWRITES the deployed engine
6
- * copies with the `components/` sources. A fix made directly in `engine/`
7
- * and exported into a patch — but never back-ported to the component
8
- * source — is silently undone by the next apply, and the only prior
9
- * signal was a drift line that read like "someone's uncommitted work".
10
- * This module detects that exact case BEFORE the copy: the deployed
11
- * bytes differ from the component source AND the file is patch-owned,
12
- * and produces a loud per-file warning naming the file, the owning
6
+ * copies with the `components/` sources. A fix made directly in `engine/` and
7
+ * exported into a patch — but never back-ported to the component source — is
8
+ * silently undone by the next apply, and a plain drift line reads like
9
+ * "someone's uncommitted work". This module detects that exact case BEFORE
10
+ * the copy (deployed bytes differ from the component source AND the file is
11
+ * patch-owned) and produces a per-file warning naming the file, the owning
13
12
  * patch, and the consequence.
14
13
  *
15
14
  * The per-file byte comparison already exists —
16
15
  * `checkRegistrationConsistency` for custom components (fragment- and
17
- * ftl-aware) and the copy-candidate walk for overrides — this module
18
- * only surfaces what was previously computed and thrown away.
16
+ * ftl-aware) and the copy-candidate walk for overrides — so this module only
17
+ * surfaces what was previously computed and thrown away.
19
18
  */
20
19
  import { readdir } from 'node:fs/promises';
21
20
  import { join, relative } from 'node:path';
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Dry-run action builders for files deleted from a component workspace
3
- * since the last apply. Split out of `furnace-apply.ts` (at the per-file
4
- * line budget after the overwrite-warning wiring); the real
5
- * undeploy paths stay in `furnace-apply-helpers.ts`.
2
+ * Dry-run action builders for files deleted from a component workspace since
3
+ * the last apply. Split out of `furnace-apply.ts` to stay under the per-file
4
+ * line budget; the real undeploy paths stay in `furnace-apply-helpers.ts`.
6
5
  */
7
6
  import type { CustomComponentConfig, DryRunAction, OverrideComponentConfig } from '../types/furnace.js';
8
7
  /** Plans the engine-restore actions for deleted override workspace files. */
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Dry-run action builders for files deleted from a component workspace
4
- * since the last apply. Split out of `furnace-apply.ts` (at the per-file
5
- * line budget after the overwrite-warning wiring); the real
6
- * undeploy paths stay in `furnace-apply-helpers.ts`.
3
+ * Dry-run action builders for files deleted from a component workspace since
4
+ * the last apply. Split out of `furnace-apply.ts` to stay under the per-file
5
+ * line budget; the real undeploy paths stay in `furnace-apply-helpers.ts`.
7
6
  */
8
7
  import { join } from 'node:path';
9
8
  import { getOverrideEngineTargetPath } from './furnace-apply-helpers.js';
@@ -1,14 +1,12 @@
1
1
  import type { ApplyResult, DryRunAction } from '../types/furnace.js';
2
2
  import { type FurnaceOperationContext } from './furnace-operation.js';
3
3
  import { type RollbackJournal } from './furnace-rollback.js';
4
- export { computeComponentChecksums, extractComponentChecksums, hasComponentChanged, hasCustomEngineDrift, hasOverrideEngineDrift, prefixChecksums, } from './furnace-apply-helpers.js';
4
+ export { computeComponentChecksums, hasComponentChanged, prefixChecksums, } from './furnace-apply-helpers.js';
5
5
  /**
6
6
  * Result of {@link applyAllComponents}.
7
7
  *
8
- * Named because the anonymous intersection this replaced forced eight
9
- * `Awaited<ReturnType<typeof applyAllComponents>>` indirections across
10
- * `furnace/deploy.ts`, `furnace/preview.ts`, `furnace-state-persist.ts` and
11
- * `build-prepare.ts` — none of which could be read without opening this file.
8
+ * Named so consumers can refer to the shape directly instead of going
9
+ * through `Awaited<ReturnType<typeof applyAllComponents>>`.
12
10
  *
13
11
  * `actions` is populated only on a dry run; `rollbackJournal` only when
14
12
  * `persistState: false` hands journal ownership back to the caller.
@@ -46,7 +44,6 @@ export declare function applyAllComponents(root: string, dryRun?: boolean, optio
46
44
  }): Promise<ApplyAllComponentsResult>; /**
47
45
  * Shared context threaded through the batch apply loops. Bundles the state
48
46
  * both loops mutate (result/actions/checksums) with the immutable run
49
- * parameters — the previous 12–13 positional parameters let call sites
50
- * drift (the named-apply state-wipe bug) and made every new parameter a
51
- * two-signature change.
47
+ * parameters; the 12–13 positional parameters this replaced let call sites
48
+ * drift and made every new parameter a two-signature change.
52
49
  */
@@ -14,11 +14,12 @@ import { CUSTOM_ELEMENTS_JS, JAR_MN, resolveFtlDir } from './furnace-constants.j
14
14
  import { topologicalSortCustom } from './furnace-graph-utils.js';
15
15
  import { resolveFurnaceMarkerComment } from './furnace-marker.js';
16
16
  import { recordFurnaceRollbackFailure } from './furnace-operation.js';
17
+ import { assertFurnaceEngineDirReady } from './furnace-precondition.js';
17
18
  import { addJarMnEntries, removeCustomElementRegistration, removeJarMnEntries, } from './furnace-registration.js';
18
19
  import { createRollbackJournal, restoreRollbackJournalOrThrow, snapshotFile, } from './furnace-rollback.js';
19
20
  import { blockingStepErrors, hasBlockingStepErrors } from './furnace-step-errors.js';
20
21
  import { runPostApplyConsistencyChecks } from './furnace-validate-registration.js';
21
- export { computeComponentChecksums, extractComponentChecksums, hasComponentChanged, hasCustomEngineDrift, hasOverrideEngineDrift, prefixChecksums, } from './furnace-apply-helpers.js';
22
+ export { computeComponentChecksums, hasComponentChanged, prefixChecksums, } from './furnace-apply-helpers.js';
22
23
  function addMissingComponentError(result, name, directoryPath) {
23
24
  result.errors.push({
24
25
  name,
@@ -50,7 +51,7 @@ async function applyOverrideBatch(ctx) {
50
51
  // reset/download/manual edits can silently erase engine files; the
51
52
  // checksum record alone cannot detect that.
52
53
  const cachedEngine = extractComponentChecksums(state.engineChecksums, 'override', name);
53
- const drifted = await hasOverrideEngineDrift(engineDir, componentDir, overrideConfig, ftlDir, cachedEngine);
54
+ const drifted = await hasOverrideEngineDrift({ engineDir, componentDir, ftlDir }, overrideConfig, cachedEngine);
54
55
  if (!drifted) {
55
56
  result.skipped.push({ name, reason: 'No changes since last apply' });
56
57
  Object.assign(newChecksums, prefixChecksums(previous, 'override', name));
@@ -76,7 +77,7 @@ async function applyOverrideBatch(ctx) {
76
77
  if (!dryRun) {
77
78
  // Runs unconditionally — including when the component source
78
79
  // changed — because the lost-work case is precisely a deployed
79
- // engine edit that the incoming copy is about to replace (J6).
80
+ // engine edit that the incoming copy is about to replace.
80
81
  recordOverwriteWarnings(result, await findPatchOwnedOverwrites({
81
82
  type: 'override',
82
83
  engineDir,
@@ -87,7 +88,7 @@ async function applyOverrideBatch(ctx) {
87
88
  patchClaims: ctx.patchClaims,
88
89
  }));
89
90
  }
90
- const { affectedPaths: filesAffected, actions } = await applyOverrideComponent(engineDir, name, componentDir, overrideConfig, ftlDir, dryRun, rollbackJournal);
91
+ const { affectedPaths: filesAffected, actions } = await applyOverrideComponent({ engineDir, name, componentDir, ftlDir }, overrideConfig, dryRun, rollbackJournal);
91
92
  if (dryRun && actions) {
92
93
  allActions.push(...actions);
93
94
  }
@@ -208,7 +209,7 @@ async function applyCustomBatch(ctx, root, markerComment) {
208
209
  // As with overrides, the checksum record is not sufficient on its
209
210
  // own: a reset/download that cleared the engine must trigger a
210
211
  // re-apply even though the workspace is unchanged.
211
- const drifted = await hasCustomEngineDrift(root, name, componentDir, customConfig, ftlDir);
212
+ const drifted = await hasCustomEngineDrift({ root, name, componentDir, ftlDir }, customConfig);
212
213
  if (!drifted) {
213
214
  result.skipped.push({ name, reason: 'No changes since last apply' });
214
215
  Object.assign(newChecksums, prefixChecksums(previous, 'custom', name));
@@ -244,7 +245,7 @@ async function applyCustomBatch(ctx, root, markerComment) {
244
245
  patchClaims: ctx.patchClaims,
245
246
  }));
246
247
  }
247
- const { affectedPaths: filesAffected, stepErrors, actions, } = await applyCustomComponent(engineDir, name, componentDir, customConfig, ftlDir, dryRun, rollbackJournal, markerComment !== undefined ? { markerComment } : {});
248
+ const { affectedPaths: filesAffected, stepErrors, actions, } = await applyCustomComponent({ engineDir, name, componentDir, ftlDir }, customConfig, dryRun, rollbackJournal, markerComment !== undefined ? { markerComment } : {});
248
249
  if (dryRun && actions) {
249
250
  allActions.push(...actions);
250
251
  }
@@ -304,19 +305,14 @@ export async function applyAllComponents(root, dryRun = false, options) {
304
305
  const { engine: engineDir } = getProjectPaths(root);
305
306
  const furnacePaths = getFurnacePaths(root);
306
307
  const ftlDir = resolveFtlDir(config.ftlBasePath);
307
- // 2026-04-26 eval Finding 6: when `markerComment` is unset in
308
- // fireforge.json, default it to `binaryName.toUpperCase()` so the
309
- // furnace-emitted edits to upstream files (e.g. customElements.js)
310
- // carry a marker that satisfies `lintModificationComments` — that
311
- // rule keys on `${binaryName.toUpperCase()}:` and was firing
312
- // `[missing-modification-comment]` on every furnace-applied
313
- // upstream edit because the implicit default was `undefined`. An
314
- // explicit `markerComment` in fireforge.json still wins.
308
+ // When `markerComment` is unset in fireforge.json, default it to
309
+ // `binaryName.toUpperCase()` so the furnace-emitted edits to upstream
310
+ // files (e.g. customElements.js) carry a marker that satisfies
311
+ // `lintModificationComments` — that rule keys on
312
+ // `${binaryName.toUpperCase()}:`. An explicit `markerComment` still wins.
315
313
  const forgeConfig = await loadConfig(root).catch(() => undefined);
316
314
  const markerComment = resolveFurnaceMarkerComment(forgeConfig);
317
- if (!(await pathExists(engineDir))) {
318
- throw new FurnaceError('Engine directory not found. Run "fireforge download" first.');
319
- }
315
+ await assertFurnaceEngineDirReady(engineDir);
320
316
  const rollbackJournal = dryRun ? undefined : createRollbackJournal();
321
317
  if (rollbackJournal && operationContext) {
322
318
  operationContext.registerJournal(rollbackJournal);
@@ -376,10 +372,10 @@ export async function applyAllComponents(root, dryRun = false, options) {
376
372
  }
377
373
  // Recompute AFTER the consistency checks: they MUTATE entry.stepErrors
378
374
  // when the applied output is inconsistent (e.g. a jar.mn entry that
379
- // silently mis-landed). Reading the pre-check snapshot meant those
380
- // failures skipped rollback and persisted checksums for a component
381
- // known to be inconsistent — while the CLI simultaneously reported
382
- // "failed to apply cleanly".
375
+ // silently mis-landed). Reading the pre-check snapshot lets those failures
376
+ // skip rollback and persist checksums for a component known to be
377
+ // inconsistent, while the CLI simultaneously reports "failed to apply
378
+ // cleanly".
383
379
  const hasStepErrors = result.applied.some((entry) => hasBlockingStepErrors(entry));
384
380
  // --- Rollback on failure, persist on success (skip for dry-run) ---
385
381
  if (!dryRun) {
@@ -426,7 +422,6 @@ export async function applyAllComponents(root, dryRun = false, options) {
426
422
  } /**
427
423
  * Shared context threaded through the batch apply loops. Bundles the state
428
424
  * both loops mutate (result/actions/checksums) with the immutable run
429
- * parameters — the previous 12–13 positional parameters let call sites
430
- * drift (the named-apply state-wipe bug) and made every new parameter a
431
- * two-signature change.
425
+ * parameters; the 12–13 positional parameters this replaced let call sites
426
+ * drift and made every new parameter a two-signature change.
432
427
  */
@@ -9,3 +9,17 @@ export declare function prefixChecksums(checksums: Record<string, string>, type:
9
9
  * (sorted alphabetically) so test snapshots and CLI output are deterministic.
10
10
  */
11
11
  export declare function diffDeletedFiles(previous: Record<string, string>, current: Record<string, string>): string[];
12
+ /**
13
+ * Canonical content normalization for every FireForge component checksum.
14
+ *
15
+ * Strips a leading BOM and folds CRLF to LF, so a file that differs from its
16
+ * deployed copy only by line endings or a byte-order mark is not reported as
17
+ * drift. Every comparison that decides "has this component changed?" must
18
+ * use it — otherwise `furnace status` and `furnace validate` can disagree
19
+ * with `apply`'s skip fast-path about the same pair of files on a CRLF
20
+ * checkout.
21
+ *
22
+ * @param content - Raw file content
23
+ * @returns Content with the BOM removed and CRLF folded to LF
24
+ */
25
+ export declare function normalizeForChecksum(content: string): string;
@@ -36,3 +36,19 @@ export function diffDeletedFiles(previous, current) {
36
36
  }
37
37
  return deleted.sort();
38
38
  }
39
+ /**
40
+ * Canonical content normalization for every FireForge component checksum.
41
+ *
42
+ * Strips a leading BOM and folds CRLF to LF, so a file that differs from its
43
+ * deployed copy only by line endings or a byte-order mark is not reported as
44
+ * drift. Every comparison that decides "has this component changed?" must
45
+ * use it — otherwise `furnace status` and `furnace validate` can disagree
46
+ * with `apply`'s skip fast-path about the same pair of files on a CRLF
47
+ * checkout.
48
+ *
49
+ * @param content - Raw file content
50
+ * @returns Content with the BOM removed and CRLF folded to LF
51
+ */
52
+ export function normalizeForChecksum(content) {
53
+ return content.replace(/^\uFEFF/, '').replace(/\r\n/g, '\n');
54
+ }