@hominis/fireforge 0.45.0 → 0.46.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 (662) hide show
  1. package/CHANGELOG.md +409 -446
  2. package/dist/bin/fireforge.d.ts +1 -1
  3. package/dist/bin/fireforge.js +21 -15
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/cli-usage-error.d.ts +46 -0
  6. package/dist/src/cli-usage-error.js +81 -0
  7. package/dist/src/cli.d.ts +7 -2
  8. package/dist/src/cli.js +47 -47
  9. package/dist/src/commands/bootstrap-checks.js +2 -1
  10. package/dist/src/commands/bootstrap.js +3 -4
  11. package/dist/src/commands/build.js +27 -17
  12. package/dist/src/commands/config.js +9 -9
  13. package/dist/src/commands/destructive-decision.d.ts +19 -0
  14. package/dist/src/commands/destructive-decision.js +31 -0
  15. package/dist/src/commands/discard.js +5 -5
  16. package/dist/src/commands/doctor-check-core.d.ts +4 -10
  17. package/dist/src/commands/doctor-check-core.js +0 -8
  18. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  19. package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
  20. package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
  21. package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
  22. package/dist/src/commands/doctor-furnace-jar.js +1 -1
  23. package/dist/src/commands/doctor-furnace.js +22 -22
  24. package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
  25. package/dist/src/commands/doctor-orphaned-harness.js +14 -23
  26. package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
  27. package/dist/src/commands/doctor-patch-manifest.js +7 -6
  28. package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
  29. package/dist/src/commands/doctor-source-pin.d.ts +12 -12
  30. package/dist/src/commands/doctor-source-pin.js +14 -14
  31. package/dist/src/commands/doctor-working-tree.d.ts +3 -3
  32. package/dist/src/commands/doctor-working-tree.js +3 -3
  33. package/dist/src/commands/doctor.d.ts +3 -1
  34. package/dist/src/commands/doctor.js +15 -16
  35. package/dist/src/commands/download.js +50 -37
  36. package/dist/src/commands/export-all.js +29 -12
  37. package/dist/src/commands/export-flow.d.ts +5 -5
  38. package/dist/src/commands/export-flow.js +29 -59
  39. package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
  40. package/dist/src/commands/export-placement-conflicts.js +12 -12
  41. package/dist/src/commands/export-placement-gate.d.ts +2 -2
  42. package/dist/src/commands/export-placement-gate.js +7 -13
  43. package/dist/src/commands/export-placement-policy.d.ts +1 -1
  44. package/dist/src/commands/export-placement-policy.js +4 -6
  45. package/dist/src/commands/export-shared.d.ts +51 -32
  46. package/dist/src/commands/export-shared.js +17 -32
  47. package/dist/src/commands/export.js +14 -5
  48. package/dist/src/commands/furnace/apply.js +16 -16
  49. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  50. package/dist/src/commands/furnace/authoring-config.js +19 -0
  51. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
  52. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  53. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
  54. package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
  55. package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
  56. package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
  57. package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
  58. package/dist/src/commands/furnace/chrome-doc.js +18 -18
  59. package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
  60. package/dist/src/commands/furnace/create-browser-test.js +7 -12
  61. package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
  62. package/dist/src/commands/furnace/create-dry-run.js +6 -9
  63. package/dist/src/commands/furnace/create-features.d.ts +2 -2
  64. package/dist/src/commands/furnace/create-features.js +2 -2
  65. package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
  66. package/dist/src/commands/furnace/create-mochikit.js +7 -7
  67. package/dist/src/commands/furnace/create-templates.d.ts +31 -15
  68. package/dist/src/commands/furnace/create-templates.js +20 -19
  69. package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
  70. package/dist/src/commands/furnace/create-xpcshell.js +8 -8
  71. package/dist/src/commands/furnace/create.d.ts +1 -1
  72. package/dist/src/commands/furnace/create.js +35 -29
  73. package/dist/src/commands/furnace/deploy.js +15 -6
  74. package/dist/src/commands/furnace/diff.js +7 -7
  75. package/dist/src/commands/furnace/index.js +1 -1
  76. package/dist/src/commands/furnace/init.js +17 -16
  77. package/dist/src/commands/furnace/list.js +2 -2
  78. package/dist/src/commands/furnace/override.d.ts +1 -1
  79. package/dist/src/commands/furnace/override.js +43 -34
  80. package/dist/src/commands/furnace/preview.js +17 -17
  81. package/dist/src/commands/furnace/refresh.js +15 -7
  82. package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
  83. package/dist/src/commands/furnace/remove-mutations.js +19 -19
  84. package/dist/src/commands/furnace/remove-state.d.ts +1 -1
  85. package/dist/src/commands/furnace/remove-state.js +1 -1
  86. package/dist/src/commands/furnace/remove.js +4 -8
  87. package/dist/src/commands/furnace/rename-browser-test.js +10 -15
  88. package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
  89. package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
  90. package/dist/src/commands/furnace/rename.js +36 -36
  91. package/dist/src/commands/furnace/scan.js +3 -3
  92. package/dist/src/commands/furnace/status.js +19 -16
  93. package/dist/src/commands/furnace/sync.js +6 -6
  94. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  95. package/dist/src/commands/furnace/test-file-name.js +39 -0
  96. package/dist/src/commands/furnace/validate.js +11 -12
  97. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  98. package/dist/src/commands/furnace/validation-output.js +3 -8
  99. package/dist/src/commands/import.js +22 -29
  100. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  101. package/dist/src/commands/lint-per-patch.js +27 -12
  102. package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
  103. package/dist/src/commands/lint-per-run-checkjs.js +14 -15
  104. package/dist/src/commands/lint-report.d.ts +3 -3
  105. package/dist/src/commands/lint-report.js +4 -4
  106. package/dist/src/commands/lint.d.ts +5 -4
  107. package/dist/src/commands/lint.js +36 -36
  108. package/dist/src/commands/manifest.d.ts +4 -4
  109. package/dist/src/commands/manifest.js +1 -1
  110. package/dist/src/commands/package.js +4 -6
  111. package/dist/src/commands/patch/compact.d.ts +2 -2
  112. package/dist/src/commands/patch/compact.js +19 -20
  113. package/dist/src/commands/patch/delete.d.ts +1 -1
  114. package/dist/src/commands/patch/delete.js +23 -33
  115. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  116. package/dist/src/commands/patch/entry-projection.js +24 -0
  117. package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
  118. package/dist/src/commands/patch/lint-ignore.js +33 -44
  119. package/dist/src/commands/patch/move-files-create.d.ts +2 -2
  120. package/dist/src/commands/patch/move-files-create.js +29 -15
  121. package/dist/src/commands/patch/move-files-into.d.ts +2 -2
  122. package/dist/src/commands/patch/move-files-into.js +41 -37
  123. package/dist/src/commands/patch/move-files.js +5 -14
  124. package/dist/src/commands/patch/patch-context.d.ts +1 -1
  125. package/dist/src/commands/patch/rename.d.ts +4 -4
  126. package/dist/src/commands/patch/rename.js +35 -49
  127. package/dist/src/commands/patch/reorder.js +35 -48
  128. package/dist/src/commands/patch/split-plan.d.ts +7 -8
  129. package/dist/src/commands/patch/split-plan.js +10 -13
  130. package/dist/src/commands/patch/split.d.ts +2 -2
  131. package/dist/src/commands/patch/split.js +50 -48
  132. package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
  133. package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
  134. package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
  135. package/dist/src/commands/patch/staged-dependency.js +22 -28
  136. package/dist/src/commands/patch/tier.d.ts +2 -2
  137. package/dist/src/commands/patch/tier.js +20 -30
  138. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  139. package/dist/src/commands/patch-rename-map.js +36 -0
  140. package/dist/src/commands/pending-resolution.d.ts +15 -0
  141. package/dist/src/commands/pending-resolution.js +25 -0
  142. package/dist/src/commands/re-export-adjacent.d.ts +25 -3
  143. package/dist/src/commands/re-export-adjacent.js +40 -24
  144. package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
  145. package/dist/src/commands/re-export-bulk-scan.js +23 -27
  146. package/dist/src/commands/re-export-drift.d.ts +10 -10
  147. package/dist/src/commands/re-export-drift.js +33 -33
  148. package/dist/src/commands/re-export-files.d.ts +2 -3
  149. package/dist/src/commands/re-export-files.js +52 -44
  150. package/dist/src/commands/re-export-lint.d.ts +29 -30
  151. package/dist/src/commands/re-export-lint.js +36 -29
  152. package/dist/src/commands/re-export-options.d.ts +1 -1
  153. package/dist/src/commands/re-export-options.js +1 -1
  154. package/dist/src/commands/re-export-register.d.ts +1 -1
  155. package/dist/src/commands/re-export-register.js +1 -1
  156. package/dist/src/commands/re-export-scan.d.ts +1 -1
  157. package/dist/src/commands/re-export-scan.js +12 -9
  158. package/dist/src/commands/re-export-single.d.ts +23 -4
  159. package/dist/src/commands/re-export-single.js +39 -31
  160. package/dist/src/commands/re-export.js +35 -17
  161. package/dist/src/commands/rebase/abort.js +9 -14
  162. package/dist/src/commands/rebase/continue.js +20 -19
  163. package/dist/src/commands/rebase/index.d.ts +1 -1
  164. package/dist/src/commands/rebase/index.js +5 -5
  165. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  166. package/dist/src/commands/rebase/patch-loop.js +20 -24
  167. package/dist/src/commands/register.js +5 -5
  168. package/dist/src/commands/reset.js +1 -1
  169. package/dist/src/commands/resolve.d.ts +2 -2
  170. package/dist/src/commands/resolve.js +21 -13
  171. package/dist/src/commands/run.d.ts +0 -13
  172. package/dist/src/commands/run.js +38 -51
  173. package/dist/src/commands/setup-support.d.ts +16 -4
  174. package/dist/src/commands/setup-support.js +20 -20
  175. package/dist/src/commands/setup.js +4 -10
  176. package/dist/src/commands/source.js +9 -2
  177. package/dist/src/commands/status-check.d.ts +3 -3
  178. package/dist/src/commands/status-check.js +6 -6
  179. package/dist/src/commands/status-json.d.ts +14 -13
  180. package/dist/src/commands/status-json.js +9 -8
  181. package/dist/src/commands/status-output.d.ts +3 -3
  182. package/dist/src/commands/status-output.js +5 -5
  183. package/dist/src/commands/status-ownership.d.ts +3 -3
  184. package/dist/src/commands/status-ownership.js +3 -3
  185. package/dist/src/commands/status.js +25 -26
  186. package/dist/src/commands/test-build-phase.d.ts +3 -3
  187. package/dist/src/commands/test-build-phase.js +48 -24
  188. package/dist/src/commands/test-diagnose.d.ts +1 -1
  189. package/dist/src/commands/test-diagnose.js +20 -20
  190. package/dist/src/commands/test-modes.d.ts +4 -4
  191. package/dist/src/commands/test-modes.js +4 -5
  192. package/dist/src/commands/test-register.js +5 -3
  193. package/dist/src/commands/test-run.d.ts +11 -11
  194. package/dist/src/commands/test-run.js +40 -33
  195. package/dist/src/commands/test-stale-gate.d.ts +12 -12
  196. package/dist/src/commands/test-stale-gate.js +17 -17
  197. package/dist/src/commands/test-verdict.d.ts +19 -5
  198. package/dist/src/commands/test-verdict.js +26 -11
  199. package/dist/src/commands/test.d.ts +3 -3
  200. package/dist/src/commands/test.js +73 -36
  201. package/dist/src/commands/token-coverage.js +3 -3
  202. package/dist/src/commands/token-list.d.ts +26 -0
  203. package/dist/src/commands/token-list.js +153 -0
  204. package/dist/src/commands/token.js +26 -10
  205. package/dist/src/commands/tree.js +26 -21
  206. package/dist/src/commands/typecheck.d.ts +6 -6
  207. package/dist/src/commands/typecheck.js +16 -16
  208. package/dist/src/commands/verify.d.ts +3 -3
  209. package/dist/src/commands/verify.js +10 -10
  210. package/dist/src/commands/watch.js +11 -11
  211. package/dist/src/commands/wire.js +17 -16
  212. package/dist/src/core/ast-utils.d.ts +7 -7
  213. package/dist/src/core/ast-utils.js +8 -8
  214. package/dist/src/core/branding.d.ts +5 -12
  215. package/dist/src/core/branding.js +6 -5
  216. package/dist/src/core/browser-wire.d.ts +1 -1
  217. package/dist/src/core/browser-wire.js +10 -7
  218. package/dist/src/core/build-audit-platform.d.ts +32 -3
  219. package/dist/src/core/build-audit-platform.js +153 -13
  220. package/dist/src/core/build-audit-registration.d.ts +5 -5
  221. package/dist/src/core/build-audit-registration.js +10 -9
  222. package/dist/src/core/build-audit-resolve.d.ts +5 -5
  223. package/dist/src/core/build-audit-resolve.js +6 -6
  224. package/dist/src/core/build-audit-skip.d.ts +57 -0
  225. package/dist/src/core/build-audit-skip.js +112 -0
  226. package/dist/src/core/build-audit-transforms.d.ts +2 -2
  227. package/dist/src/core/build-audit-transforms.js +3 -3
  228. package/dist/src/core/build-audit.d.ts +21 -8
  229. package/dist/src/core/build-audit.js +142 -40
  230. package/dist/src/core/build-baseline-types.d.ts +19 -18
  231. package/dist/src/core/build-baseline-types.js +1 -1
  232. package/dist/src/core/build-baseline.d.ts +48 -31
  233. package/dist/src/core/build-baseline.js +20 -43
  234. package/dist/src/core/build-jar-escalation.d.ts +8 -8
  235. package/dist/src/core/build-jar-escalation.js +18 -17
  236. package/dist/src/core/build-overwrite-guard.d.ts +4 -4
  237. package/dist/src/core/build-overwrite-guard.js +14 -14
  238. package/dist/src/core/build-prepare.d.ts +4 -12
  239. package/dist/src/core/build-prepare.js +22 -26
  240. package/dist/src/core/config-mutate.js +4 -4
  241. package/dist/src/core/config-paths.d.ts +2 -6
  242. package/dist/src/core/config-paths.js +4 -2
  243. package/dist/src/core/config-state.d.ts +0 -6
  244. package/dist/src/core/config-state.js +3 -21
  245. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  246. package/dist/src/core/config-validate-build-audit.js +80 -0
  247. package/dist/src/core/config-validate-file-size.d.ts +1 -1
  248. package/dist/src/core/config-validate-file-size.js +3 -3
  249. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  250. package/dist/src/core/config-validate-patch-policy.js +3 -3
  251. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  252. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  253. package/dist/src/core/config-validate.js +22 -12
  254. package/dist/src/core/config.d.ts +12 -12
  255. package/dist/src/core/config.js +21 -25
  256. package/dist/src/core/coverage-extend.d.ts +16 -16
  257. package/dist/src/core/coverage-extend.js +20 -20
  258. package/dist/src/core/destructive.d.ts +14 -14
  259. package/dist/src/core/destructive.js +9 -9
  260. package/dist/src/core/diff-hunks.d.ts +2 -2
  261. package/dist/src/core/diff-hunks.js +7 -7
  262. package/dist/src/core/discard-baseline.d.ts +10 -10
  263. package/dist/src/core/discard-baseline.js +22 -23
  264. package/dist/src/core/display-state.d.ts +11 -11
  265. package/dist/src/core/display-state.js +12 -12
  266. package/dist/src/core/engine-changes.d.ts +2 -2
  267. package/dist/src/core/engine-changes.js +2 -2
  268. package/dist/src/core/engine-precondition.d.ts +5 -13
  269. package/dist/src/core/engine-precondition.js +5 -10
  270. package/dist/src/core/engine-session-lock.d.ts +18 -18
  271. package/dist/src/core/engine-session-lock.js +50 -54
  272. package/dist/src/core/export-moved-code-shape.d.ts +7 -7
  273. package/dist/src/core/export-moved-code-shape.js +10 -10
  274. package/dist/src/core/file-lock-owner.d.ts +103 -0
  275. package/dist/src/core/file-lock-owner.js +259 -0
  276. package/dist/src/core/file-lock.d.ts +14 -19
  277. package/dist/src/core/file-lock.js +90 -128
  278. package/dist/src/core/firefox-cache.d.ts +13 -1
  279. package/dist/src/core/firefox-cache.js +61 -36
  280. package/dist/src/core/firefox-download.d.ts +15 -0
  281. package/dist/src/core/firefox-download.js +38 -22
  282. package/dist/src/core/firefox-extract.d.ts +8 -7
  283. package/dist/src/core/firefox-extract.js +45 -27
  284. package/dist/src/core/firefox.d.ts +34 -36
  285. package/dist/src/core/firefox.js +13 -44
  286. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  287. package/dist/src/core/furnace-apply-dry-run.js +2 -8
  288. package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
  289. package/dist/src/core/furnace-apply-ftl.js +8 -8
  290. package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
  291. package/dist/src/core/furnace-apply-helpers.js +28 -39
  292. package/dist/src/core/furnace-apply-output.js +1 -1
  293. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
  294. package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
  295. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
  296. package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
  297. package/dist/src/core/furnace-apply.d.ts +4 -4
  298. package/dist/src/core/furnace-apply.js +50 -29
  299. package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
  300. package/dist/src/core/furnace-checksum-utils.js +5 -5
  301. package/dist/src/core/furnace-config-custom.d.ts +1 -1
  302. package/dist/src/core/furnace-config-custom.js +2 -2
  303. package/dist/src/core/furnace-config-order.js +1 -1
  304. package/dist/src/core/furnace-config-tokens.d.ts +3 -3
  305. package/dist/src/core/furnace-config-tokens.js +3 -3
  306. package/dist/src/core/furnace-config-validate.js +2 -2
  307. package/dist/src/core/furnace-config.d.ts +5 -5
  308. package/dist/src/core/furnace-config.js +40 -53
  309. package/dist/src/core/furnace-constants.d.ts +6 -6
  310. package/dist/src/core/furnace-constants.js +9 -8
  311. package/dist/src/core/furnace-css-fragments.d.ts +6 -6
  312. package/dist/src/core/furnace-css-fragments.js +11 -11
  313. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  314. package/dist/src/core/furnace-dir-entry.js +21 -0
  315. package/dist/src/core/furnace-jsconfig.d.ts +7 -7
  316. package/dist/src/core/furnace-jsconfig.js +22 -20
  317. package/dist/src/core/furnace-operation.d.ts +22 -19
  318. package/dist/src/core/furnace-operation.js +38 -34
  319. package/dist/src/core/furnace-precondition.d.ts +10 -10
  320. package/dist/src/core/furnace-precondition.js +8 -8
  321. package/dist/src/core/furnace-refresh.d.ts +18 -6
  322. package/dist/src/core/furnace-refresh.js +5 -8
  323. package/dist/src/core/furnace-registration-ast.d.ts +2 -3
  324. package/dist/src/core/furnace-registration-ast.js +9 -12
  325. package/dist/src/core/furnace-registration-remove.d.ts +4 -4
  326. package/dist/src/core/furnace-registration-remove.js +6 -6
  327. package/dist/src/core/furnace-registration-validate.d.ts +2 -2
  328. package/dist/src/core/furnace-registration-validate.js +2 -2
  329. package/dist/src/core/furnace-registration.d.ts +7 -6
  330. package/dist/src/core/furnace-registration.js +29 -36
  331. package/dist/src/core/furnace-rollback.d.ts +1 -1
  332. package/dist/src/core/furnace-rollback.js +5 -5
  333. package/dist/src/core/furnace-scanner.js +3 -6
  334. package/dist/src/core/furnace-stale-export.d.ts +17 -16
  335. package/dist/src/core/furnace-stale-export.js +16 -15
  336. package/dist/src/core/furnace-staleness.d.ts +2 -2
  337. package/dist/src/core/furnace-staleness.js +2 -2
  338. package/dist/src/core/furnace-state-persist.d.ts +12 -12
  339. package/dist/src/core/furnace-state-persist.js +10 -10
  340. package/dist/src/core/furnace-step-errors.d.ts +6 -6
  341. package/dist/src/core/furnace-step-errors.js +6 -6
  342. package/dist/src/core/furnace-validate-accessibility.js +14 -14
  343. package/dist/src/core/furnace-validate-compatibility.js +9 -9
  344. package/dist/src/core/furnace-validate-registration.d.ts +2 -2
  345. package/dist/src/core/furnace-validate-registration.js +18 -20
  346. package/dist/src/core/furnace-validate-structure.d.ts +1 -1
  347. package/dist/src/core/furnace-validate-structure.js +4 -4
  348. package/dist/src/core/furnace-validate.js +9 -9
  349. package/dist/src/core/furnace-version-drift.d.ts +5 -5
  350. package/dist/src/core/furnace-version-drift.js +5 -5
  351. package/dist/src/core/git-base.d.ts +6 -4
  352. package/dist/src/core/git-base.js +29 -7
  353. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  354. package/dist/src/core/git-diff-new-file.js +119 -0
  355. package/dist/src/core/git-diff.d.ts +13 -13
  356. package/dist/src/core/git-diff.js +121 -189
  357. package/dist/src/core/git-file-ops.d.ts +6 -13
  358. package/dist/src/core/git-file-ops.js +11 -35
  359. package/dist/src/core/git-readonly-index.d.ts +12 -14
  360. package/dist/src/core/git-readonly-index.js +12 -16
  361. package/dist/src/core/git-status.d.ts +9 -2
  362. package/dist/src/core/git-status.js +23 -11
  363. package/dist/src/core/git.d.ts +3 -9
  364. package/dist/src/core/git.js +28 -57
  365. package/dist/src/core/harness-orphans.d.ts +17 -17
  366. package/dist/src/core/harness-orphans.js +28 -27
  367. package/dist/src/core/history-log.d.ts +19 -0
  368. package/dist/src/core/history-log.js +29 -0
  369. package/dist/src/core/license-headers.d.ts +19 -18
  370. package/dist/src/core/license-headers.js +29 -28
  371. package/dist/src/core/mach-build-artifacts.d.ts +21 -21
  372. package/dist/src/core/mach-build-artifacts.js +23 -23
  373. package/dist/src/core/mach-error-hints.d.ts +5 -10
  374. package/dist/src/core/mach-error-hints.js +14 -14
  375. package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
  376. package/dist/src/core/mach-known-noise-filter.js +57 -56
  377. package/dist/src/core/mach-mozconfig.d.ts +6 -6
  378. package/dist/src/core/mach-mozconfig.js +17 -16
  379. package/dist/src/core/mach-python.d.ts +3 -0
  380. package/dist/src/core/mach-python.js +13 -7
  381. package/dist/src/core/mach-resource-shim.d.ts +24 -12
  382. package/dist/src/core/mach-resource-shim.js +124 -21
  383. package/dist/src/core/mach.d.ts +59 -73
  384. package/dist/src/core/mach.js +47 -115
  385. package/dist/src/core/marionette-port.d.ts +15 -30
  386. package/dist/src/core/marionette-port.js +46 -89
  387. package/dist/src/core/marionette-preflight.d.ts +6 -6
  388. package/dist/src/core/marionette-preflight.js +32 -50
  389. package/dist/src/core/markdown-table.d.ts +9 -9
  390. package/dist/src/core/markdown-table.js +14 -14
  391. package/dist/src/core/mochitest-server-port.d.ts +8 -8
  392. package/dist/src/core/mochitest-server-port.js +17 -17
  393. package/dist/src/core/module-resolution-preflight.d.ts +8 -8
  394. package/dist/src/core/module-resolution-preflight.js +11 -11
  395. package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
  396. package/dist/src/core/moz-manifest-helpers.js +7 -7
  397. package/dist/src/core/moz-manifest-register.d.ts +1 -1
  398. package/dist/src/core/moz-manifest-register.js +2 -2
  399. package/dist/src/core/moz-manifest-rules.js +46 -42
  400. package/dist/src/core/moz-manifest-tokenizers.js +1 -1
  401. package/dist/src/core/ownership-table.d.ts +5 -5
  402. package/dist/src/core/ownership-table.js +7 -7
  403. package/dist/src/core/parser-fallback.d.ts +3 -3
  404. package/dist/src/core/parser-fallback.js +3 -3
  405. package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
  406. package/dist/src/core/patch-apply-fuzz.js +13 -13
  407. package/dist/src/core/patch-apply.d.ts +13 -14
  408. package/dist/src/core/patch-apply.js +36 -42
  409. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  410. package/dist/src/core/patch-export-coverage.js +1 -30
  411. package/dist/src/core/patch-export-update.d.ts +21 -4
  412. package/dist/src/core/patch-export-update.js +7 -6
  413. package/dist/src/core/patch-export.d.ts +20 -30
  414. package/dist/src/core/patch-export.js +55 -77
  415. package/dist/src/core/patch-files.d.ts +0 -4
  416. package/dist/src/core/patch-files.js +0 -11
  417. package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
  418. package/dist/src/core/patch-identifier-suggest.js +4 -4
  419. package/dist/src/core/patch-lint-binary.d.ts +12 -18
  420. package/dist/src/core/patch-lint-cache.d.ts +18 -2
  421. package/dist/src/core/patch-lint-cache.js +16 -19
  422. package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
  423. package/dist/src/core/patch-lint-checkjs.js +78 -64
  424. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
  425. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
  426. package/dist/src/core/patch-lint-creators.d.ts +5 -9
  427. package/dist/src/core/patch-lint-creators.js +3 -3
  428. package/dist/src/core/patch-lint-cross.d.ts +27 -19
  429. package/dist/src/core/patch-lint-cross.js +67 -110
  430. package/dist/src/core/patch-lint-css.d.ts +1 -1
  431. package/dist/src/core/patch-lint-css.js +15 -11
  432. package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
  433. package/dist/src/core/patch-lint-diff-tag.js +5 -5
  434. package/dist/src/core/patch-lint-diff.d.ts +4 -4
  435. package/dist/src/core/patch-lint-diff.js +4 -4
  436. package/dist/src/core/patch-lint-file-size.d.ts +3 -3
  437. package/dist/src/core/patch-lint-file-size.js +6 -6
  438. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  439. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  440. package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
  441. package/dist/src/core/patch-lint-jsdoc.js +46 -46
  442. package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
  443. package/dist/src/core/patch-lint-module-registration.js +1 -1
  444. package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
  445. package/dist/src/core/patch-lint-mozbuild.js +10 -10
  446. package/dist/src/core/patch-lint-observer.d.ts +3 -3
  447. package/dist/src/core/patch-lint-observer.js +7 -7
  448. package/dist/src/core/patch-lint-ownership.d.ts +6 -6
  449. package/dist/src/core/patch-lint-ownership.js +6 -6
  450. package/dist/src/core/patch-lint-prettier.d.ts +6 -6
  451. package/dist/src/core/patch-lint-prettier.js +7 -7
  452. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  453. package/dist/src/core/patch-lint-queue-types.js +12 -0
  454. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  455. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  456. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
  457. package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
  458. package/dist/src/core/patch-lint.d.ts +41 -35
  459. package/dist/src/core/patch-lint.js +52 -49
  460. package/dist/src/core/patch-lock.d.ts +1 -1
  461. package/dist/src/core/patch-lock.js +11 -11
  462. package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
  463. package/dist/src/core/patch-manifest-consistency.js +16 -17
  464. package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
  465. package/dist/src/core/patch-manifest-files-affected.js +3 -3
  466. package/dist/src/core/patch-manifest-io.d.ts +14 -14
  467. package/dist/src/core/patch-manifest-io.js +35 -34
  468. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  469. package/dist/src/core/patch-manifest-query.js +4 -4
  470. package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
  471. package/dist/src/core/patch-manifest-resolve.js +7 -7
  472. package/dist/src/core/patch-manifest-validate.js +3 -3
  473. package/dist/src/core/patch-manifest.d.ts +2 -2
  474. package/dist/src/core/patch-manifest.js +2 -2
  475. package/dist/src/core/patch-parse.d.ts +32 -21
  476. package/dist/src/core/patch-parse.js +40 -15
  477. package/dist/src/core/patch-policy.js +15 -27
  478. package/dist/src/core/patch-registration-refs.d.ts +4 -4
  479. package/dist/src/core/patch-registration-refs.js +7 -7
  480. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  481. package/dist/src/core/patch-source-metadata.js +0 -4
  482. package/dist/src/core/patch-transform.d.ts +8 -16
  483. package/dist/src/core/patch-transform.js +13 -23
  484. package/dist/src/core/process-cpu-time.d.ts +1 -1
  485. package/dist/src/core/process-cpu-time.js +6 -6
  486. package/dist/src/core/rebase-session.d.ts +9 -15
  487. package/dist/src/core/rebase-session.js +13 -25
  488. package/dist/src/core/register-browser-content.js +3 -2
  489. package/dist/src/core/register-browser-test.js +2 -1
  490. package/dist/src/core/register-module.js +2 -1
  491. package/dist/src/core/register-result.d.ts +1 -1
  492. package/dist/src/core/register-result.js +1 -1
  493. package/dist/src/core/register-scaffold.d.ts +2 -2
  494. package/dist/src/core/register-scaffold.js +8 -7
  495. package/dist/src/core/register-shared-css.d.ts +3 -3
  496. package/dist/src/core/register-shared-css.js +6 -5
  497. package/dist/src/core/register-xpcshell-test.d.ts +2 -2
  498. package/dist/src/core/register-xpcshell-test.js +2 -2
  499. package/dist/src/core/run-log-redact.d.ts +38 -0
  500. package/dist/src/core/run-log-redact.js +69 -0
  501. package/dist/src/core/run-log.d.ts +21 -10
  502. package/dist/src/core/run-log.js +76 -27
  503. package/dist/src/core/shared-ftl.d.ts +2 -2
  504. package/dist/src/core/shared-ftl.js +6 -6
  505. package/dist/src/core/signal-critical.d.ts +2 -2
  506. package/dist/src/core/signal-critical.js +4 -6
  507. package/dist/src/core/smoke-patterns.d.ts +5 -6
  508. package/dist/src/core/smoke-patterns.js +15 -20
  509. package/dist/src/core/state-file.d.ts +15 -4
  510. package/dist/src/core/state-file.js +14 -1
  511. package/dist/src/core/status-binary.d.ts +8 -8
  512. package/dist/src/core/status-binary.js +12 -12
  513. package/dist/src/core/status-classify.d.ts +17 -17
  514. package/dist/src/core/status-classify.js +13 -12
  515. package/dist/src/core/test-changed-prefs.d.ts +12 -12
  516. package/dist/src/core/test-changed-prefs.js +40 -25
  517. package/dist/src/core/test-harness-crash.d.ts +39 -39
  518. package/dist/src/core/test-harness-crash.js +69 -69
  519. package/dist/src/core/test-harness-output.d.ts +7 -7
  520. package/dist/src/core/test-harness-output.js +7 -7
  521. package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
  522. package/dist/src/core/test-harness-verdict-notes.js +4 -4
  523. package/dist/src/core/test-path-scope.d.ts +8 -8
  524. package/dist/src/core/test-path-scope.js +11 -11
  525. package/dist/src/core/test-stale-check.d.ts +22 -23
  526. package/dist/src/core/test-stale-check.js +31 -30
  527. package/dist/src/core/test-stale-symlink.d.ts +1 -1
  528. package/dist/src/core/test-stale-symlink.js +1 -1
  529. package/dist/src/core/test-stall-triage.d.ts +9 -9
  530. package/dist/src/core/test-stall-triage.js +22 -22
  531. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  532. package/dist/src/core/test-xpcshell-retry.js +14 -11
  533. package/dist/src/core/token-category.d.ts +35 -2
  534. package/dist/src/core/token-category.js +67 -58
  535. package/dist/src/core/token-coverage.js +4 -5
  536. package/dist/src/core/token-dark-mode.d.ts +9 -9
  537. package/dist/src/core/token-dark-mode.js +13 -25
  538. package/dist/src/core/token-docs.d.ts +1 -1
  539. package/dist/src/core/token-inventory.d.ts +56 -0
  540. package/dist/src/core/token-inventory.js +109 -0
  541. package/dist/src/core/token-manager.d.ts +4 -4
  542. package/dist/src/core/token-manager.js +22 -22
  543. package/dist/src/core/token-scaffold.d.ts +4 -4
  544. package/dist/src/core/token-scaffold.js +4 -4
  545. package/dist/src/core/token-variant.d.ts +14 -14
  546. package/dist/src/core/token-variant.js +52 -53
  547. package/dist/src/core/toolchain-preflight.d.ts +15 -15
  548. package/dist/src/core/toolchain-preflight.js +23 -23
  549. package/dist/src/core/tree-cow.d.ts +3 -5
  550. package/dist/src/core/tree-cow.js +8 -8
  551. package/dist/src/core/tree-guard.d.ts +3 -3
  552. package/dist/src/core/tree-guard.js +23 -23
  553. package/dist/src/core/tree-store.d.ts +15 -15
  554. package/dist/src/core/tree-store.js +39 -38
  555. package/dist/src/core/typecheck-shim.d.ts +16 -15
  556. package/dist/src/core/typecheck-shim.js +26 -25
  557. package/dist/src/core/typecheck.d.ts +12 -12
  558. package/dist/src/core/typecheck.js +33 -33
  559. package/dist/src/core/wire-destroy.d.ts +2 -2
  560. package/dist/src/core/wire-destroy.js +5 -5
  561. package/dist/src/core/wire-dom-fragment.d.ts +3 -3
  562. package/dist/src/core/wire-dom-fragment.js +12 -23
  563. package/dist/src/core/wire-init.d.ts +2 -2
  564. package/dist/src/core/wire-init.js +7 -7
  565. package/dist/src/core/wire-subscript.d.ts +1 -1
  566. package/dist/src/core/wire-subscript.js +3 -3
  567. package/dist/src/core/wire-utils.d.ts +9 -9
  568. package/dist/src/core/wire-utils.js +16 -28
  569. package/dist/src/core/xpcshell-appdir.d.ts +20 -20
  570. package/dist/src/core/xpcshell-appdir.js +28 -30
  571. package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
  572. package/dist/src/core/xpcshell-profile-dir.js +7 -7
  573. package/dist/src/errors/base.d.ts +69 -16
  574. package/dist/src/errors/base.js +95 -26
  575. package/dist/src/errors/build.d.ts +6 -6
  576. package/dist/src/errors/build.js +26 -34
  577. package/dist/src/errors/codes.d.ts +10 -10
  578. package/dist/src/errors/codes.js +10 -10
  579. package/dist/src/errors/config.d.ts +0 -14
  580. package/dist/src/errors/config.js +13 -34
  581. package/dist/src/errors/download.d.ts +13 -0
  582. package/dist/src/errors/download.js +53 -24
  583. package/dist/src/errors/furnace.d.ts +2 -2
  584. package/dist/src/errors/furnace.js +8 -9
  585. package/dist/src/errors/git.d.ts +9 -9
  586. package/dist/src/errors/git.js +21 -31
  587. package/dist/src/errors/patch.d.ts +3 -3
  588. package/dist/src/errors/patch.js +11 -13
  589. package/dist/src/errors/rebase.d.ts +1 -1
  590. package/dist/src/errors/rebase.js +8 -8
  591. package/dist/src/errors/run.d.ts +1 -1
  592. package/dist/src/errors/run.js +1 -1
  593. package/dist/src/index.d.ts +4 -4
  594. package/dist/src/index.js +4 -4
  595. package/dist/src/types/commands/options.d.ts +155 -200
  596. package/dist/src/types/commands/patches.d.ts +19 -19
  597. package/dist/src/types/commands/project.d.ts +3 -3
  598. package/dist/src/types/config.d.ts +52 -19
  599. package/dist/src/types/furnace.d.ts +17 -17
  600. package/dist/src/types/index.d.ts +0 -1
  601. package/dist/src/types/json.d.ts +3 -3
  602. package/dist/src/types/json.js +2 -2
  603. package/dist/src/types/typecheck.d.ts +3 -3
  604. package/dist/src/utils/assert.d.ts +4 -16
  605. package/dist/src/utils/assert.js +7 -24
  606. package/dist/src/utils/build-info.d.ts +6 -6
  607. package/dist/src/utils/build-info.js +6 -6
  608. package/dist/src/utils/child-env.d.ts +7 -6
  609. package/dist/src/utils/child-env.js +5 -5
  610. package/dist/src/utils/concurrency.d.ts +2 -2
  611. package/dist/src/utils/concurrency.js +2 -2
  612. package/dist/src/utils/elapsed.js +10 -1
  613. package/dist/src/utils/errors.d.ts +8 -8
  614. package/dist/src/utils/errors.js +8 -8
  615. package/dist/src/utils/fs.d.ts +1 -1
  616. package/dist/src/utils/fs.js +15 -20
  617. package/dist/src/utils/hash.d.ts +12 -0
  618. package/dist/src/utils/hash.js +16 -0
  619. package/dist/src/utils/line-dispatch.d.ts +15 -0
  620. package/dist/src/utils/line-dispatch.js +48 -0
  621. package/dist/src/utils/logger.d.ts +4 -4
  622. package/dist/src/utils/logger.js +11 -11
  623. package/dist/src/utils/machine-output.js +2 -2
  624. package/dist/src/utils/options.d.ts +14 -20
  625. package/dist/src/utils/options.js +26 -27
  626. package/dist/src/utils/package-root.js +5 -14
  627. package/dist/src/utils/paths.d.ts +4 -4
  628. package/dist/src/utils/paths.js +4 -4
  629. package/dist/src/utils/platform.d.ts +0 -4
  630. package/dist/src/utils/process-group.d.ts +10 -9
  631. package/dist/src/utils/process-group.js +37 -36
  632. package/dist/src/utils/process.d.ts +70 -55
  633. package/dist/src/utils/process.js +129 -179
  634. package/dist/src/utils/ps-duration.d.ts +4 -4
  635. package/dist/src/utils/ps-duration.js +9 -9
  636. package/dist/src/utils/regex.d.ts +4 -4
  637. package/dist/src/utils/regex.js +7 -7
  638. package/dist/src/utils/sleep.d.ts +26 -0
  639. package/dist/src/utils/sleep.js +31 -0
  640. package/dist/src/utils/stdio-drain.d.ts +7 -7
  641. package/dist/src/utils/stdio-drain.js +8 -8
  642. package/dist/src/utils/validation.d.ts +12 -49
  643. package/dist/src/utils/validation.js +26 -36
  644. package/docs/README.md +2 -2
  645. package/docs/configuration.md +163 -69
  646. package/docs/exit-codes.md +66 -49
  647. package/docs/furnace.md +20 -19
  648. package/docs/lifecycle-invariants.md +414 -247
  649. package/docs/machine-output.md +58 -34
  650. package/docs/patch-workflow.md +48 -44
  651. package/docs/run-logs.md +72 -28
  652. package/docs/testing.md +105 -98
  653. package/docs/verification-trees.md +23 -22
  654. package/package.json +7 -6
  655. package/dist/src/commands/rebase.d.ts +0 -4
  656. package/dist/src/commands/rebase.js +0 -5
  657. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  658. package/dist/src/core/patch-artifact-normalize.js +0 -24
  659. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  660. package/dist/src/core/patch-lint-reexports.js +0 -8
  661. package/dist/src/core/wire-targets.d.ts +0 -7
  662. package/dist/src/core/wire-targets.js +0 -8
@@ -1,20 +1,9 @@
1
1
  import type { ComponentApplyContext, CustomComponentConfig, DryRunAction, OverrideComponentConfig, StepError } from '../types/furnace.js';
2
2
  import { type RollbackJournal } from './furnace-rollback.js';
3
- interface DirectoryEntry {
4
- isFile(): boolean;
5
- isSymbolicLink?(): boolean;
6
- name: string;
7
- }
8
- /**
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.
12
- */
13
- export declare function isRegularFile(entry: DirectoryEntry): boolean;
14
3
  /**
15
4
  * Filter deciding which files in an override workspace directory are candidates
16
5
  * for copying into the engine. Exported so `furnace remove` can invert apply
17
- * using the exact same file set — the "files to restore" set is defined as the
6
+ * using the same file set: the "files to restore" set is defined as the
18
7
  * inverse of the "files apply would have written" set.
19
8
  */
20
9
  export declare function isOverrideCopyCandidate(entryName: string, type: OverrideComponentConfig['type']): boolean;
@@ -27,14 +16,14 @@ export declare function getOverrideEngineTargetPath(engineDir: string, config: O
27
16
  * Behaviour matches the per-file branch of `restoreOverrideEngineFiles` in
28
17
  * `furnace remove`: snapshot first, then either `git restore` (if the file
29
18
  * exists in HEAD) or hard-delete (if the override introduced the file). The
30
- * caller MUST guarantee `engineDir` is a git repository — this helper does
19
+ * caller must guarantee `engineDir` is a git repository. This helper does
31
20
  * not re-check, because both `furnace remove` and `furnace apply` already
32
21
  * own the precondition check at their entry points and re-checking on every
33
22
  * file would balloon git invocations.
34
23
  *
35
24
  * Returns the action taken so the caller can produce accurate user-facing
36
25
  * counts (`restored` vs `removed`). `noop` means the file was neither in HEAD
37
- * nor on disk, which can happen when the engine was reset out-of-band — the
26
+ * nor on disk, which can happen when the engine was reset out-of-band. The
38
27
  * caller should treat that as a successful no-op rather than an error.
39
28
  */
40
29
  export declare function restoreOverrideFileToBaseline(engineDir: string, enginePath: string, journal: RollbackJournal): Promise<'restored' | 'removed' | 'noop'>;
@@ -43,14 +32,14 @@ export declare function computeComponentChecksums(componentDir: string): Promise
43
32
  /**
44
33
  * Removes engine copies of files that the developer has deleted from a custom
45
34
  * component's workspace since the last apply. `.ftl` files live under the
46
- * shared Fluent tree (`engine/${FTL_DIR}`); everything else lives under
35
+ * shared Fluent tree (`engine/${FTL_DIR}`). Everything else lives under
47
36
  * `engine/${config.targetPath}`. Snapshots each removal into the journal so a
48
37
  * mid-apply failure can roll the engine back to its pre-undeploy state. Files
49
38
  * that are already missing from the engine are silently no-op (the engine
50
- * may have been reset out-of-band — refusing here would surface a confusing
51
- * error in a recovery path).
39
+ * may have been reset out-of-band, and refusing here would surface a
40
+ * confusing error in a recovery path).
52
41
  *
53
- * Does **not** touch jar.mn or customElements.js: registration churn is the
42
+ * Does not touch jar.mn or customElements.js: registration churn is the
54
43
  * caller's responsibility, since it must coordinate with the new file list
55
44
  * computed by the regular apply step that follows.
56
45
  */
@@ -62,9 +51,9 @@ export declare function undeployCustomFiles(engineDir: string, config: CustomCom
62
51
  * HEAD if it was a Firefox baseline file or hard-deletes it if the override
63
52
  * had introduced it.
64
53
  *
65
- * Requires `engineDir` to be a git repository — overrides cannot be inverted
54
+ * Requires `engineDir` to be a git repository: overrides cannot be inverted
66
55
  * without git HEAD as the source of truth. The caller is expected to have
67
- * already validated this precondition for the apply path; we re-check here
56
+ * already validated this precondition for the apply path. We re-check here
68
57
  * so unit tests that exercise this helper directly cannot accidentally
69
58
  * silent-fail on a non-git fixture.
70
59
  */
@@ -1,10 +1,10 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { createHash } from 'node:crypto';
3
2
  import { readdir } from 'node:fs/promises';
4
3
  import { join, relative } from 'node:path';
5
4
  import { FurnaceError } from '../errors/furnace.js';
6
5
  import { toError } from '../utils/errors.js';
7
6
  import { copyFile, ensureDir, pathExists, readText, removeFile } from '../utils/fs.js';
7
+ import { sha256Hex } from '../utils/hash.js';
8
8
  import { verbose } from '../utils/logger.js';
9
9
  import { normalizePathSlashes } from '../utils/paths.js';
10
10
  import { buildCustomDryRunActions } from './furnace-apply-dry-run.js';
@@ -12,30 +12,16 @@ import { applyCustomFtlFile, applySharedFtlPrune, removeCustomFtlJarMnEntry, } f
12
12
  import { normalizeForChecksum } from './furnace-checksum-utils.js';
13
13
  import { CUSTOM_ELEMENTS_JS, JAR_MN } from './furnace-constants.js';
14
14
  import { deployFileWithFragments, SHARED_FRAGMENTS_DIR } from './furnace-css-fragments.js';
15
+ import { isRegularFile } from './furnace-dir-entry.js';
15
16
  import { addCustomElementRegistration, addJarMnEntries } from './furnace-registration.js';
16
17
  import { recordCreatedDir, snapshotFile } from './furnace-rollback.js';
17
18
  import { checkRegistrationConsistency } from './furnace-validate-registration.js';
18
19
  import { isGitRepository } from './git.js';
19
20
  import { fileExistsInHead, restoreTrackedPath } from './git-file-ops.js';
20
- /**
21
- * True for a plain-file directory entry — symlinks and directories are
22
- * never copy candidates. Exported for the patch-owned overwrite probe,
23
- * which walks the same override copy-candidate set as apply.
24
- */
25
- export function isRegularFile(entry) {
26
- if (!entry.isFile())
27
- return false;
28
- if (typeof entry.isSymbolicLink === 'function' && entry.isSymbolicLink())
29
- return false;
30
- return true;
31
- }
32
- function isChecksummedComponentFile(name) {
33
- return name.endsWith('.mjs') || name.endsWith('.css') || name.endsWith('.ftl');
34
- }
35
21
  /**
36
22
  * Filter deciding which files in an override workspace directory are candidates
37
23
  * for copying into the engine. Exported so `furnace remove` can invert apply
38
- * using the exact same file set — the "files to restore" set is defined as the
24
+ * using the same file set: the "files to restore" set is defined as the
39
25
  * inverse of the "files apply would have written" set.
40
26
  */
41
27
  export function isOverrideCopyCandidate(entryName, type) {
@@ -60,18 +46,18 @@ export function getOverrideEngineTargetPath(engineDir, config, fileName, ftlDir)
60
46
  * Behaviour matches the per-file branch of `restoreOverrideEngineFiles` in
61
47
  * `furnace remove`: snapshot first, then either `git restore` (if the file
62
48
  * exists in HEAD) or hard-delete (if the override introduced the file). The
63
- * caller MUST guarantee `engineDir` is a git repository — this helper does
49
+ * caller must guarantee `engineDir` is a git repository. This helper does
64
50
  * not re-check, because both `furnace remove` and `furnace apply` already
65
51
  * own the precondition check at their entry points and re-checking on every
66
52
  * file would balloon git invocations.
67
53
  *
68
54
  * Returns the action taken so the caller can produce accurate user-facing
69
55
  * counts (`restored` vs `removed`). `noop` means the file was neither in HEAD
70
- * nor on disk, which can happen when the engine was reset out-of-band — the
56
+ * nor on disk, which can happen when the engine was reset out-of-band. The
71
57
  * caller should treat that as a successful no-op rather than an error.
72
58
  */
73
59
  export async function restoreOverrideFileToBaseline(engineDir, enginePath, journal) {
74
- // Engine-relative paths are IDENTIFIERS here, not filesystem arguments:
60
+ // Engine-relative paths are identifiers here, not filesystem arguments:
75
61
  // they are handed to git, recorded in furnace state, and compared against
76
62
  // the POSIX paths furnace.json and jar.mn already carry. `relative()`
77
63
  // returns backslashes on Windows, so without this the same file has two
@@ -80,8 +66,8 @@ export async function restoreOverrideFileToBaseline(engineDir, enginePath, journ
80
66
  // Snapshot before mutation so a later rollback can undo both restoration
81
67
  // (writes whatever content we removed back) and deletion (recreates the
82
68
  // file). Snapshotting a missing path records `{ existed: false }`, which
83
- // restoreFile turns into a delete — exactly the inverse of "we just
84
- // wrote a file here", which is correct for the noop case too.
69
+ // restoreFile turns into a delete, the inverse of "we just wrote a file
70
+ // here", which is correct for the noop case too.
85
71
  await snapshotFile(journal, enginePath);
86
72
  if (await fileExistsInHead(engineDir, relPath)) {
87
73
  await restoreTrackedPath(engineDir, relPath);
@@ -102,10 +88,13 @@ export async function computeComponentChecksums(componentDir) {
102
88
  continue;
103
89
  if (entry.name === 'override.json')
104
90
  continue;
105
- if (!isChecksummedComponentFile(entry.name))
91
+ // The three extensions a component can deploy. Anything else in the
92
+ // workspace directory is not part of the component's checksum identity.
93
+ const { name: entryName } = entry;
94
+ if (!entryName.endsWith('.mjs') && !entryName.endsWith('.css') && !entryName.endsWith('.ftl'))
106
95
  continue;
107
96
  const content = await readText(join(componentDir, entry.name));
108
- const hash = createHash('sha256').update(normalizeForChecksum(content)).digest('hex');
97
+ const hash = sha256Hex(normalizeForChecksum(content));
109
98
  checksums[entry.name] = hash;
110
99
  }
111
100
  return checksums;
@@ -113,14 +102,14 @@ export async function computeComponentChecksums(componentDir) {
113
102
  /**
114
103
  * Removes engine copies of files that the developer has deleted from a custom
115
104
  * component's workspace since the last apply. `.ftl` files live under the
116
- * shared Fluent tree (`engine/${FTL_DIR}`); everything else lives under
105
+ * shared Fluent tree (`engine/${FTL_DIR}`). Everything else lives under
117
106
  * `engine/${config.targetPath}`. Snapshots each removal into the journal so a
118
107
  * mid-apply failure can roll the engine back to its pre-undeploy state. Files
119
108
  * that are already missing from the engine are silently no-op (the engine
120
- * may have been reset out-of-band — refusing here would surface a confusing
121
- * error in a recovery path).
109
+ * may have been reset out-of-band, and refusing here would surface a
110
+ * confusing error in a recovery path).
122
111
  *
123
- * Does **not** touch jar.mn or customElements.js: registration churn is the
112
+ * Does not touch jar.mn or customElements.js: registration churn is the
124
113
  * caller's responsibility, since it must coordinate with the new file list
125
114
  * computed by the regular apply step that follows.
126
115
  */
@@ -138,7 +127,7 @@ export async function undeployCustomFiles(engineDir, config, deletedFiles, ftlDi
138
127
  removed.push(normalizePathSlashes(relative(engineDir, enginePath)));
139
128
  }
140
129
  // When an `.ftl` is deleted from the workspace the corresponding locale
141
- // jar.mn entry must also be dropped — otherwise the chrome URI points at
130
+ // jar.mn entry must also be dropped. Otherwise the chrome URI points at
142
131
  // a missing file and runtime Fluent resolution breaks silently.
143
132
  // `removeCustomFtlJarMnEntry` early-returns for `sharedFtl` components
144
133
  // (the shared bundle is owned elsewhere).
@@ -153,9 +142,9 @@ export async function undeployCustomFiles(engineDir, config, deletedFiles, ftlDi
153
142
  * HEAD if it was a Firefox baseline file or hard-deletes it if the override
154
143
  * had introduced it.
155
144
  *
156
- * Requires `engineDir` to be a git repository — overrides cannot be inverted
145
+ * Requires `engineDir` to be a git repository: overrides cannot be inverted
157
146
  * without git HEAD as the source of truth. The caller is expected to have
158
- * already validated this precondition for the apply path; we re-check here
147
+ * already validated this precondition for the apply path. We re-check here
159
148
  * so unit tests that exercise this helper directly cannot accidentally
160
149
  * silent-fail on a non-git fixture.
161
150
  */
@@ -169,11 +158,11 @@ export async function undeployOverrideFiles(engineDir, config, deletedFiles, ftl
169
158
  if (!(await isGitRepository(engineDir))) {
170
159
  throw new FurnaceError('Cannot undeploy override files: engine is not a git repository. Run "fireforge download" to initialise it.');
171
160
  }
172
- // Note: we deliberately do not re-filter `deletedFiles` through
161
+ // Note: we do not re-filter `deletedFiles` through
173
162
  // `isOverrideCopyCandidate(fileName, config.type)`. A file recorded in
174
163
  // `previous` was already a valid copy candidate when it was deployed, and
175
164
  // re-filtering would block cleanup if the override type later flipped
176
- // from `full` to `css-only` — exactly the case we need cleanup for.
165
+ // from `full` to `css-only`, which is the case we need cleanup for.
177
166
  const restored = [];
178
167
  const removed = [];
179
168
  for (const fileName of deletedFiles) {
@@ -233,13 +222,13 @@ export async function hasOverrideEngineDrift(ctx, config, cachedEngineChecksums)
233
222
  const engineContent = normalizeForChecksum(await readText(enginePath));
234
223
  // Fast path: compare engine content hash against cached value from last apply
235
224
  if (cachedEngineChecksums) {
236
- const engineHash = createHash('sha256').update(engineContent).digest('hex');
225
+ const engineHash = sha256Hex(engineContent);
237
226
  const cachedHash = cachedEngineChecksums[entry.name];
238
227
  if (cachedHash && engineHash !== cachedHash) {
239
228
  return true;
240
229
  }
241
230
  if (cachedHash)
242
- continue; // Hash match — skip full source comparison
231
+ continue; // Hash match, skip full source comparison
243
232
  }
244
233
  // Slow path: byte-compare engine content against workspace source
245
234
  const srcContent = normalizeForChecksum(await readText(join(componentDir, entry.name)));
@@ -270,7 +259,7 @@ export async function hasCustomEngineDrift(ctx, config) {
270
259
  // Registration drift: only check jar.mn entries for the file types that
271
260
  // actually exist in source. jarMn{Mjs,Css} are substring checks, so a
272
261
  // component with only .mjs (no .css) should not be flagged when jarMnCss
273
- // is false — that is the expected post-apply state, not drift.
262
+ // is false. That is the expected post-apply state, not drift.
274
263
  const entries = await readdir(componentDir, { withFileTypes: true, encoding: 'utf8' });
275
264
  let hasMjs = false;
276
265
  let hasCss = false;
@@ -322,16 +311,16 @@ export async function applyCustomComponent(ctx, config, dryRun = false, rollback
322
311
  // must complete before any copy (they read the original content), but
323
312
  // independent files can be processed concurrently.
324
313
  const filesToCopy = entries.filter((entry) => isRegularFile(entry) && (entry.name.endsWith('.mjs') || entry.name.endsWith('.css')));
325
- // Snapshot phase (serial — journal is not concurrent-safe for the same path)
314
+ // Snapshot phase (serial: journal is not concurrent-safe for the same path)
326
315
  for (const entry of filesToCopy) {
327
316
  const dest = join(targetDir, entry.name);
328
317
  if (rollbackJournal) {
329
318
  await snapshotFile(rollbackJournal, dest);
330
319
  }
331
320
  }
332
- // Copy phase (parallel — independent file writes to different paths).
321
+ // Copy phase (parallel: independent file writes to different paths).
333
322
  // CSS files carrying @fireforge-include directives are written as their
334
- // fragment-expanded form; the workspace source keeps only the directive,
323
+ // fragment-expanded form. The workspace source keeps only the directive,
335
324
  // so shared CSS stays single-sourced.
336
325
  const sharedDir = join(componentDir, '..', '..', SHARED_FRAGMENTS_DIR);
337
326
  await Promise.all(filesToCopy.map(async (entry) => {
@@ -52,7 +52,7 @@ export function logApplyResult(result, isDryRun) {
52
52
  }
53
53
  }
54
54
  // Patch-owned overwrite warnings print on every non-dry-run
55
- // outcome — including the rolled-back branch, where the overwrite
55
+ // outcome, including the rolled-back branch, where the overwrite
56
56
  // happened before the rollback restored it and the operator still needs
57
57
  // to know the deployed copy was momentarily replaced.
58
58
  if (!isDryRun && result.warnings !== undefined) {
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * Patch-owned overwrite warnings for `furnace apply`.
3
3
  *
4
- * For Furnace-managed components, apply OVERWRITES the deployed engine
4
+ * For Furnace-managed components, apply overwrites the deployed engine
5
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
6
+ * exported into a patch (but never back-ported to the component source) is
7
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
8
+ * "someone's uncommitted work". This module detects that case before
9
+ * the copy (deployed bytes differ from the component source and the file is
10
10
  * patch-owned) and produces a per-file warning naming the file, the owning
11
11
  * patch, and the consequence.
12
12
  *
13
- * The per-file byte comparison already exists —
13
+ * The per-file byte comparison already exists:
14
14
  * `checkRegistrationConsistency` for custom components (fragment- and
15
- * ftl-aware) and the copy-candidate walk for overrides — so this module only
15
+ * ftl-aware) and the copy-candidate walk for overrides. This module only
16
16
  * surfaces what was previously computed and thrown away.
17
17
  */
18
18
  import type { CustomComponentConfig, OverrideComponentConfig } from '../types/furnace.js';
@@ -26,7 +26,7 @@ export interface PatchOwnedOverwriteWarning {
26
26
  }
27
27
  /**
28
28
  * Loads the file → owning-patch map for the overwrite warning.
29
- * A missing or unreadable patches manifest degrades to an empty map — the
29
+ * A missing or unreadable patches manifest degrades to an empty map. The
30
30
  * warning is advisory and must never block an apply.
31
31
  */
32
32
  export declare function loadPatchClaimsForApply(root: string): Promise<ReadonlyMap<string, readonly string[]>>;
@@ -55,8 +55,8 @@ export type PatchOwnedOverwriteProbe = {
55
55
  };
56
56
  /**
57
57
  * Finds deployed files this component's apply is about to overwrite whose
58
- * engine bytes differ from the component source AND that are patch-owned.
59
- * Probe failures degrade to a verbose line and an empty list — the apply
58
+ * engine bytes differ from the component source and that are patch-owned.
59
+ * Probe failures degrade to a verbose line and an empty list. The apply
60
60
  * itself must not fail because the warning probe could not run.
61
61
  */
62
62
  export declare function findPatchOwnedOverwrites(args: PatchOwnedOverwriteProbe): Promise<PatchOwnedOverwriteWarning[]>;
@@ -2,18 +2,18 @@
2
2
  /**
3
3
  * Patch-owned overwrite warnings for `furnace apply`.
4
4
  *
5
- * For Furnace-managed components, apply OVERWRITES the deployed engine
5
+ * For Furnace-managed components, apply overwrites the deployed engine
6
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
7
+ * exported into a patch (but never back-ported to the component source) is
8
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
9
+ * "someone's uncommitted work". This module detects that case before
10
+ * the copy (deployed bytes differ from the component source and the file is
11
11
  * patch-owned) and produces a per-file warning naming the file, the owning
12
12
  * patch, and the consequence.
13
13
  *
14
- * The per-file byte comparison already exists —
14
+ * The per-file byte comparison already exists:
15
15
  * `checkRegistrationConsistency` for custom components (fragment- and
16
- * ftl-aware) and the copy-candidate walk for overrides — so this module only
16
+ * ftl-aware) and the copy-candidate walk for overrides. This module only
17
17
  * surfaces what was previously computed and thrown away.
18
18
  */
19
19
  import { readdir } from 'node:fs/promises';
@@ -21,15 +21,17 @@ import { join, relative } from 'node:path';
21
21
  import { toError } from '../utils/errors.js';
22
22
  import { pathExists, readText } from '../utils/fs.js';
23
23
  import { verbose } from '../utils/logger.js';
24
+ import { normalizePathSlashes } from '../utils/paths.js';
24
25
  import { getProjectPaths } from './config.js';
25
- import { getOverrideEngineTargetPath, isOverrideCopyCandidate, isRegularFile, } from './furnace-apply-helpers.js';
26
+ import { getOverrideEngineTargetPath, isOverrideCopyCandidate } from './furnace-apply-helpers.js';
26
27
  import { FTL_DIR } from './furnace-constants.js';
28
+ import { isRegularFile } from './furnace-dir-entry.js';
27
29
  import { checkRegistrationConsistency } from './furnace-validate-registration.js';
28
30
  import { loadPatchesManifest } from './patch-manifest.js';
29
31
  import { buildPatchClaims } from './status-classify.js';
30
32
  /**
31
33
  * Loads the file → owning-patch map for the overwrite warning.
32
- * A missing or unreadable patches manifest degrades to an empty map — the
34
+ * A missing or unreadable patches manifest degrades to an empty map. The
33
35
  * warning is advisory and must never block an apply.
34
36
  */
35
37
  export async function loadPatchClaimsForApply(root) {
@@ -86,7 +88,7 @@ async function findOverrideOverwrites(args) {
86
88
  // A missing target is a fresh deploy, not a lost engine edit.
87
89
  if (!(await pathExists(enginePath)))
88
90
  continue;
89
- const engineRel = relative(engineDir, enginePath).replace(/\\/g, '/');
91
+ const engineRel = normalizePathSlashes(relative(engineDir, enginePath));
90
92
  const owners = patchClaims.get(engineRel);
91
93
  if (owners === undefined || owners.length === 0)
92
94
  continue;
@@ -102,8 +104,8 @@ async function findOverrideOverwrites(args) {
102
104
  }
103
105
  /**
104
106
  * Finds deployed files this component's apply is about to overwrite whose
105
- * engine bytes differ from the component source AND that are patch-owned.
106
- * Probe failures degrade to a verbose line and an empty list — the apply
107
+ * engine bytes differ from the component source and that are patch-owned.
108
+ * Probe failures degrade to a verbose line and an empty list. The apply
107
109
  * itself must not fail because the warning probe could not run.
108
110
  */
109
111
  export async function findPatchOwnedOverwrites(args) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Dry-run action builders for files deleted from a component workspace since
3
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`.
4
+ * line budget. The real undeploy paths stay in `furnace-apply-helpers.ts`.
5
5
  */
6
6
  import type { CustomComponentConfig, DryRunAction, OverrideComponentConfig } from '../types/furnace.js';
7
7
  /** Plans the engine-restore actions for deleted override workspace files. */
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Dry-run action builders for files deleted from a component workspace since
4
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`.
5
+ * line budget. The real undeploy paths stay in `furnace-apply-helpers.ts`.
6
6
  */
7
7
  import { join } from 'node:path';
8
8
  import { getOverrideEngineTargetPath } from './furnace-apply-helpers.js';
@@ -1,15 +1,15 @@
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, hasComponentChanged, prefixChecksums, } from './furnace-apply-helpers.js';
4
+ export { computeComponentChecksums, prefixChecksums } from './furnace-apply-helpers.js';
5
5
  /**
6
6
  * Result of {@link applyAllComponents}.
7
7
  *
8
8
  * Named so consumers can refer to the shape directly instead of going
9
9
  * through `Awaited<ReturnType<typeof applyAllComponents>>`.
10
10
  *
11
- * `actions` is populated only on a dry run; `rollbackJournal` only when
12
- * `persistState: false` hands journal ownership back to the caller.
11
+ * `actions` is populated only on a dry run. `rollbackJournal` is set only
12
+ * when `persistState: false` hands journal ownership back to the caller.
13
13
  */
14
14
  export type ApplyAllComponentsResult = ApplyResult & {
15
15
  actions?: DryRunAction[];
@@ -44,6 +44,6 @@ export declare function applyAllComponents(root: string, dryRun?: boolean, optio
44
44
  }): Promise<ApplyAllComponentsResult>; /**
45
45
  * Shared context threaded through the batch apply loops. Bundles the state
46
46
  * both loops mutate (result/actions/checksums) with the immutable run
47
- * parameters; the 12–13 positional parameters this replaced let call sites
47
+ * parameters. The 12-13 positional parameters this replaced let call sites
48
48
  * drift and made every new parameter a two-signature change.
49
49
  */
@@ -19,7 +19,18 @@ import { addJarMnEntries, removeCustomElementRegistration, removeJarMnEntries, }
19
19
  import { createRollbackJournal, restoreRollbackJournalOrThrow, snapshotFile, } from './furnace-rollback.js';
20
20
  import { blockingStepErrors, hasBlockingStepErrors } from './furnace-step-errors.js';
21
21
  import { runPostApplyConsistencyChecks } from './furnace-validate-registration.js';
22
- export { computeComponentChecksums, hasComponentChanged, prefixChecksums, } from './furnace-apply-helpers.js';
22
+ export { computeComponentChecksums, prefixChecksums } from './furnace-apply-helpers.js';
23
+ /**
24
+ * Records one component's checksums into the run-wide accumulator, under the
25
+ * flattened `type/name/file` keys the state file stores. A Map keeps the
26
+ * accumulation explicit. The previous `Object.assign` merges read as if
27
+ * they replaced the accumulator rather than adding to it.
28
+ */
29
+ function recordComponentChecksums(accumulator, checksums, type, name) {
30
+ for (const [key, value] of Object.entries(prefixChecksums(checksums, type, name))) {
31
+ accumulator.set(key, value);
32
+ }
33
+ }
23
34
  function addMissingComponentError(result, name, directoryPath) {
24
35
  result.errors.push({
25
36
  name,
@@ -48,13 +59,13 @@ async function applyOverrideBatch(ctx) {
48
59
  const changed = await hasComponentChanged(componentDir, previous, currentChecksums);
49
60
  if (!changed) {
50
61
  // Fast path holds only if the engine still reflects what we deployed.
51
- // reset/download/manual edits can silently erase engine files; the
52
- // checksum record alone cannot detect that.
62
+ // reset/download/manual edits can silently erase engine files, and
63
+ // the checksum record alone cannot detect that.
53
64
  const cachedEngine = extractComponentChecksums(state.engineChecksums, 'override', name);
54
65
  const drifted = await hasOverrideEngineDrift({ engineDir, componentDir, ftlDir }, overrideConfig, cachedEngine);
55
66
  if (!drifted) {
56
67
  result.skipped.push({ name, reason: 'No changes since last apply' });
57
- Object.assign(newChecksums, prefixChecksums(previous, 'override', name));
68
+ recordComponentChecksums(newChecksums, previous, 'override', name);
58
69
  continue;
59
70
  }
60
71
  }
@@ -75,9 +86,9 @@ async function applyOverrideBatch(ctx) {
75
86
  filesAffectedTotal.push(...restored, ...removed);
76
87
  }
77
88
  if (!dryRun) {
78
- // Runs unconditionally — including when the component source
79
- // changed — because the lost-work case is precisely a deployed
80
- // engine edit that the incoming copy is about to replace.
89
+ // Runs unconditionally, including when the component source
90
+ // changed, because the lost-work case is a deployed engine edit
91
+ // that the incoming copy is about to replace.
81
92
  recordOverwriteWarnings(result, await findPatchOwnedOverwrites({
82
93
  type: 'override',
83
94
  engineDir,
@@ -95,7 +106,7 @@ async function applyOverrideBatch(ctx) {
95
106
  filesAffectedTotal.push(...filesAffected);
96
107
  result.applied.push({ name, type: 'override', filesAffected: filesAffectedTotal });
97
108
  if (!dryRun) {
98
- Object.assign(newChecksums, prefixChecksums(currentChecksums, 'override', name));
109
+ recordComponentChecksums(newChecksums, currentChecksums, 'override', name);
99
110
  }
100
111
  }
101
112
  catch (error) {
@@ -110,11 +121,12 @@ async function applyOverrideBatch(ctx) {
110
121
  * After undeploying deleted files, the in-engine jar.mn and
111
122
  * customElements.js still carry entries for the removed files. Re-sync them
112
123
  * by removing all of `name`'s jar.mn entries and re-adding only those that
113
- * still exist in the workspace; if the .mjs itself was deleted, also drop
124
+ * still exist in the workspace. If the .mjs itself was deleted, also drop
114
125
  * the customElements.js registration. Snapshots are taken under the same
115
126
  * journal so the undo path is symmetric with apply.
116
127
  */
117
- async function reconcileCustomRegistrationAfterUndeploy(engineDir, name, config, deletedFiles, currentChecksums, rollbackJournal, filesAffected) {
128
+ async function reconcileCustomRegistrationAfterUndeploy(args) {
129
+ const { engineDir, name, config, deletedFiles, currentChecksums, rollbackJournal, filesAffected, } = args;
118
130
  if (!config.register || deletedFiles.length === 0)
119
131
  return;
120
132
  const deletedRegistrationFiles = deletedFiles.filter((f) => f.endsWith('.mjs') || f.endsWith('.css'));
@@ -129,13 +141,14 @@ async function reconcileCustomRegistrationAfterUndeploy(engineDir, name, config,
129
141
  await removeJarMnEntries(engineDir, name);
130
142
  const liveJarFiles = Object.keys(currentChecksums).filter((f) => f.endsWith('.mjs') || f.endsWith('.css'));
131
143
  if (liveJarFiles.length > 0) {
132
- // applyCustomComponent has already added live entries; the remove above
133
- // dropped them too, so re-add now to leave jar.mn in the correct state.
144
+ // applyCustomComponent has already added live entries, and the remove
145
+ // above dropped them too, so re-add now to leave jar.mn in the correct
146
+ // state.
134
147
  await addJarMnEntries(engineDir, name, liveJarFiles);
135
148
  }
136
149
  filesAffected.push(JAR_MN);
137
150
  // If the .mjs file itself was deleted, the customElements registration
138
- // must go too — otherwise we leave a dangling import in the Pattern B
151
+ // must go too. Otherwise we leave a dangling import in the Pattern B
139
152
  // block that fails at runtime.
140
153
  if (deletedFiles.includes(`${name}.mjs`)) {
141
154
  if (rollbackJournal) {
@@ -212,7 +225,7 @@ async function applyCustomBatch(ctx, root, markerComment) {
212
225
  const drifted = await hasCustomEngineDrift({ root, name, componentDir, ftlDir }, customConfig);
213
226
  if (!drifted) {
214
227
  result.skipped.push({ name, reason: 'No changes since last apply' });
215
- Object.assign(newChecksums, prefixChecksums(previous, 'custom', name));
228
+ recordComponentChecksums(newChecksums, previous, 'custom', name);
216
229
  continue;
217
230
  }
218
231
  }
@@ -233,9 +246,9 @@ async function applyCustomBatch(ctx, root, markerComment) {
233
246
  filesAffectedTotal.push(...removed);
234
247
  }
235
248
  if (!dryRun) {
236
- // Runs unconditionally — the `changed === true` path used to skip
237
- // drift detection entirely, which is exactly when a deployed
238
- // engine-only fix gets silently replaced (J6).
249
+ // Runs unconditionally. The `changed === true` path used to skip
250
+ // drift detection entirely, which is when a deployed engine-only
251
+ // fix gets silently replaced (J6).
239
252
  recordOverwriteWarnings(result, await findPatchOwnedOverwrites({
240
253
  type: 'custom',
241
254
  root,
@@ -250,7 +263,15 @@ async function applyCustomBatch(ctx, root, markerComment) {
250
263
  allActions.push(...actions);
251
264
  }
252
265
  if (!dryRun && deletedFiles.length > 0 && blockingStepErrors(stepErrors).length === 0) {
253
- await reconcileCustomRegistrationAfterUndeploy(engineDir, name, customConfig, deletedFiles, currentChecksums, rollbackJournal, filesAffectedTotal);
266
+ await reconcileCustomRegistrationAfterUndeploy({
267
+ engineDir,
268
+ name,
269
+ config: customConfig,
270
+ deletedFiles,
271
+ currentChecksums,
272
+ rollbackJournal,
273
+ filesAffected: filesAffectedTotal,
274
+ });
254
275
  }
255
276
  filesAffectedTotal.push(...filesAffected);
256
277
  result.applied.push({
@@ -259,12 +280,12 @@ async function applyCustomBatch(ctx, root, markerComment) {
259
280
  filesAffected: filesAffectedTotal,
260
281
  ...(stepErrors.length > 0 ? { stepErrors } : {}),
261
282
  });
262
- // Only store checksums when the component applied without BLOCKING
283
+ // Only store checksums when the component applied without blocking
263
284
  // step errors, so that partially failed components are re-applied on
264
- // the next run. Advisory errors (FTL degradation) still persist —
285
+ // the next run. Advisory errors (FTL degradation) still persist, since
265
286
  // re-applying cannot fix a fork that has no locale jar.mn.
266
287
  if (!dryRun && blockingStepErrors(stepErrors).length === 0) {
267
- Object.assign(newChecksums, prefixChecksums(currentChecksums, 'custom', name));
288
+ recordComponentChecksums(newChecksums, currentChecksums, 'custom', name);
268
289
  }
269
290
  }
270
291
  catch (error) {
@@ -308,7 +329,7 @@ export async function applyAllComponents(root, dryRun = false, options) {
308
329
  // When `markerComment` is unset in fireforge.json, default it to
309
330
  // `binaryName.toUpperCase()` so the furnace-emitted edits to upstream
310
331
  // files (e.g. customElements.js) carry a marker that satisfies
311
- // `lintModificationComments` — that rule keys on
332
+ // `lintModificationComments`. That rule keys on
312
333
  // `${binaryName.toUpperCase()}:`. An explicit `markerComment` still wins.
313
334
  const forgeConfig = await loadConfig(root).catch(() => undefined);
314
335
  const markerComment = resolveFurnaceMarkerComment(forgeConfig);
@@ -318,7 +339,7 @@ export async function applyAllComponents(root, dryRun = false, options) {
318
339
  operationContext.registerJournal(rollbackJournal);
319
340
  }
320
341
  // Everything below this line can write to the engine. A real apply that
321
- // reached it without a journal would have no way back — neither the
342
+ // reached it without a journal would have no way back: neither the
322
343
  // lifecycle wrapper's throw path nor the signal handler can restore what
323
344
  // was never captured. `operationContext` is legitimately absent for the
324
345
  // few callers that drive apply outside the wrapper, so the invariant is on
@@ -330,7 +351,7 @@ export async function applyAllComponents(root, dryRun = false, options) {
330
351
  errors: [],
331
352
  };
332
353
  const allActions = [];
333
- const newChecksums = {};
354
+ const newChecksums = new Map();
334
355
  const componentName = options?.componentName;
335
356
  // When a single component is requested, validate it exists before running
336
357
  // the batch functions (which would silently skip an unknown name).
@@ -341,7 +362,7 @@ export async function applyAllComponents(root, dryRun = false, options) {
341
362
  }
342
363
  }
343
364
  // Patch-claim map for the overwrite warning: loaded once per
344
- // apply. A missing/unreadable manifest degrades to an empty map — the
365
+ // apply. A missing/unreadable manifest degrades to an empty map. The
345
366
  // warning is advisory and must never block the apply.
346
367
  const patchClaims = await loadPatchClaimsForApply(root);
347
368
  const batchContext = {
@@ -370,7 +391,7 @@ export async function applyAllComponents(root, dryRun = false, options) {
370
391
  if (!dryRun && !hasApplyStepErrors && result.errors.length === 0) {
371
392
  await runPostApplyConsistencyChecks(root, config, result, ftlDir);
372
393
  }
373
- // Recompute AFTER the consistency checks: they MUTATE entry.stepErrors
394
+ // Recompute after the consistency checks: they mutate entry.stepErrors
374
395
  // when the applied output is inconsistent (e.g. a jar.mn entry that
375
396
  // silently mis-landed). Reading the pre-check snapshot lets those failures
376
397
  // skip rollback and persist checksums for a component known to be
@@ -406,8 +427,8 @@ export async function applyAllComponents(root, dryRun = false, options) {
406
427
  // instead of byte-comparing against workspace sources.
407
428
  await updateFurnaceState(root, {
408
429
  lastApply: new Date().toISOString(),
409
- appliedChecksums: newChecksums,
410
- engineChecksums: { ...newChecksums },
430
+ appliedChecksums: Object.fromEntries(newChecksums),
431
+ engineChecksums: Object.fromEntries(newChecksums),
411
432
  });
412
433
  }
413
434
  else if (rollbackJournal) {
@@ -422,6 +443,6 @@ export async function applyAllComponents(root, dryRun = false, options) {
422
443
  } /**
423
444
  * Shared context threaded through the batch apply loops. Bundles the state
424
445
  * both loops mutate (result/actions/checksums) with the immutable run
425
- * parameters; the 12–13 positional parameters this replaced let call sites
446
+ * parameters. The 12-13 positional parameters this replaced let call sites
426
447
  * drift and made every new parameter a two-signature change.
427
448
  */