@hominis/fireforge 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +34 -9
  3. package/dist/bin/fireforge.js +21 -6
  4. package/dist/src/cli.js +22 -5
  5. package/dist/src/commands/bootstrap-checks.js +0 -1
  6. package/dist/src/commands/bootstrap.d.ts +2 -1
  7. package/dist/src/commands/bootstrap.js +16 -7
  8. package/dist/src/commands/build.js +4 -3
  9. package/dist/src/commands/config.js +30 -10
  10. package/dist/src/commands/discard.js +18 -3
  11. package/dist/src/commands/doctor/post-rebase-audit.js +0 -1
  12. package/dist/src/commands/doctor-check-core.js +0 -1
  13. package/dist/src/commands/doctor-external-toolchains.d.ts +3 -0
  14. package/dist/src/commands/doctor-external-toolchains.js +54 -0
  15. package/dist/src/commands/doctor-furnace-jar.js +0 -1
  16. package/dist/src/commands/doctor-furnace-manifest-sync.js +0 -1
  17. package/dist/src/commands/doctor-furnace.js +2 -2
  18. package/dist/src/commands/doctor-working-tree.js +0 -1
  19. package/dist/src/commands/doctor.js +4 -1
  20. package/dist/src/commands/download.js +28 -13
  21. package/dist/src/commands/export-all.js +5 -3
  22. package/dist/src/commands/export-flow.js +12 -7
  23. package/dist/src/commands/export-placement-gate.js +0 -1
  24. package/dist/src/commands/export-placement-policy.js +0 -1
  25. package/dist/src/commands/export-shared.d.ts +5 -1
  26. package/dist/src/commands/export-shared.js +18 -6
  27. package/dist/src/commands/export.js +15 -10
  28. package/dist/src/commands/furnace/apply.js +22 -6
  29. package/dist/src/commands/furnace/chrome-doc-remove.js +0 -1
  30. package/dist/src/commands/furnace/chrome-doc-templates.js +0 -1
  31. package/dist/src/commands/furnace/chrome-doc-tests.js +0 -1
  32. package/dist/src/commands/furnace/chrome-doc.js +0 -1
  33. package/dist/src/commands/furnace/create-browser-test.js +0 -1
  34. package/dist/src/commands/furnace/create-dry-run.js +0 -1
  35. package/dist/src/commands/furnace/create-features.js +0 -1
  36. package/dist/src/commands/furnace/create-mochikit.js +0 -1
  37. package/dist/src/commands/furnace/create-readback.js +0 -1
  38. package/dist/src/commands/furnace/create-templates.js +0 -1
  39. package/dist/src/commands/furnace/create-validation.js +0 -1
  40. package/dist/src/commands/furnace/create-xpcshell.js +0 -1
  41. package/dist/src/commands/furnace/create.js +0 -1
  42. package/dist/src/commands/furnace/deploy.js +7 -83
  43. package/dist/src/commands/furnace/diff.js +0 -1
  44. package/dist/src/commands/furnace/index.js +59 -25
  45. package/dist/src/commands/furnace/init.js +0 -1
  46. package/dist/src/commands/furnace/list.js +0 -1
  47. package/dist/src/commands/furnace/override.js +0 -1
  48. package/dist/src/commands/furnace/preview.js +3 -3
  49. package/dist/src/commands/furnace/refresh.js +0 -1
  50. package/dist/src/commands/furnace/remove-state.d.ts +15 -0
  51. package/dist/src/commands/furnace/remove-state.js +47 -1
  52. package/dist/src/commands/furnace/remove.js +3 -9
  53. package/dist/src/commands/furnace/rename-browser-test.js +1 -5
  54. package/dist/src/commands/furnace/rename-helpers.d.ts +6 -0
  55. package/dist/src/commands/furnace/rename-helpers.js +30 -1
  56. package/dist/src/commands/furnace/rename-xpcshell.js +7 -6
  57. package/dist/src/commands/furnace/rename.js +15 -36
  58. package/dist/src/commands/furnace/scan.js +0 -1
  59. package/dist/src/commands/furnace/status.js +0 -1
  60. package/dist/src/commands/furnace/sync.js +76 -4
  61. package/dist/src/commands/furnace/validate.js +0 -1
  62. package/dist/src/commands/furnace/validation-output.js +0 -1
  63. package/dist/src/commands/import.js +35 -9
  64. package/dist/src/commands/lint-per-patch.js +19 -7
  65. package/dist/src/commands/lint.js +13 -3
  66. package/dist/src/commands/manifest.js +1 -2
  67. package/dist/src/commands/package.js +2 -1
  68. package/dist/src/commands/patch/compact.js +1 -1
  69. package/dist/src/commands/patch/delete.js +1 -1
  70. package/dist/src/commands/patch/index.js +1 -1
  71. package/dist/src/commands/patch/lint-ignore.js +21 -6
  72. package/dist/src/commands/patch/move-files.js +1 -1
  73. package/dist/src/commands/patch/patch-context.js +0 -1
  74. package/dist/src/commands/patch/rename.js +4 -4
  75. package/dist/src/commands/patch/reorder.js +3 -4
  76. package/dist/src/commands/patch/split-plan.js +2 -1
  77. package/dist/src/commands/patch/split.js +4 -4
  78. package/dist/src/commands/patch/staged-dependency.js +1 -1
  79. package/dist/src/commands/patch/tier.js +18 -5
  80. package/dist/src/commands/re-export-bulk-scan.js +0 -1
  81. package/dist/src/commands/re-export-files.js +1 -1
  82. package/dist/src/commands/re-export-options.js +0 -1
  83. package/dist/src/commands/re-export-scan.js +0 -1
  84. package/dist/src/commands/re-export.js +6 -4
  85. package/dist/src/commands/rebase/abort.js +2 -9
  86. package/dist/src/commands/rebase/confirm.js +0 -1
  87. package/dist/src/commands/rebase/conflict-summary.js +0 -1
  88. package/dist/src/commands/rebase/continue.js +0 -1
  89. package/dist/src/commands/rebase/index.d.ts +1 -1
  90. package/dist/src/commands/rebase/index.js +10 -15
  91. package/dist/src/commands/rebase/patch-loop.js +38 -7
  92. package/dist/src/commands/rebase/summary.js +2 -3
  93. package/dist/src/commands/rebase.js +0 -1
  94. package/dist/src/commands/register.js +1 -1
  95. package/dist/src/commands/reset.js +16 -9
  96. package/dist/src/commands/resolve.js +2 -2
  97. package/dist/src/commands/run.js +4 -4
  98. package/dist/src/commands/setup-support.js +0 -1
  99. package/dist/src/commands/setup.js +1 -2
  100. package/dist/src/commands/source.js +1 -2
  101. package/dist/src/commands/status-output.js +1 -12
  102. package/dist/src/commands/status.js +147 -133
  103. package/dist/src/commands/test-appdir.js +0 -1
  104. package/dist/src/commands/test-diagnose.js +18 -2
  105. package/dist/src/commands/test-modes.d.ts +15 -0
  106. package/dist/src/commands/test-modes.js +61 -0
  107. package/dist/src/commands/test-register.d.ts +4 -0
  108. package/dist/src/commands/test-register.js +64 -0
  109. package/dist/src/commands/test-run.d.ts +23 -7
  110. package/dist/src/commands/test-run.js +15 -14
  111. package/dist/src/commands/test.d.ts +0 -4
  112. package/dist/src/commands/test.js +85 -86
  113. package/dist/src/commands/token-coverage.js +0 -1
  114. package/dist/src/commands/token.js +1 -2
  115. package/dist/src/commands/typecheck.js +1 -1
  116. package/dist/src/commands/verify.js +3 -9
  117. package/dist/src/commands/watch.js +5 -1
  118. package/dist/src/commands/wire.js +1 -1
  119. package/dist/src/core/ast-utils.js +0 -1
  120. package/dist/src/core/brand-validation.js +0 -1
  121. package/dist/src/core/branding.js +0 -1
  122. package/dist/src/core/browser-wire.js +0 -1
  123. package/dist/src/core/build-audit-platform.js +0 -1
  124. package/dist/src/core/build-audit-registration.js +0 -1
  125. package/dist/src/core/build-audit-resolve.js +0 -1
  126. package/dist/src/core/build-audit-transforms.js +0 -1
  127. package/dist/src/core/build-audit.js +0 -1
  128. package/dist/src/core/build-baseline-types.js +0 -1
  129. package/dist/src/core/build-baseline.js +0 -1
  130. package/dist/src/core/build-prepare.js +2 -2
  131. package/dist/src/core/config-mutate.js +0 -1
  132. package/dist/src/core/config-paths.d.ts +2 -2
  133. package/dist/src/core/config-paths.js +6 -1
  134. package/dist/src/core/config-state.js +0 -1
  135. package/dist/src/core/config-validate-patch-policy.js +0 -1
  136. package/dist/src/core/config-validate-test-toolchains.d.ts +8 -0
  137. package/dist/src/core/config-validate-test-toolchains.js +105 -0
  138. package/dist/src/core/config-validate.js +3 -1
  139. package/dist/src/core/config.js +0 -1
  140. package/dist/src/core/destructive.js +0 -1
  141. package/dist/src/core/diff-hunks.js +13 -7
  142. package/dist/src/core/engine-changes.js +0 -1
  143. package/dist/src/core/engine-session-lock.d.ts +12 -0
  144. package/dist/src/core/engine-session-lock.js +45 -0
  145. package/dist/src/core/file-lock.d.ts +8 -0
  146. package/dist/src/core/file-lock.js +157 -48
  147. package/dist/src/core/firefox-archive.d.ts +4 -0
  148. package/dist/src/core/firefox-archive.js +6 -1
  149. package/dist/src/core/firefox-cache.js +60 -4
  150. package/dist/src/core/firefox-download.js +0 -1
  151. package/dist/src/core/firefox-extract.js +75 -16
  152. package/dist/src/core/firefox-ignorefile.js +0 -1
  153. package/dist/src/core/firefox.d.ts +12 -0
  154. package/dist/src/core/firefox.js +64 -2
  155. package/dist/src/core/furnace-apply-dry-run.js +0 -1
  156. package/dist/src/core/furnace-apply-ftl.d.ts +7 -3
  157. package/dist/src/core/furnace-apply-ftl.js +10 -5
  158. package/dist/src/core/furnace-apply-helpers.js +0 -1
  159. package/dist/src/core/furnace-apply-output.js +2 -2
  160. package/dist/src/core/furnace-apply.d.ts +7 -1
  161. package/dist/src/core/furnace-apply.js +47 -13
  162. package/dist/src/core/furnace-checksum-utils.js +0 -1
  163. package/dist/src/core/furnace-config-array-utils.js +0 -1
  164. package/dist/src/core/furnace-config-custom.js +0 -1
  165. package/dist/src/core/furnace-config-order.js +0 -1
  166. package/dist/src/core/furnace-config-tokens.js +0 -1
  167. package/dist/src/core/furnace-config-validate.js +0 -1
  168. package/dist/src/core/furnace-config.d.ts +11 -0
  169. package/dist/src/core/furnace-config.js +37 -1
  170. package/dist/src/core/furnace-constants.js +0 -1
  171. package/dist/src/core/furnace-css-fragments.js +0 -1
  172. package/dist/src/core/furnace-graph-utils.js +0 -1
  173. package/dist/src/core/furnace-jsconfig.d.ts +2 -3
  174. package/dist/src/core/furnace-jsconfig.js +25 -18
  175. package/dist/src/core/furnace-marker.js +0 -1
  176. package/dist/src/core/furnace-operation.js +0 -1
  177. package/dist/src/core/furnace-refresh.js +0 -1
  178. package/dist/src/core/furnace-registration-ast.d.ts +14 -0
  179. package/dist/src/core/furnace-registration-ast.js +1 -2
  180. package/dist/src/core/furnace-registration-remove.js +0 -1
  181. package/dist/src/core/furnace-registration-validate.js +1 -5
  182. package/dist/src/core/furnace-registration.js +0 -1
  183. package/dist/src/core/furnace-rollback.js +0 -1
  184. package/dist/src/core/furnace-scanner.js +0 -1
  185. package/dist/src/core/furnace-staleness.js +0 -1
  186. package/dist/src/core/furnace-state-persist.d.ts +72 -0
  187. package/dist/src/core/furnace-state-persist.js +118 -0
  188. package/dist/src/core/furnace-step-errors.d.ts +23 -0
  189. package/dist/src/core/furnace-step-errors.js +25 -0
  190. package/dist/src/core/furnace-stories.js +0 -1
  191. package/dist/src/core/furnace-validate-accessibility.js +0 -1
  192. package/dist/src/core/furnace-validate-checks.js +0 -1
  193. package/dist/src/core/furnace-validate-compatibility.js +0 -1
  194. package/dist/src/core/furnace-validate-helpers.js +0 -1
  195. package/dist/src/core/furnace-validate-registration.js +7 -7
  196. package/dist/src/core/furnace-validate-structure.d.ts +8 -0
  197. package/dist/src/core/furnace-validate-structure.js +11 -2
  198. package/dist/src/core/furnace-validate.js +0 -1
  199. package/dist/src/core/furnace-version-drift.d.ts +6 -3
  200. package/dist/src/core/furnace-version-drift.js +6 -4
  201. package/dist/src/core/git-base.js +0 -1
  202. package/dist/src/core/git-diff.js +0 -1
  203. package/dist/src/core/git-file-ops.js +0 -1
  204. package/dist/src/core/git-status.d.ts +13 -0
  205. package/dist/src/core/git-status.js +32 -2
  206. package/dist/src/core/git.d.ts +10 -1
  207. package/dist/src/core/git.js +63 -6
  208. package/dist/src/core/license-headers.js +0 -1
  209. package/dist/src/core/lint-cache.js +0 -1
  210. package/dist/src/core/lint-projection.js +0 -1
  211. package/dist/src/core/mach-build-artifacts.js +0 -1
  212. package/dist/src/core/mach-error-hints.js +0 -1
  213. package/dist/src/core/mach-mozconfig.js +0 -1
  214. package/dist/src/core/mach-python.js +0 -1
  215. package/dist/src/core/mach-resource-shim.js +0 -1
  216. package/dist/src/core/mach.js +0 -1
  217. package/dist/src/core/manifest-helpers.js +0 -1
  218. package/dist/src/core/manifest-register.js +0 -1
  219. package/dist/src/core/manifest-rules.js +0 -1
  220. package/dist/src/core/manifest-tokenizers.js +0 -1
  221. package/dist/src/core/marionette-port.d.ts +8 -0
  222. package/dist/src/core/marionette-port.js +34 -3
  223. package/dist/src/core/marionette-preflight.js +0 -1
  224. package/dist/src/core/markdown-table.js +0 -1
  225. package/dist/src/core/ownership-table.js +2 -9
  226. package/dist/src/core/parser-fallback.js +0 -1
  227. package/dist/src/core/patch-apply-fuzz.d.ts +27 -9
  228. package/dist/src/core/patch-apply-fuzz.js +71 -34
  229. package/dist/src/core/patch-apply.d.ts +30 -0
  230. package/dist/src/core/patch-apply.js +101 -18
  231. package/dist/src/core/patch-artifact-normalize.d.ts +18 -5
  232. package/dist/src/core/patch-artifact-normalize.js +19 -15
  233. package/dist/src/core/patch-export-coverage.js +0 -1
  234. package/dist/src/core/patch-export-metadata.js +0 -1
  235. package/dist/src/core/patch-export-update.js +2 -3
  236. package/dist/src/core/patch-export.d.ts +2 -6
  237. package/dist/src/core/patch-export.js +24 -48
  238. package/dist/src/core/patch-files.js +0 -1
  239. package/dist/src/core/patch-identifier-suggest.js +0 -1
  240. package/dist/src/core/patch-lint-checkjs.js +0 -1
  241. package/dist/src/core/patch-lint-chrome-jsdoc.js +0 -1
  242. package/dist/src/core/patch-lint-cross.js +0 -1
  243. package/dist/src/core/patch-lint-css.js +0 -1
  244. package/dist/src/core/patch-lint-diff-tag.js +0 -1
  245. package/dist/src/core/patch-lint-diff.d.ts +2 -1
  246. package/dist/src/core/patch-lint-diff.js +17 -32
  247. package/dist/src/core/patch-lint-imports.js +0 -1
  248. package/dist/src/core/patch-lint-jsdoc.js +0 -1
  249. package/dist/src/core/patch-lint-observer.js +0 -1
  250. package/dist/src/core/patch-lint-ownership.js +0 -1
  251. package/dist/src/core/patch-lint-reexports.js +0 -1
  252. package/dist/src/core/patch-lint.d.ts +37 -2
  253. package/dist/src/core/patch-lint.js +47 -34
  254. package/dist/src/core/patch-lock.js +0 -1
  255. package/dist/src/core/patch-manifest-consistency.js +9 -1
  256. package/dist/src/core/patch-manifest-io.d.ts +16 -0
  257. package/dist/src/core/patch-manifest-io.js +30 -5
  258. package/dist/src/core/patch-manifest-query.js +18 -10
  259. package/dist/src/core/patch-manifest-resolve.js +0 -1
  260. package/dist/src/core/patch-manifest-validate.js +0 -1
  261. package/dist/src/core/patch-manifest.d.ts +1 -1
  262. package/dist/src/core/patch-manifest.js +1 -2
  263. package/dist/src/core/patch-parse.d.ts +59 -0
  264. package/dist/src/core/patch-parse.js +209 -92
  265. package/dist/src/core/patch-policy.js +0 -1
  266. package/dist/src/core/patch-registration-refs.js +16 -26
  267. package/dist/src/core/patch-source-metadata.js +0 -1
  268. package/dist/src/core/patch-transform.d.ts +4 -0
  269. package/dist/src/core/patch-transform.js +30 -38
  270. package/dist/src/core/rebase-session.js +0 -1
  271. package/dist/src/core/register-browser-content.js +0 -1
  272. package/dist/src/core/register-module.js +0 -1
  273. package/dist/src/core/register-result.js +0 -1
  274. package/dist/src/core/register-scaffold.js +0 -1
  275. package/dist/src/core/register-shared-css.js +0 -1
  276. package/dist/src/core/register-test-manifest.js +0 -1
  277. package/dist/src/core/register-xpcshell-test.js +0 -1
  278. package/dist/src/core/shared-ftl.js +0 -1
  279. package/dist/src/core/signal-critical.js +0 -1
  280. package/dist/src/core/smoke-patterns.js +0 -1
  281. package/dist/src/core/state-file.js +0 -1
  282. package/dist/src/core/status-classify.d.ts +16 -0
  283. package/dist/src/core/status-classify.js +24 -16
  284. package/dist/src/core/test-harness-crash.d.ts +64 -7
  285. package/dist/src/core/test-harness-crash.js +196 -15
  286. package/dist/src/core/test-harness-output.js +0 -1
  287. package/dist/src/core/test-path-scope.d.ts +21 -13
  288. package/dist/src/core/test-path-scope.js +43 -28
  289. package/dist/src/core/test-stale-check.js +0 -1
  290. package/dist/src/core/test-stale-symlink.js +0 -1
  291. package/dist/src/core/test-xpcshell-retry.js +0 -1
  292. package/dist/src/core/token-coverage.js +0 -1
  293. package/dist/src/core/token-dark-mode.js +0 -1
  294. package/dist/src/core/token-docs.js +0 -1
  295. package/dist/src/core/token-manager.js +0 -1
  296. package/dist/src/core/token-scaffold.js +0 -1
  297. package/dist/src/core/token-variant.js +0 -1
  298. package/dist/src/core/toolchain-preflight.d.ts +31 -10
  299. package/dist/src/core/toolchain-preflight.js +97 -36
  300. package/dist/src/core/typecheck-shim.js +13 -1
  301. package/dist/src/core/typecheck.js +0 -1
  302. package/dist/src/core/wire-destroy.js +0 -1
  303. package/dist/src/core/wire-dom-fragment.js +0 -1
  304. package/dist/src/core/wire-init.js +0 -1
  305. package/dist/src/core/wire-subscript.js +0 -1
  306. package/dist/src/core/wire-targets.js +0 -1
  307. package/dist/src/core/wire-utils.js +0 -1
  308. package/dist/src/core/xpcshell-appdir.js +1 -4
  309. package/dist/src/errors/base.d.ts +29 -0
  310. package/dist/src/errors/base.js +35 -1
  311. package/dist/src/errors/build.js +0 -1
  312. package/dist/src/errors/codes.d.ts +6 -0
  313. package/dist/src/errors/codes.js +6 -1
  314. package/dist/src/errors/config.js +0 -1
  315. package/dist/src/errors/download.js +0 -1
  316. package/dist/src/errors/furnace.d.ts +11 -1
  317. package/dist/src/errors/furnace.js +6 -5
  318. package/dist/src/errors/git.js +0 -1
  319. package/dist/src/errors/patch.d.ts +17 -0
  320. package/dist/src/errors/patch.js +29 -1
  321. package/dist/src/errors/rebase.js +0 -1
  322. package/dist/src/errors/run.js +1 -1
  323. package/dist/src/index.js +0 -1
  324. package/dist/src/types/cli.js +0 -1
  325. package/dist/src/types/commands/index.js +0 -1
  326. package/dist/src/types/commands/options.d.ts +13 -5
  327. package/dist/src/types/commands/options.js +0 -1
  328. package/dist/src/types/commands/patches.d.ts +8 -0
  329. package/dist/src/types/commands/patches.js +0 -1
  330. package/dist/src/types/commands/project.d.ts +11 -2
  331. package/dist/src/types/commands/project.js +0 -1
  332. package/dist/src/types/config.d.ts +32 -0
  333. package/dist/src/types/config.js +0 -1
  334. package/dist/src/types/furnace.d.ts +10 -0
  335. package/dist/src/types/furnace.js +0 -1
  336. package/dist/src/types/index.js +0 -1
  337. package/dist/src/types/typecheck.js +0 -1
  338. package/dist/src/utils/elapsed.js +0 -1
  339. package/dist/src/utils/errors.js +0 -1
  340. package/dist/src/utils/fs.js +37 -5
  341. package/dist/src/utils/logger.d.ts +7 -0
  342. package/dist/src/utils/logger.js +85 -3
  343. package/dist/src/utils/options.d.ts +15 -0
  344. package/dist/src/utils/options.js +25 -1
  345. package/dist/src/utils/package-root.js +11 -4
  346. package/dist/src/utils/parse.js +0 -1
  347. package/dist/src/utils/paths.js +0 -1
  348. package/dist/src/utils/platform.js +0 -1
  349. package/dist/src/utils/process.d.ts +33 -4
  350. package/dist/src/utils/process.js +183 -28
  351. package/dist/src/utils/regex.d.ts +13 -3
  352. package/dist/src/utils/regex.js +53 -4
  353. package/dist/src/utils/validation.d.ts +0 -12
  354. package/dist/src/utils/validation.js +13 -26
  355. package/package.json +8 -7
@@ -4,14 +4,15 @@
4
4
  *
5
5
  * Orchestrates the full patch-rebase workflow:
6
6
  * 1. Reset engine to baseline
7
- * 2. Apply each patch with escalating fuzz
7
+ * 2. Apply each patch with escalating context reduction (git apply -C<n>)
8
8
  * 3. Pause on failures for manual resolution
9
9
  * 4. Re-export successfully applied patches with the new version stamp
10
10
  *
11
11
  * Supports `--continue` (resume after manual fix) and `--abort` (cancel).
12
12
  */
13
+ import { Command } from 'commander';
13
14
  import { getProjectPaths, loadConfig } from '../../core/config.js';
14
- import { getFurnacePaths, updateFurnaceState } from '../../core/furnace-config.js';
15
+ import { clearAppliedFurnaceState } from '../../core/furnace-config.js';
15
16
  import { getHead, isGitRepository, isMissingHeadError, resetChanges } from '../../core/git.js';
16
17
  import { discoverPatches } from '../../core/patch-files.js';
17
18
  import { loadPatchesManifest } from '../../core/patch-manifest.js';
@@ -21,7 +22,8 @@ import { GeneralError } from '../../errors/base.js';
21
22
  import { RebaseSessionExistsError } from '../../errors/rebase.js';
22
23
  import { pathExists } from '../../utils/fs.js';
23
24
  import { info, intro, outro, spinner } from '../../utils/logger.js';
24
- import { pickDefined } from '../../utils/options.js';
25
+ import { commanderArgParser, pickDefined } from '../../utils/options.js';
26
+ import { parsePositiveIntegerFlag } from '../../utils/validation.js';
25
27
  import { handleAbort } from './abort.js';
26
28
  import { confirmDirtyEngineReset } from './confirm.js';
27
29
  import { handleContinue } from './continue.js';
@@ -78,9 +80,9 @@ async function handleFreshStart(projectRoot, options) {
78
80
  }
79
81
  info(`Rebasing patches: ${fromVersion} → ${currentVersion}`);
80
82
  info(`Found ${manifest.patches.length} patch(es)`);
81
- info(`Max fuzz factor: ${maxFuzz}`);
83
+ info(`Max context-reduction steps (fuzz-like): ${maxFuzz}`);
82
84
  if (isDryRun) {
83
- info('[dry-run] Would reset engine, apply patches with fuzz, and re-export.');
85
+ info('[dry-run] Would reset engine, apply patches with context reduction, and re-export.');
84
86
  outro('Dry run complete');
85
87
  return;
86
88
  }
@@ -102,13 +104,7 @@ async function handleFreshStart(projectRoot, options) {
102
104
  await resetChanges(paths.engine);
103
105
  resetSpinner.stop('Engine reset to baseline');
104
106
  // Clear Furnace state — the engine no longer contains deployed components.
105
- // Preserve pendingRepair since that tracks authoring-side rollback issues.
106
- const furnacePaths = getFurnacePaths(projectRoot);
107
- if (await pathExists(furnacePaths.furnaceState)) {
108
- await updateFurnaceState(projectRoot, (current) => ({
109
- ...(current.pendingRepair ? { pendingRepair: current.pendingRepair } : {}),
110
- }));
111
- }
107
+ await clearAppliedFurnaceState(projectRoot);
112
108
  // Create rebase session
113
109
  const allPatches = await discoverPatches(paths.patches);
114
110
  const session = {
@@ -147,14 +143,13 @@ export async function rebaseCommand(projectRoot, options = {}) {
147
143
  export function registerRebase(program, { getProjectRoot, withErrorHandling }) {
148
144
  program
149
145
  .command('rebase')
150
- .description('Semi-automated Firefox source version upgrade — apply patches with fuzz and re-export')
146
+ .description('Semi-automated Firefox source version upgrade — apply patches with drift tolerance and re-export')
151
147
  .option('--continue', 'Resume after manually resolving a failed patch')
152
148
  .option('--abort', 'Cancel the rebase and restore engine to pre-rebase state')
153
149
  .option('--dry-run', 'Show what would happen without modifying anything')
154
- .option('--max-fuzz <n>', 'Maximum fuzz factor for git apply (default: 3)', parseInt)
150
+ .option('--max-fuzz <n>', 'Maximum context-reduction steps for git apply -C<n> (fuzz-like drift tolerance; default: 3)', commanderArgParser((v) => parsePositiveIntegerFlag('--max-fuzz', v)))
155
151
  .option('-y, --yes', 'Skip dirty-tree confirmation prompt')
156
152
  .action(withErrorHandling(async (options) => {
157
153
  await rebaseCommand(getProjectRoot(), pickDefined(options));
158
154
  }));
159
155
  }
160
- //# sourceMappingURL=index.js.map
@@ -76,7 +76,7 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
76
76
  success(` ${entry.filename} — applied cleanly`);
77
77
  }
78
78
  else {
79
- warn(` ${entry.filename} — applied with fuzz=${result.fuzzFactor}`);
79
+ warn(` ${entry.filename} — applied with context reduction (step ${result.fuzzFactor})`);
80
80
  }
81
81
  }
82
82
  else {
@@ -129,7 +129,7 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
129
129
  // patch was tested against if we proceeded to stamp. Refuse to claim
130
130
  // success and leave the session in place so the user can recover via
131
131
  // `fireforge rebase --continue` after fixing the underlying cause.
132
- const reExportFailures = await reExportAppliedPatches(session, paths);
132
+ const { failures: reExportFailures, overlapSkipped } = await reExportAppliedPatches(session, paths);
133
133
  if (reExportFailures.length > 0) {
134
134
  for (const f of reExportFailures) {
135
135
  error(` ${f.filename}: ${f.error}`);
@@ -138,10 +138,20 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
138
138
  `Versions were not stamped and the rebase session has been kept so you can retry. ` +
139
139
  `Fix the underlying cause shown above, then re-run "fireforge rebase --continue".`);
140
140
  }
141
- // Stamp versions
141
+ if (overlapSkipped.length > 0) {
142
+ warn(`${overlapSkipped.length} patch(es) share files with other patches and were NOT ` +
143
+ `re-exported or version-stamped: ${overlapSkipped.join(', ')}. Their .patch files ` +
144
+ `still describe the pre-rebase source. Re-export them manually (e.g. ` +
145
+ `"fireforge re-export") and verify the overlapping hunks before the next import.`);
146
+ }
147
+ // Stamp versions — only for patches whose .patch file now actually
148
+ // reflects the new source (overlap-skipped ones keep their old stamp so
149
+ // the queue does not lie about what each patch was tested against).
150
+ const overlapSkippedSet = new Set(overlapSkipped);
142
151
  const appliedFilenames = session.patches
143
152
  .filter((p) => p.status === 'applied-clean' || p.status === 'applied-fuzz' || p.status === 'resolved')
144
- .map((p) => p.filename);
153
+ .map((p) => p.filename)
154
+ .filter((filename) => !overlapSkippedSet.has(filename));
145
155
  if (appliedFilenames.length > 0) {
146
156
  await stampPatchVersions(paths.patches, appliedFilenames, session.toVersion, session.toProduct);
147
157
  }
@@ -181,9 +191,24 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
181
191
  }
182
192
  async function reExportAppliedPatches(session, paths) {
183
193
  const failures = [];
194
+ const overlapSkipped = [];
184
195
  const manifest = await loadPatchesManifest(paths.patches);
185
196
  if (!manifest)
186
- return failures;
197
+ return { failures, overlapSkipped };
198
+ // Re-export writes `getDiffForFilesAgainstHead(files)` — the CUMULATIVE
199
+ // diff of those files. For a file claimed by two patches (a supported
200
+ // `--allow-overlap` queue), that diff contains BOTH patches' hunks, so
201
+ // rewriting each patch with it would duplicate the shared file's hunks
202
+ // into every owner: the very next import then fails or silently
203
+ // double-materialises. Refuse to auto-re-export any patch whose files
204
+ // overlap another patch; the operator re-exports those manually where
205
+ // per-patch attribution is possible.
206
+ const fileOwners = new Map();
207
+ for (const patch of manifest.patches) {
208
+ for (const file of patch.filesAffected) {
209
+ fileOwners.set(file, (fileOwners.get(file) ?? 0) + 1);
210
+ }
211
+ }
187
212
  const s = spinner('Re-exporting patches...');
188
213
  const reExportable = session.patches.filter((entry) => entry.status === 'applied-clean' || entry.status === 'applied-fuzz');
189
214
  const startedAt = Date.now();
@@ -191,6 +216,13 @@ async function reExportAppliedPatches(session, paths) {
191
216
  const meta = manifest.patches.find((p) => p.filename === entry.filename);
192
217
  if (!meta)
193
218
  continue;
219
+ const sharedFiles = meta.filesAffected.filter((f) => (fileOwners.get(f) ?? 0) > 1);
220
+ if (sharedFiles.length > 0) {
221
+ overlapSkipped.push(entry.filename);
222
+ warn(`Skipping re-export of ${entry.filename}: file(s) shared with other patches ` +
223
+ `(${sharedFiles.join(', ')}). Re-export it manually once the overlap is resolved.`);
224
+ continue;
225
+ }
194
226
  const existingFiles = [];
195
227
  for (const f of meta.filesAffected) {
196
228
  if (await pathExists(join(paths.engine, f))) {
@@ -224,6 +256,5 @@ async function reExportAppliedPatches(session, paths) {
224
256
  else {
225
257
  s.stop('Patches re-exported');
226
258
  }
227
- return failures;
259
+ return { failures, overlapSkipped };
228
260
  }
229
- //# sourceMappingURL=patch-loop.js.map
@@ -11,7 +11,7 @@ function statusLabel(status, fuzzFactor) {
11
11
  case 'applied-clean':
12
12
  return 'applied cleanly';
13
13
  case 'applied-fuzz':
14
- return `applied with fuzz=${fuzzFactor ?? '?'}`;
14
+ return `applied with context reduction (step ${fuzzFactor ?? '?'})`;
15
15
  case 'resolved':
16
16
  return 'RESOLVED manually';
17
17
  case 'failed':
@@ -43,6 +43,5 @@ export function printSummary(session) {
43
43
  const failed = session.patches.filter((p) => p.status === 'failed').length;
44
44
  const total = session.patches.length;
45
45
  info('');
46
- info(`Results: ${total} total: ${clean} clean, ${fuzz} fuzz-applied, ${resolved} manually resolved, ${failed} failed`);
46
+ info(`Results: ${total} total: ${clean} clean, ${fuzz} context-reduced, ${resolved} manually resolved, ${failed} failed`);
47
47
  }
48
- //# sourceMappingURL=summary.js.map
@@ -3,4 +3,3 @@
3
3
  * `fireforge rebase` — re-exports from `./rebase/` sub-modules.
4
4
  */
5
5
  export { rebaseCommand, registerRebase } from './rebase/index.js';
6
- //# sourceMappingURL=rebase.js.map
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { join } from 'node:path';
3
+ import { Command } from 'commander';
3
4
  import { getProjectPaths } from '../core/config.js';
4
5
  import { registerFile } from '../core/manifest-rules.js';
5
6
  import { InvalidArgumentError } from '../errors/base.js';
@@ -104,4 +105,3 @@ export function registerRegister(program, { getProjectRoot, withErrorHandling })
104
105
  await registerCommand(getProjectRoot(), path, pickDefined(options));
105
106
  }));
106
107
  }
107
- //# sourceMappingURL=register.js.map
@@ -1,8 +1,9 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { confirm } from '@clack/prompts';
3
+ import { Command } from 'commander';
3
4
  import { getProjectPaths } from '../core/config.js';
4
- import { getFurnacePaths, updateFurnaceState } from '../core/furnace-config.js';
5
- import { hasChanges, isGitRepository, resetChanges } from '../core/git.js';
5
+ import { clearAppliedFurnaceState } from '../core/furnace-config.js';
6
+ import { getHead, hasChanges, isGitRepository, isMissingHeadError, resetChanges, } from '../core/git.js';
6
7
  import { expandUntrackedDirectoryEntries, getWorkingTreeStatus } from '../core/git-status.js';
7
8
  import { GeneralError, InvalidArgumentError } from '../errors/base.js';
8
9
  import { pathExists } from '../utils/fs.js';
@@ -24,6 +25,18 @@ export async function resetCommand(projectRoot, options) {
24
25
  if (!(await isGitRepository(paths.engine))) {
25
26
  throw new GeneralError('Engine directory is not a git repository. Run "fireforge download" to initialize.');
26
27
  }
28
+ // Unborn-HEAD guard (mirrors status): an interrupted download leaves a
29
+ // repo with no baseline commit, where the entire ~300k-file tree reads
30
+ // as untracked — a reset against that state is never what the operator
31
+ // wants, and the guidance names the actual fix.
32
+ try {
33
+ await getHead(paths.engine);
34
+ }
35
+ catch (headError) {
36
+ if (!isMissingHeadError(headError))
37
+ throw headError;
38
+ throw new GeneralError('Engine repository has no baseline commit yet — a previous "fireforge download" was interrupted before git created the initial Firefox source commit. Re-run "fireforge download --force" to recreate the baseline repository cleanly.');
39
+ }
27
40
  // Check for changes
28
41
  const hasUncommittedChanges = await hasChanges(paths.engine);
29
42
  if (!hasUncommittedChanges) {
@@ -71,12 +84,7 @@ export async function resetCommand(projectRoot, options) {
71
84
  // consistent regardless of the drift oracle.) Preserve pendingRepair:
72
85
  // authoring-side rollback markers are about the workspace/component
73
86
  // tree, not the engine checkout, so reset must not silently forget them.
74
- const furnacePaths = getFurnacePaths(projectRoot);
75
- if (await pathExists(furnacePaths.furnaceState)) {
76
- await updateFurnaceState(projectRoot, (current) => ({
77
- ...(current.pendingRepair ? { pendingRepair: current.pendingRepair } : {}),
78
- }));
79
- }
87
+ await clearAppliedFurnaceState(projectRoot);
80
88
  s.stop('Changes reset');
81
89
  outro('Working tree restored to clean state');
82
90
  }
@@ -96,4 +104,3 @@ export function registerReset(program, { getProjectRoot, withErrorHandling }) {
96
104
  await resetCommand(getProjectRoot(), pickDefined(options));
97
105
  }));
98
106
  }
99
- //# sourceMappingURL=reset.js.map
@@ -1,6 +1,7 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { join } from 'node:path';
3
3
  import { confirm } from '@clack/prompts';
4
+ import { Command } from 'commander';
4
5
  import { getProjectPaths, loadConfig, loadState, updateState } from '../core/config.js';
5
6
  import { isGitRepository } from '../core/git.js';
6
7
  import { getStagedDiffForFiles } from '../core/git-diff.js';
@@ -43,7 +44,7 @@ export async function resolveCommand(projectRoot, options = {}) {
43
44
  // pipe / CI shell could otherwise commit whatever the engine
44
45
  // currently contains. 2026-04-21 eval (Finding #18): a scripted
45
46
  // recovery flow was dead-ended by the unconditional TTY refusal.
46
- if (!process.stdin.isTTY && !options.yes) {
47
+ if (!(process.stdin.isTTY && process.stdout.isTTY) && !options.yes) {
47
48
  throw new GeneralError('Cannot run "fireforge resolve" in non-interactive mode. Use a terminal with TTY support, or pass "--yes" to skip the interactive confirmation once the manual merge is complete.');
48
49
  }
49
50
  if (!options.yes) {
@@ -167,4 +168,3 @@ export function registerResolve(program, { getProjectRoot, withErrorHandling })
167
168
  await resolveCommand(getProjectRoot(), options);
168
169
  }));
169
170
  }
170
- //# sourceMappingURL=resolve.js.map
@@ -2,6 +2,7 @@
2
2
  import { createWriteStream } from 'node:fs';
3
3
  import { readdir, readFile } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
+ import { Command } from 'commander';
5
6
  import { getProjectPaths, loadConfig } from '../core/config.js';
6
7
  import { warnIfFurnaceStale } from '../core/furnace-staleness.js';
7
8
  import { buildArtifactMismatchMessage, hasBuildArtifacts, hasRunnableBundle, run, runMachSmoke, } from '../core/mach.js';
@@ -13,7 +14,7 @@ import { SmokeRunError } from '../errors/run.js';
13
14
  import { toError } from '../utils/errors.js';
14
15
  import { pathExists, removeDir, removeFile } from '../utils/fs.js';
15
16
  import { info, intro, verbose, warn } from '../utils/logger.js';
16
- import { pickDefined } from '../utils/options.js';
17
+ import { commanderArgParser, pickDefined } from '../utils/options.js';
17
18
  /**
18
19
  * Exit code returned by smoke-run mode when the captured console stream
19
20
  * produced one or more error lines that did NOT match the operator's
@@ -330,13 +331,13 @@ export function registerRun(program, { getProjectRoot, withErrorHandling }) {
330
331
  program
331
332
  .command('run')
332
333
  .description('Launch the built browser')
333
- .option('--smoke-exit <seconds>', 'Smoke-run mode (POSIX only): launch, capture console, SIGTERM the process group after <seconds>. Exit 0 on a clean window, 12 on unallowed errors, 13 on launch failure.', (value) => {
334
+ .option('--smoke-exit <seconds>', 'Smoke-run mode (POSIX only): launch, capture console, SIGTERM the process group after <seconds>. Exit 0 on a clean window, 12 on unallowed errors, 13 on launch failure.', commanderArgParser((value) => {
334
335
  const parsed = Number.parseInt(value, 10);
335
336
  if (!Number.isFinite(parsed) || parsed < 1 || String(parsed) !== value.trim()) {
336
337
  throw new Error(`--smoke-exit expects a positive integer number of seconds (got "${value}").`);
337
338
  }
338
339
  return parsed;
339
- })
340
+ }))
340
341
  .option('--console-allow <regex>', 'Allowlist regex (repeatable). Lines that match any entry do not count toward the smoke exit code.', (value, acc) => {
341
342
  acc.push(value);
342
343
  return acc;
@@ -348,4 +349,3 @@ export function registerRun(program, { getProjectRoot, withErrorHandling }) {
348
349
  await runCommand(getProjectRoot(), pickDefined(options));
349
350
  }));
350
351
  }
351
- //# sourceMappingURL=run.js.map
@@ -388,4 +388,3 @@ export async function writeSetupProjectFiles(projectRoot, config) {
388
388
  await writeText(destPath, content);
389
389
  }
390
390
  }
391
- //# sourceMappingURL=setup-support.js.map
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { resolve } from 'node:path';
3
3
  import { confirm } from '@clack/prompts';
4
- import { Option } from 'commander';
4
+ import { Command, Option } from 'commander';
5
5
  import { configExists } from '../core/config.js';
6
6
  import { ConfigError } from '../errors/config.js';
7
7
  import { cancel, intro, isCancel, note, outro, spinner } from '../utils/logger.js';
@@ -93,4 +93,3 @@ export function registerSetup(program, { withErrorHandling }) {
93
93
  await setupCommand(resolve(process.cwd()), setupOptions);
94
94
  }));
95
95
  }
96
- //# sourceMappingURL=setup.js.map
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { Option } from 'commander';
2
+ import { Command, Option } from 'commander';
3
3
  import { configExists, loadRawConfigDocument, validateConfig, withConfigFileLock, writeConfigDocument, } from '../core/config.js';
4
4
  import { resolveArchive } from '../core/firefox-archive.js';
5
5
  import { GeneralError, InvalidArgumentError } from '../errors/base.js';
@@ -92,4 +92,3 @@ export function registerSource(program, { getProjectRoot, withErrorHandling }) {
92
92
  });
93
93
  }));
94
94
  }
95
- //# sourceMappingURL=source.js.map
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { isFileRegistered, matchesRegistrablePattern } from '../core/manifest-rules.js';
3
+ import { getPrimaryStatusCode } from '../core/status-classify.js';
3
4
  import { GeneralError } from '../errors/base.js';
4
5
  import { info, outro, warn } from '../utils/logger.js';
5
6
  const STATUS_DESCRIPTIONS = {
@@ -15,17 +16,6 @@ const STATUS_DESCRIPTIONS = {
15
16
  function getStatusDescription(code) {
16
17
  return STATUS_DESCRIPTIONS[code] ?? 'changed';
17
18
  }
18
- function getPrimaryStatusCode(status) {
19
- if (status.includes('?'))
20
- return '?';
21
- if (status.includes('!'))
22
- return '!';
23
- for (const code of status) {
24
- if (code !== ' ')
25
- return code;
26
- }
27
- return status;
28
- }
29
19
  function isNewFileStatus(status) {
30
20
  const code = getPrimaryStatusCode(status);
31
21
  return code === '?' || code === 'A';
@@ -192,4 +182,3 @@ export async function renderDefaultStatus(totalModified, buckets, projectRoot, b
192
182
  .map((section) => `${section.files.length} ${section.label}`);
193
183
  outro(parts.join(', '));
194
184
  }
195
- //# sourceMappingURL=status-output.js.map