@hominis/fireforge 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (470) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +10 -1
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +4 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  22. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  23. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  24. package/dist/src/commands/doctor-working-tree.js +11 -18
  25. package/dist/src/commands/doctor.js +35 -53
  26. package/dist/src/commands/download.js +32 -48
  27. package/dist/src/commands/export-all.js +29 -33
  28. package/dist/src/commands/export-flow.js +6 -6
  29. package/dist/src/commands/export-placement-conflicts.js +10 -9
  30. package/dist/src/commands/export-placement-gate.js +5 -5
  31. package/dist/src/commands/export-shared.d.ts +30 -33
  32. package/dist/src/commands/export-shared.js +45 -43
  33. package/dist/src/commands/export.js +21 -27
  34. package/dist/src/commands/furnace/apply.js +14 -23
  35. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  36. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  37. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  38. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  39. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  40. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  41. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  42. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  43. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  44. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  45. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  46. package/dist/src/commands/furnace/create-readback.js +12 -13
  47. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  48. package/dist/src/commands/furnace/create-templates.js +35 -30
  49. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  50. package/dist/src/commands/furnace/create.js +33 -23
  51. package/dist/src/commands/furnace/deploy.js +16 -24
  52. package/dist/src/commands/furnace/diff.js +9 -9
  53. package/dist/src/commands/furnace/init.js +33 -36
  54. package/dist/src/commands/furnace/override.js +23 -25
  55. package/dist/src/commands/furnace/preview.js +47 -67
  56. package/dist/src/commands/furnace/refresh.js +12 -16
  57. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  58. package/dist/src/commands/furnace/remove-mutations.js +9 -16
  59. package/dist/src/commands/furnace/remove-state.js +1 -1
  60. package/dist/src/commands/furnace/remove.js +33 -38
  61. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  62. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  63. package/dist/src/commands/furnace/rename.js +59 -69
  64. package/dist/src/commands/furnace/scan.js +19 -33
  65. package/dist/src/commands/furnace/status.js +12 -9
  66. package/dist/src/commands/furnace/sync.js +9 -16
  67. package/dist/src/commands/furnace/validate.js +20 -20
  68. package/dist/src/commands/import.js +42 -35
  69. package/dist/src/commands/lint-per-patch.js +15 -10
  70. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  71. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  72. package/dist/src/commands/lint-report.js +6 -7
  73. package/dist/src/commands/lint.d.ts +15 -16
  74. package/dist/src/commands/lint.js +86 -102
  75. package/dist/src/commands/package.js +6 -11
  76. package/dist/src/commands/patch/compact.js +1 -1
  77. package/dist/src/commands/patch/delete.js +24 -33
  78. package/dist/src/commands/patch/index.d.ts +5 -6
  79. package/dist/src/commands/patch/index.js +10 -12
  80. package/dist/src/commands/patch/lint-ignore.js +14 -13
  81. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  82. package/dist/src/commands/patch/move-files-create.js +8 -8
  83. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  84. package/dist/src/commands/patch/move-files-into.js +8 -8
  85. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  86. package/dist/src/commands/patch/patch-context.js +2 -3
  87. package/dist/src/commands/patch/rename.d.ts +10 -11
  88. package/dist/src/commands/patch/rename.js +11 -12
  89. package/dist/src/commands/patch/reorder.js +8 -9
  90. package/dist/src/commands/patch/split-plan.js +1 -1
  91. package/dist/src/commands/patch/split.d.ts +8 -10
  92. package/dist/src/commands/patch/split.js +9 -11
  93. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  94. package/dist/src/commands/patch/staged-dependency.js +7 -3
  95. package/dist/src/commands/patch/tier.d.ts +9 -9
  96. package/dist/src/commands/patch/tier.js +18 -15
  97. package/dist/src/commands/re-export-adjacent.js +9 -8
  98. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  99. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  100. package/dist/src/commands/re-export-drift.js +10 -10
  101. package/dist/src/commands/re-export-files.d.ts +6 -7
  102. package/dist/src/commands/re-export-files.js +34 -44
  103. package/dist/src/commands/re-export-lint.d.ts +10 -13
  104. package/dist/src/commands/re-export-lint.js +16 -14
  105. package/dist/src/commands/re-export-options.d.ts +6 -6
  106. package/dist/src/commands/re-export-options.js +6 -6
  107. package/dist/src/commands/re-export-register.d.ts +4 -10
  108. package/dist/src/commands/re-export-register.js +5 -11
  109. package/dist/src/commands/re-export-scan.js +1 -1
  110. package/dist/src/commands/re-export-single.d.ts +3 -3
  111. package/dist/src/commands/re-export-single.js +33 -25
  112. package/dist/src/commands/re-export.js +13 -21
  113. package/dist/src/commands/rebase/abort.js +3 -3
  114. package/dist/src/commands/rebase/confirm.js +2 -1
  115. package/dist/src/commands/rebase/continue.d.ts +1 -1
  116. package/dist/src/commands/rebase/continue.js +14 -9
  117. package/dist/src/commands/rebase/index.js +11 -11
  118. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  119. package/dist/src/commands/rebase/patch-loop.js +60 -39
  120. package/dist/src/commands/rebase/summary.js +1 -1
  121. package/dist/src/commands/register.js +5 -7
  122. package/dist/src/commands/reset.js +2 -1
  123. package/dist/src/commands/resolve.d.ts +16 -13
  124. package/dist/src/commands/resolve.js +30 -33
  125. package/dist/src/commands/run.js +33 -35
  126. package/dist/src/commands/setup-support.js +15 -19
  127. package/dist/src/commands/setup.js +13 -9
  128. package/dist/src/commands/status-check.d.ts +6 -6
  129. package/dist/src/commands/status-json.d.ts +6 -6
  130. package/dist/src/commands/status-json.js +5 -0
  131. package/dist/src/commands/status-output.d.ts +5 -5
  132. package/dist/src/commands/status-output.js +6 -6
  133. package/dist/src/commands/status-ownership.d.ts +16 -14
  134. package/dist/src/commands/status-ownership.js +16 -14
  135. package/dist/src/commands/status.js +42 -34
  136. package/dist/src/commands/test-build-phase.js +26 -13
  137. package/dist/src/commands/test-diagnose.js +44 -44
  138. package/dist/src/commands/test-register.js +1 -0
  139. package/dist/src/commands/test-run.d.ts +14 -16
  140. package/dist/src/commands/test-run.js +21 -13
  141. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  142. package/dist/src/commands/test-stale-gate.js +15 -16
  143. package/dist/src/commands/test-verdict.d.ts +20 -3
  144. package/dist/src/commands/test-verdict.js +30 -0
  145. package/dist/src/commands/test.js +83 -76
  146. package/dist/src/commands/token-coverage.js +3 -4
  147. package/dist/src/commands/token.js +16 -18
  148. package/dist/src/commands/tree.js +47 -31
  149. package/dist/src/commands/typecheck.d.ts +10 -12
  150. package/dist/src/commands/typecheck.js +24 -27
  151. package/dist/src/commands/verify.js +13 -15
  152. package/dist/src/commands/watch.js +21 -23
  153. package/dist/src/commands/wire.js +52 -62
  154. package/dist/src/core/ast-utils.d.ts +8 -7
  155. package/dist/src/core/ast-utils.js +8 -7
  156. package/dist/src/core/branding.d.ts +9 -14
  157. package/dist/src/core/branding.js +7 -11
  158. package/dist/src/core/browser-wire.d.ts +1 -1
  159. package/dist/src/core/browser-wire.js +14 -19
  160. package/dist/src/core/build-audit-platform.js +25 -33
  161. package/dist/src/core/build-audit-registration.js +17 -25
  162. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  163. package/dist/src/core/build-audit-resolve.js +27 -33
  164. package/dist/src/core/build-audit-transforms.js +18 -19
  165. package/dist/src/core/build-audit.js +28 -42
  166. package/dist/src/core/build-baseline-types.d.ts +29 -35
  167. package/dist/src/core/build-baseline.d.ts +5 -4
  168. package/dist/src/core/build-baseline.js +14 -14
  169. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  170. package/dist/src/core/build-overwrite-guard.js +62 -19
  171. package/dist/src/core/build-prepare.d.ts +2 -2
  172. package/dist/src/core/build-prepare.js +8 -9
  173. package/dist/src/core/config-state.js +12 -4
  174. package/dist/src/core/config-validate.js +8 -5
  175. package/dist/src/core/config.d.ts +5 -8
  176. package/dist/src/core/config.js +7 -16
  177. package/dist/src/core/coverage-extend.d.ts +15 -13
  178. package/dist/src/core/coverage-extend.js +15 -13
  179. package/dist/src/core/destructive.d.ts +31 -9
  180. package/dist/src/core/destructive.js +29 -26
  181. package/dist/src/core/diff-hunks.js +10 -12
  182. package/dist/src/core/discard-baseline.d.ts +8 -8
  183. package/dist/src/core/discard-baseline.js +16 -15
  184. package/dist/src/core/display-state.d.ts +12 -14
  185. package/dist/src/core/display-state.js +12 -14
  186. package/dist/src/core/engine-changes.d.ts +2 -4
  187. package/dist/src/core/engine-changes.js +2 -4
  188. package/dist/src/core/engine-precondition.d.ts +28 -13
  189. package/dist/src/core/engine-precondition.js +25 -10
  190. package/dist/src/core/engine-session-lock.d.ts +47 -21
  191. package/dist/src/core/engine-session-lock.js +168 -33
  192. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  193. package/dist/src/core/export-moved-code-shape.js +10 -10
  194. package/dist/src/core/file-lock.d.ts +62 -5
  195. package/dist/src/core/file-lock.js +196 -59
  196. package/dist/src/core/firefox-cache.js +1 -3
  197. package/dist/src/core/firefox-extract.js +10 -14
  198. package/dist/src/core/firefox.d.ts +7 -5
  199. package/dist/src/core/firefox.js +4 -5
  200. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  201. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  202. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  203. package/dist/src/core/furnace-apply-ftl.js +12 -12
  204. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  205. package/dist/src/core/furnace-apply-helpers.js +19 -16
  206. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  207. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  208. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  209. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  210. package/dist/src/core/furnace-apply.d.ts +5 -8
  211. package/dist/src/core/furnace-apply.js +19 -24
  212. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  213. package/dist/src/core/furnace-checksum-utils.js +16 -0
  214. package/dist/src/core/furnace-config.d.ts +21 -30
  215. package/dist/src/core/furnace-config.js +32 -54
  216. package/dist/src/core/furnace-constants.d.ts +8 -0
  217. package/dist/src/core/furnace-constants.js +10 -2
  218. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  219. package/dist/src/core/furnace-css-fragments.js +5 -5
  220. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  221. package/dist/src/core/furnace-jsconfig.js +11 -12
  222. package/dist/src/core/furnace-marker.d.ts +7 -8
  223. package/dist/src/core/furnace-marker.js +7 -8
  224. package/dist/src/core/furnace-operation.d.ts +31 -0
  225. package/dist/src/core/furnace-operation.js +54 -17
  226. package/dist/src/core/furnace-precondition.d.ts +61 -0
  227. package/dist/src/core/furnace-precondition.js +67 -0
  228. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  229. package/dist/src/core/furnace-registration-remove.js +6 -7
  230. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  231. package/dist/src/core/furnace-registration-validate.js +20 -1
  232. package/dist/src/core/furnace-registration.d.ts +5 -6
  233. package/dist/src/core/furnace-registration.js +10 -12
  234. package/dist/src/core/furnace-rollback.js +7 -7
  235. package/dist/src/core/furnace-scanner.d.ts +1 -0
  236. package/dist/src/core/furnace-scanner.js +1 -2
  237. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  238. package/dist/src/core/furnace-stale-export.js +10 -10
  239. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  240. package/dist/src/core/furnace-state-persist.js +6 -8
  241. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  242. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  243. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  244. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  245. package/dist/src/core/furnace-validate-helpers.js +0 -491
  246. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  247. package/dist/src/core/furnace-validate-registration.js +115 -41
  248. package/dist/src/core/furnace-validate.d.ts +16 -0
  249. package/dist/src/core/furnace-validate.js +188 -145
  250. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  251. package/dist/src/core/furnace-version-drift.js +10 -11
  252. package/dist/src/core/git-base.d.ts +7 -9
  253. package/dist/src/core/git-base.js +7 -9
  254. package/dist/src/core/git-diff.d.ts +20 -9
  255. package/dist/src/core/git-diff.js +148 -63
  256. package/dist/src/core/git-file-ops.d.ts +19 -19
  257. package/dist/src/core/git-file-ops.js +19 -19
  258. package/dist/src/core/git-readonly-index.d.ts +53 -19
  259. package/dist/src/core/git-readonly-index.js +75 -31
  260. package/dist/src/core/git-status.d.ts +5 -6
  261. package/dist/src/core/git-status.js +5 -6
  262. package/dist/src/core/git.d.ts +9 -10
  263. package/dist/src/core/git.js +54 -70
  264. package/dist/src/core/license-headers.d.ts +17 -23
  265. package/dist/src/core/license-headers.js +17 -23
  266. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  267. package/dist/src/core/mach-build-artifacts.js +57 -19
  268. package/dist/src/core/mach-error-hints.js +42 -29
  269. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  270. package/dist/src/core/mach-known-noise-filter.js +18 -20
  271. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  272. package/dist/src/core/mach-mozconfig.js +30 -0
  273. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  274. package/dist/src/core/mach-resource-shim.js +50 -67
  275. package/dist/src/core/mach.d.ts +37 -41
  276. package/dist/src/core/mach.js +50 -51
  277. package/dist/src/core/marionette-port.d.ts +36 -1
  278. package/dist/src/core/marionette-port.js +96 -31
  279. package/dist/src/core/marionette-preflight.d.ts +8 -12
  280. package/dist/src/core/marionette-preflight.js +86 -52
  281. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  282. package/dist/src/core/mochitest-server-port.js +119 -0
  283. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  284. package/dist/src/core/module-resolution-preflight.js +9 -11
  285. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  286. package/dist/src/core/moz-manifest-helpers.js +163 -0
  287. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  288. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  289. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  290. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  291. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  292. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  293. package/dist/src/core/ownership-table.d.ts +14 -16
  294. package/dist/src/core/ownership-table.js +14 -16
  295. package/dist/src/core/parser-fallback.d.ts +15 -1
  296. package/dist/src/core/parser-fallback.js +22 -3
  297. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  298. package/dist/src/core/patch-apply-fuzz.js +15 -18
  299. package/dist/src/core/patch-apply.d.ts +13 -34
  300. package/dist/src/core/patch-apply.js +16 -76
  301. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  302. package/dist/src/core/patch-artifact-normalize.js +13 -15
  303. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  304. package/dist/src/core/patch-export-metadata.js +13 -4
  305. package/dist/src/core/patch-export-update.d.ts +13 -1
  306. package/dist/src/core/patch-export-update.js +25 -8
  307. package/dist/src/core/patch-export.d.ts +15 -8
  308. package/dist/src/core/patch-export.js +10 -11
  309. package/dist/src/core/patch-files.d.ts +5 -6
  310. package/dist/src/core/patch-files.js +5 -6
  311. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  312. package/dist/src/core/patch-identifier-suggest.js +14 -19
  313. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  314. package/dist/src/core/patch-lint-binary.js +39 -0
  315. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  316. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  317. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  318. package/dist/src/core/patch-lint-checkjs.js +16 -16
  319. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  320. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  321. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  322. package/dist/src/core/patch-lint-creators.js +8 -8
  323. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  324. package/dist/src/core/patch-lint-cross.js +16 -16
  325. package/dist/src/core/patch-lint-css.d.ts +3 -5
  326. package/dist/src/core/patch-lint-css.js +17 -22
  327. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  328. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  329. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  330. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  331. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  332. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  333. package/dist/src/core/patch-lint-observer.js +7 -7
  334. package/dist/src/core/patch-lint.d.ts +38 -29
  335. package/dist/src/core/patch-lint.js +89 -121
  336. package/dist/src/core/patch-lock.d.ts +1 -1
  337. package/dist/src/core/patch-lock.js +45 -9
  338. package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
  339. package/dist/src/core/patch-manifest-consistency.js +25 -27
  340. package/dist/src/core/patch-manifest-io.js +14 -18
  341. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  342. package/dist/src/core/patch-manifest-resolve.js +9 -12
  343. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  344. package/dist/src/core/patch-manifest-validate.js +25 -13
  345. package/dist/src/core/patch-parse.d.ts +24 -13
  346. package/dist/src/core/patch-parse.js +19 -14
  347. package/dist/src/core/patch-policy.d.ts +2 -2
  348. package/dist/src/core/patch-policy.js +2 -2
  349. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  350. package/dist/src/core/patch-registration-refs.js +9 -9
  351. package/dist/src/core/process-cpu-time.d.ts +12 -0
  352. package/dist/src/core/process-cpu-time.js +52 -0
  353. package/dist/src/core/rebase-session.d.ts +38 -26
  354. package/dist/src/core/rebase-session.js +55 -28
  355. package/dist/src/core/register-browser-content.js +9 -74
  356. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  357. package/dist/src/core/register-module.js +10 -43
  358. package/dist/src/core/register-scaffold.d.ts +8 -8
  359. package/dist/src/core/register-scaffold.js +10 -10
  360. package/dist/src/core/register-shared-css.d.ts +9 -12
  361. package/dist/src/core/register-shared-css.js +17 -87
  362. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  363. package/dist/src/core/register-xpcshell-test.js +7 -8
  364. package/dist/src/core/shared-ftl.js +12 -4
  365. package/dist/src/core/state-file.d.ts +45 -0
  366. package/dist/src/core/state-file.js +34 -0
  367. package/dist/src/core/status-binary.d.ts +18 -11
  368. package/dist/src/core/status-binary.js +19 -12
  369. package/dist/src/core/status-classify.d.ts +30 -36
  370. package/dist/src/core/status-classify.js +21 -26
  371. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  372. package/dist/src/core/test-changed-prefs.js +78 -0
  373. package/dist/src/core/test-harness-crash.d.ts +25 -63
  374. package/dist/src/core/test-harness-crash.js +121 -142
  375. package/dist/src/core/test-harness-signature.d.ts +18 -0
  376. package/dist/src/core/test-harness-signature.js +13 -0
  377. package/dist/src/core/test-path-scope.d.ts +12 -15
  378. package/dist/src/core/test-path-scope.js +15 -18
  379. package/dist/src/core/test-stale-check.d.ts +17 -17
  380. package/dist/src/core/test-stale-check.js +50 -43
  381. package/dist/src/core/test-stall-triage.d.ts +51 -0
  382. package/dist/src/core/test-stall-triage.js +126 -0
  383. package/dist/src/core/token-category.js +5 -7
  384. package/dist/src/core/token-coverage.js +9 -9
  385. package/dist/src/core/token-dark-mode.d.ts +9 -11
  386. package/dist/src/core/token-dark-mode.js +9 -11
  387. package/dist/src/core/token-docs.d.ts +2 -0
  388. package/dist/src/core/token-docs.js +2 -0
  389. package/dist/src/core/token-manager.d.ts +10 -2
  390. package/dist/src/core/token-manager.js +17 -8
  391. package/dist/src/core/token-scaffold.d.ts +7 -7
  392. package/dist/src/core/token-scaffold.js +7 -7
  393. package/dist/src/core/token-variant.d.ts +4 -4
  394. package/dist/src/core/token-variant.js +4 -4
  395. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  396. package/dist/src/core/toolchain-preflight.js +28 -31
  397. package/dist/src/core/tree-guard.js +12 -2
  398. package/dist/src/core/tree-store.d.ts +41 -27
  399. package/dist/src/core/tree-store.js +63 -42
  400. package/dist/src/core/typecheck-shim.d.ts +23 -24
  401. package/dist/src/core/typecheck-shim.js +23 -24
  402. package/dist/src/core/typecheck.js +8 -8
  403. package/dist/src/core/wire-destroy.d.ts +3 -3
  404. package/dist/src/core/wire-destroy.js +7 -15
  405. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  406. package/dist/src/core/wire-dom-fragment.js +11 -44
  407. package/dist/src/core/wire-init.d.ts +2 -3
  408. package/dist/src/core/wire-init.js +8 -19
  409. package/dist/src/core/wire-subscript.d.ts +2 -3
  410. package/dist/src/core/wire-subscript.js +4 -13
  411. package/dist/src/core/wire-utils.d.ts +7 -8
  412. package/dist/src/core/wire-utils.js +7 -8
  413. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  414. package/dist/src/core/xpcshell-appdir.js +38 -45
  415. package/dist/src/errors/base.d.ts +37 -16
  416. package/dist/src/errors/base.js +37 -16
  417. package/dist/src/errors/build.d.ts +13 -1
  418. package/dist/src/errors/build.js +14 -2
  419. package/dist/src/errors/codes.d.ts +16 -0
  420. package/dist/src/errors/codes.js +16 -0
  421. package/dist/src/errors/furnace.d.ts +4 -4
  422. package/dist/src/errors/git.d.ts +6 -10
  423. package/dist/src/errors/git.js +6 -10
  424. package/dist/src/errors/patch.d.ts +7 -7
  425. package/dist/src/errors/patch.js +7 -7
  426. package/dist/src/errors/rebase.d.ts +4 -4
  427. package/dist/src/errors/rebase.js +4 -4
  428. package/dist/src/index.d.ts +7 -1
  429. package/dist/src/index.js +5 -0
  430. package/dist/src/types/commands/index.d.ts +2 -2
  431. package/dist/src/types/commands/options.d.ts +88 -70
  432. package/dist/src/types/commands/patches.d.ts +24 -34
  433. package/dist/src/types/commands/project.d.ts +5 -34
  434. package/dist/src/types/config.d.ts +25 -23
  435. package/dist/src/types/config.js +6 -1
  436. package/dist/src/types/furnace.d.ts +37 -13
  437. package/dist/src/types/furnace.js +19 -1
  438. package/dist/src/types/index.d.ts +3 -3
  439. package/dist/src/utils/build-info.d.ts +7 -8
  440. package/dist/src/utils/build-info.js +12 -11
  441. package/dist/src/utils/errors.d.ts +6 -8
  442. package/dist/src/utils/errors.js +6 -8
  443. package/dist/src/utils/logger.d.ts +27 -10
  444. package/dist/src/utils/logger.js +28 -16
  445. package/dist/src/utils/machine-output.d.ts +12 -0
  446. package/dist/src/utils/machine-output.js +33 -0
  447. package/dist/src/utils/options.d.ts +31 -14
  448. package/dist/src/utils/options.js +86 -30
  449. package/dist/src/utils/paths.d.ts +10 -8
  450. package/dist/src/utils/paths.js +10 -8
  451. package/dist/src/utils/platform.d.ts +0 -25
  452. package/dist/src/utils/platform.js +1 -42
  453. package/dist/src/utils/process-group.d.ts +9 -4
  454. package/dist/src/utils/process-group.js +19 -5
  455. package/dist/src/utils/process.d.ts +42 -7
  456. package/dist/src/utils/process.js +44 -17
  457. package/dist/src/utils/ps-duration.d.ts +31 -0
  458. package/dist/src/utils/ps-duration.js +70 -0
  459. package/dist/src/utils/regex.d.ts +9 -10
  460. package/dist/src/utils/regex.js +9 -10
  461. package/dist/src/utils/validation.d.ts +58 -28
  462. package/dist/src/utils/validation.js +60 -33
  463. package/package.json +2 -2
  464. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  465. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  466. package/dist/src/core/manifest-helpers.d.ts +0 -38
  467. package/dist/src/core/manifest-helpers.js +0 -120
  468. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  469. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  470. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -3,21 +3,19 @@
3
3
  *
4
4
  * Currently the identity function, kept as a narrow chokepoint for future
5
5
  * artifact-level fixes so every export path (`commitExportedPatch`,
6
- * `commitPlacementExport`, `updatePatch`, `patch split`) funnels through
7
- * one place.
6
+ * `commitPlacementExport`, `updatePatch`, `patch split`) funnels through one
7
+ * place.
8
8
  *
9
- * History: this used to strip marker lines whose payload was pure
10
- * whitespace (`/^[ +-]\s+$/` → bare marker) to appease repository
11
- * trailing-whitespace checks. That corrupted real content — Firefox
12
- * sources contain whitespace-only lines, so a ` `/`-` line whose payload
13
- * was e.g. two spaces no longer matched the pristine tree (the freshly
14
- * exported patch failed `git apply --check`), and a `+` line silently
15
- * changed what the patch produces, making re-import diverge from the
16
- * engine state it was exported from (2026-07-05 review, finding M2).
17
- * The whitespace check itself excludes `patches/*.patch`
18
- * (scripts/check-worktree-whitespace.mjs), so the trimming had no
19
- * remaining justification. Patch bodies are now written byte-for-byte as
20
- * git produced them — including the single-space rendering of blank
21
- * context lines, which `re-export.integration.test.ts` pins.
9
+ * **Do not reintroduce whitespace trimming here.** Stripping marker lines
10
+ * whose payload is pure whitespace (`/^[ +-]\s+$/` → bare marker) corrupts
11
+ * real content: Firefox sources contain whitespace-only lines, so a ` `/`-`
12
+ * line whose payload was e.g. two spaces no longer matches the pristine tree
13
+ * (the freshly exported patch fails `git apply --check`), and a `+` line
14
+ * silently changes what the patch produces, making re-import diverge from
15
+ * the engine state it was exported from. The repository whitespace check
16
+ * already excludes `patches/*.patch`
17
+ * (scripts/check-worktree-whitespace.mjs). Patch bodies are written
18
+ * byte-for-byte as git produced them, including the single-space rendering
19
+ * of blank context lines, which `re-export.integration.test.ts` pins.
22
20
  */
23
21
  export declare function normalizePatchArtifact(content: string): string;
@@ -4,22 +4,20 @@
4
4
  *
5
5
  * Currently the identity function, kept as a narrow chokepoint for future
6
6
  * artifact-level fixes so every export path (`commitExportedPatch`,
7
- * `commitPlacementExport`, `updatePatch`, `patch split`) funnels through
8
- * one place.
7
+ * `commitPlacementExport`, `updatePatch`, `patch split`) funnels through one
8
+ * place.
9
9
  *
10
- * History: this used to strip marker lines whose payload was pure
11
- * whitespace (`/^[ +-]\s+$/` → bare marker) to appease repository
12
- * trailing-whitespace checks. That corrupted real content — Firefox
13
- * sources contain whitespace-only lines, so a ` `/`-` line whose payload
14
- * was e.g. two spaces no longer matched the pristine tree (the freshly
15
- * exported patch failed `git apply --check`), and a `+` line silently
16
- * changed what the patch produces, making re-import diverge from the
17
- * engine state it was exported from (2026-07-05 review, finding M2).
18
- * The whitespace check itself excludes `patches/*.patch`
19
- * (scripts/check-worktree-whitespace.mjs), so the trimming had no
20
- * remaining justification. Patch bodies are now written byte-for-byte as
21
- * git produced them — including the single-space rendering of blank
22
- * context lines, which `re-export.integration.test.ts` pins.
10
+ * **Do not reintroduce whitespace trimming here.** Stripping marker lines
11
+ * whose payload is pure whitespace (`/^[ +-]\s+$/` → bare marker) corrupts
12
+ * real content: Firefox sources contain whitespace-only lines, so a ` `/`-`
13
+ * line whose payload was e.g. two spaces no longer matches the pristine tree
14
+ * (the freshly exported patch fails `git apply --check`), and a `+` line
15
+ * silently changes what the patch produces, making re-import diverge from
16
+ * the engine state it was exported from. The repository whitespace check
17
+ * already excludes `patches/*.patch`
18
+ * (scripts/check-worktree-whitespace.mjs). Patch bodies are written
19
+ * byte-for-byte as git produced them, including the single-space rendering
20
+ * of blank context lines, which `re-export.integration.test.ts` pins.
23
21
  */
24
22
  export function normalizePatchArtifact(content) {
25
23
  return content;
@@ -2,6 +2,7 @@
2
2
  * Manifest metadata mutation helpers for patch export commands.
3
3
  */
4
4
  import type { PatchMetadata } from '../types/commands/index.js';
5
+ import type { PatchDirectoryLockOptions } from './patch-lock.js';
5
6
  /**
6
7
  * Optional `PatchMetadata` keys safe to clear via the helpers below.
7
8
  */
@@ -13,8 +14,11 @@ export type ClearablePatchMetadataField = 'tier' | 'lintIgnore' | 'stagedDepende
13
14
  * @param filename - Patch filename
14
15
  * @param updates - Field values to set
15
16
  * @param unsetFields - Optional fields to remove from the entry
17
+ * @param lockOptions - `--wait-lock` budget and the command name recorded in
18
+ * the lock's owner metadata. Threaded from the CLI so a caller that waits
19
+ * is not silently given the default 30s budget.
16
20
  */
17
- export declare function updatePatchMetadata(patchesDir: string, filename: string, updates: Partial<PatchMetadata>, unsetFields?: ReadonlyArray<ClearablePatchMetadataField>): Promise<void>;
21
+ export declare function updatePatchMetadata(patchesDir: string, filename: string, updates: Partial<PatchMetadata>, unsetFields?: ReadonlyArray<ClearablePatchMetadataField>, lockOptions?: PatchDirectoryLockOptions): Promise<void>;
18
22
  /** Return shape from a `mutatePatchMetadata` mutator. */
19
23
  export interface PatchMetadataMutation {
20
24
  /** Field values to set on the entry. */
@@ -32,5 +36,11 @@ export interface PatchMetadataMutationResult {
32
36
  /**
33
37
  * Reads a patch's metadata under the directory lock, applies a mutator
34
38
  * function to compute the update, and writes the result back.
39
+ *
40
+ * @param patchesDir - Path to the patches directory
41
+ * @param filename - Patch filename
42
+ * @param mutator - Computes the update from the existing metadata
43
+ * @param lockOptions - `--wait-lock` budget and owner-metadata command name
44
+ * @returns Before/after metadata, or null when the patch was not found
35
45
  */
36
- export declare function mutatePatchMetadata(patchesDir: string, filename: string, mutator: (existing: PatchMetadata) => PatchMetadataMutation): Promise<PatchMetadataMutationResult | null>;
46
+ export declare function mutatePatchMetadata(patchesDir: string, filename: string, mutator: (existing: PatchMetadata) => PatchMetadataMutation, lockOptions?: PatchDirectoryLockOptions): Promise<PatchMetadataMutationResult | null>;
@@ -11,20 +11,29 @@ import { mutatePatchRowsInManifest } from './patch-manifest.js';
11
11
  * @param filename - Patch filename
12
12
  * @param updates - Field values to set
13
13
  * @param unsetFields - Optional fields to remove from the entry
14
+ * @param lockOptions - `--wait-lock` budget and the command name recorded in
15
+ * the lock's owner metadata. Threaded from the CLI so a caller that waits
16
+ * is not silently given the default 30s budget.
14
17
  */
15
- export async function updatePatchMetadata(patchesDir, filename, updates, unsetFields = []) {
18
+ export async function updatePatchMetadata(patchesDir, filename, updates, unsetFields = [], lockOptions = {}) {
16
19
  await withPatchDirectoryLock(patchesDir, async () => {
17
20
  await mutatePatchRowsInManifest(patchesDir, [filename], () => ({
18
21
  set: updates,
19
22
  unset: unsetFields,
20
23
  }));
21
- });
24
+ }, lockOptions);
22
25
  }
23
26
  /**
24
27
  * Reads a patch's metadata under the directory lock, applies a mutator
25
28
  * function to compute the update, and writes the result back.
29
+ *
30
+ * @param patchesDir - Path to the patches directory
31
+ * @param filename - Patch filename
32
+ * @param mutator - Computes the update from the existing metadata
33
+ * @param lockOptions - `--wait-lock` budget and owner-metadata command name
34
+ * @returns Before/after metadata, or null when the patch was not found
26
35
  */
27
- export async function mutatePatchMetadata(patchesDir, filename, mutator) {
36
+ export async function mutatePatchMetadata(patchesDir, filename, mutator, lockOptions = {}) {
28
37
  return await withPatchDirectoryLock(patchesDir, async () => {
29
38
  const result = await mutatePatchRowsInManifest(patchesDir, [filename], (existing) => {
30
39
  const { set = {}, unset = [] } = mutator(existing);
@@ -34,5 +43,5 @@ export async function mutatePatchMetadata(patchesDir, filename, mutator) {
34
43
  if (!changed)
35
44
  return null;
36
45
  return { before: changed.before, after: changed.after };
37
- });
46
+ }, lockOptions);
38
47
  }
@@ -1,5 +1,6 @@
1
1
  import type { PatchMetadata } from '../types/commands/index.js';
2
2
  import type { FireForgeConfig } from '../types/config.js';
3
+ import type { PatchDirectoryLockOptions } from './patch-lock.js';
3
4
  /**
4
5
  * Optional post-commit hook for {@link updatePatchAndMetadata}. Runs inside
5
6
  * the patch directory lock after the mutation has succeeded but before the
@@ -16,5 +17,16 @@ export interface UpdatePatchPolicyGate {
16
17
  * Updates a patch file body and its manifest row under the same patch
17
18
  * directory lock. Intended for commands like `re-export --files` where the
18
19
  * file body and `filesAffected` metadata must move together.
20
+ *
21
+ * The body write is skipped when the normalized new content is byte-identical
22
+ * to what is already on disk. A bulk `re-export --all` refreshes every patch
23
+ * in the queue, including ones the working tree never touched; rewriting an
24
+ * unchanged body churns its mtime and reports "Re-exported" for a patch
25
+ * nothing happened to, which is exactly the noise that hides a real
26
+ * unexpected rewrite in `git status`. Metadata still moves either way — only
27
+ * the redundant byte-for-byte write is elided.
28
+ *
29
+ * @returns True when the patch body on disk changed, false when it was
30
+ * already byte-identical to the new content.
19
31
  */
20
- export declare function updatePatchAndMetadata(patchesDir: string, filename: string, newContent: string, updates: Partial<PatchMetadata>, onCommitted?: UpdatePatchCommittedHook, policyGate?: UpdatePatchPolicyGate): Promise<void>;
32
+ export declare function updatePatchAndMetadata(patchesDir: string, filename: string, newContent: string, updates: Partial<PatchMetadata>, onCommitted?: UpdatePatchCommittedHook, policyGate?: UpdatePatchPolicyGate, lockOptions?: PatchDirectoryLockOptions): Promise<boolean>;
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { join } from 'node:path';
3
+ import { PatchError } from '../errors/patch.js';
3
4
  import { toError } from '../utils/errors.js';
4
5
  import { pathExists, readText, writeText } from '../utils/fs.js';
5
6
  import { warn } from '../utils/logger.js';
@@ -11,20 +12,31 @@ import { buildProjectedManifest, enforcePatchPolicy } from './patch-policy.js';
11
12
  * Updates a patch file body and its manifest row under the same patch
12
13
  * directory lock. Intended for commands like `re-export --files` where the
13
14
  * file body and `filesAffected` metadata must move together.
15
+ *
16
+ * The body write is skipped when the normalized new content is byte-identical
17
+ * to what is already on disk. A bulk `re-export --all` refreshes every patch
18
+ * in the queue, including ones the working tree never touched; rewriting an
19
+ * unchanged body churns its mtime and reports "Re-exported" for a patch
20
+ * nothing happened to, which is exactly the noise that hides a real
21
+ * unexpected rewrite in `git status`. Metadata still moves either way — only
22
+ * the redundant byte-for-byte write is elided.
23
+ *
24
+ * @returns True when the patch body on disk changed, false when it was
25
+ * already byte-identical to the new content.
14
26
  */
15
- export async function updatePatchAndMetadata(patchesDir, filename, newContent, updates, onCommitted, policyGate) {
16
- await withPatchDirectoryLock(patchesDir, async () => {
27
+ export async function updatePatchAndMetadata(patchesDir, filename, newContent, updates, onCommitted, policyGate, lockOptions = {}) {
28
+ return withPatchDirectoryLock(patchesDir, async () => {
17
29
  const manifest = await loadPatchesManifestForWrite(patchesDir);
18
30
  if (!manifest) {
19
- throw new Error('Cannot update patch metadata: patches.json is missing.');
31
+ throw new PatchError('Cannot update patch metadata: patches.json is missing.', filename);
20
32
  }
21
33
  const patchIndex = manifest.patches.findIndex((p) => p.filename === filename);
22
34
  if (patchIndex === -1) {
23
- throw new Error(`Cannot update patch metadata: ${filename} not found in patches.json.`);
35
+ throw new PatchError(`Cannot update patch metadata: ${filename} not found in patches.json.`, filename);
24
36
  }
25
37
  const patchPath = join(patchesDir, filename);
26
38
  if (!(await pathExists(patchPath))) {
27
- throw new Error(`Cannot update patch: patch file is missing on disk: ${filename}`);
39
+ throw new PatchError(`Cannot update patch: patch file is missing on disk: ${filename}`, filename);
28
40
  }
29
41
  const originalContent = await readText(patchPath);
30
42
  const existingPatch = manifest.patches[patchIndex];
@@ -37,10 +49,14 @@ export async function updatePatchAndMetadata(patchesDir, filename, newContent, u
37
49
  forceUnsafe: policyGate.forceUnsafe === true,
38
50
  });
39
51
  }
52
+ const normalized = normalizePatchArtifact(newContent);
53
+ const bodyChanged = normalized !== originalContent;
40
54
  let patchWritten = false;
41
55
  try {
42
- await writeText(patchPath, normalizePatchArtifact(newContent));
43
- patchWritten = true;
56
+ if (bodyChanged) {
57
+ await writeText(patchPath, normalized);
58
+ patchWritten = true;
59
+ }
44
60
  await mutatePatchRowsInManifest(patchesDir, [filename], () => ({ set: updates }));
45
61
  }
46
62
  catch (error) {
@@ -63,5 +79,6 @@ export async function updatePatchAndMetadata(patchesDir, filename, newContent, u
63
79
  toError(hookError).message);
64
80
  }
65
81
  }
66
- });
82
+ return bodyChanged;
83
+ }, lockOptions);
67
84
  }
@@ -1,6 +1,7 @@
1
1
  import type { PatchCategory, PatchesManifest, PatchInfo, PatchMetadata } from '../types/commands/index.js';
2
2
  import type { FireForgeConfig } from '../types/config.js';
3
3
  import { type SupersedeCoverageDetail } from './patch-export-coverage.js';
4
+ import type { PatchDirectoryLockOptions } from './patch-lock.js';
4
5
  export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, findSupersededPatches, isPatchFullyCovered, type SupersedeCoverageDetail, } from './patch-export-coverage.js';
5
6
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
6
7
  export { updatePatchAndMetadata } from './patch-export-update.js';
@@ -23,11 +24,11 @@ export declare function sanitizeName(name: string): string;
23
24
  /**
24
25
  * Strips a leading `NNN-<category>-` prefix from a sanitized name slug.
25
26
  * Operators frequently pass the DESIRED FILENAME stem to `--name`
26
- * (`--name 203-ui-foo --category ui`), which 0.33.0 double-prefixed into
27
- * `203-ui-203-ui-foo.patch`. The filename builders prepend the order and
28
- * category themselves, so a matching prefix in the name is always
29
- * redundant. Applied repeatedly so a twice-prefixed slug (from a previous
30
- * double-prefix incident) also collapses. Exported for direct testing.
27
+ * (`--name 203-ui-foo --category ui`), which would otherwise double-prefix
28
+ * into `203-ui-203-ui-foo.patch`. The filename builders prepend the order
29
+ * and category themselves, so a matching prefix in the name is always
30
+ * redundant. Applied repeatedly so a twice-prefixed slug also collapses.
31
+ * Exported for direct testing.
31
32
  */
32
33
  export declare function stripRedundantCategoryPrefix(sanitizedName: string, category: string): string;
33
34
  /**
@@ -36,9 +37,9 @@ export declare function stripRedundantCategoryPrefix(sanitizedName: string, cate
36
37
  * A single trailing `.patch` extension is stripped before sanitisation:
37
38
  * operators frequently pass a full patch FILENAME where a name is expected
38
39
  * (`move-files <from> 348-ui-foo.patch --create`, `rename --to foo.patch`),
39
- * and 0.38.0 slugged the extension into `-patch`, producing double-suffixed
40
- * `...-patch.patch` files. A name that deliberately ends in a literal
41
- * `-patch` slug segment must now be written without the dot form.
40
+ * and slugging the extension produces double-suffixed `...-patch.patch`
41
+ * files. A name that deliberately ends in a literal `-patch` slug segment
42
+ * must be written without the dot form.
42
43
  */
43
44
  export declare function patchNameSlug(name: string, category: string): string;
44
45
  /**
@@ -69,6 +70,12 @@ export interface CommitExportedPatchInput {
69
70
  policyCommand?: string;
70
71
  /** Whether --force-unsafe was supplied by the mutating command. */
71
72
  forceUnsafe?: boolean;
73
+ /**
74
+ * `--wait-lock` budget and the command name recorded in the lock's owner
75
+ * metadata. Threaded from the CLI so a caller that asked to wait is not
76
+ * silently given the default budget.
77
+ */
78
+ lockOptions?: PatchDirectoryLockOptions;
72
79
  }
73
80
  export interface CommitExportedPatchResult {
74
81
  patchFilename: string;
@@ -7,7 +7,7 @@ import { PATCH_CATEGORIES } from '../utils/validation.js';
7
7
  import { discoverPatches, withPatchDirectoryLock } from './patch-apply.js';
8
8
  import { normalizePatchArtifact } from './patch-artifact-normalize.js';
9
9
  import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
10
- import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
10
+ import { addPatchToManifest, findPatchesAffectingFile, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
11
11
  import { requirePatchOrder } from './patch-parse.js';
12
12
  import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
13
13
  export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, findSupersededPatches, isPatchFullyCovered, } from './patch-export-coverage.js';
@@ -50,11 +50,11 @@ export function sanitizeName(name) {
50
50
  /**
51
51
  * Strips a leading `NNN-<category>-` prefix from a sanitized name slug.
52
52
  * Operators frequently pass the DESIRED FILENAME stem to `--name`
53
- * (`--name 203-ui-foo --category ui`), which 0.33.0 double-prefixed into
54
- * `203-ui-203-ui-foo.patch`. The filename builders prepend the order and
55
- * category themselves, so a matching prefix in the name is always
56
- * redundant. Applied repeatedly so a twice-prefixed slug (from a previous
57
- * double-prefix incident) also collapses. Exported for direct testing.
53
+ * (`--name 203-ui-foo --category ui`), which would otherwise double-prefix
54
+ * into `203-ui-203-ui-foo.patch`. The filename builders prepend the order
55
+ * and category themselves, so a matching prefix in the name is always
56
+ * redundant. Applied repeatedly so a twice-prefixed slug also collapses.
57
+ * Exported for direct testing.
58
58
  */
59
59
  export function stripRedundantCategoryPrefix(sanitizedName, category) {
60
60
  const prefixes = [
@@ -80,9 +80,9 @@ export function stripRedundantCategoryPrefix(sanitizedName, category) {
80
80
  * A single trailing `.patch` extension is stripped before sanitisation:
81
81
  * operators frequently pass a full patch FILENAME where a name is expected
82
82
  * (`move-files <from> 348-ui-foo.patch --create`, `rename --to foo.patch`),
83
- * and 0.38.0 slugged the extension into `-patch`, producing double-suffixed
84
- * `...-patch.patch` files. A name that deliberately ends in a literal
85
- * `-patch` slug segment must now be written without the dot form.
83
+ * and slugging the extension produces double-suffixed `...-patch.patch`
84
+ * files. A name that deliberately ends in a literal `-patch` slug segment
85
+ * must be written without the dot form.
86
86
  */
87
87
  export function patchNameSlug(name, category) {
88
88
  const stem = name.replace(/\.patch$/i, '');
@@ -186,7 +186,7 @@ export async function commitExportedPatch(input) {
186
186
  metadata: plan.metadata,
187
187
  superseded: plan.supersededPatches,
188
188
  };
189
- });
189
+ }, input.lockOptions ?? {});
190
190
  }
191
191
  /**
192
192
  * Parses a patch filename to extract order, category, and name.
@@ -226,7 +226,6 @@ export function parseFilename(filename) {
226
226
  * @returns The patch info and metadata, or null if not found
227
227
  */
228
228
  export async function findExistingPatchForFile(patchesDir, filePath) {
229
- const { findPatchesAffectingFile } = await import('./patch-manifest.js');
230
229
  const affectingPatches = await findPatchesAffectingFile(patchesDir, filePath);
231
230
  if (affectingPatches.length === 0) {
232
231
  return null;
@@ -12,11 +12,10 @@ export declare function getTargetFileFromPatch(patchPath: string): Promise<strin
12
12
  *
13
13
  * Delegates to {@link extractAffectedFiles} so `GIT binary patch` sections
14
14
  * (which have no `+++ b/…` line, only a `diff --git a/… b/…` header) are
15
- * included alongside text hunks. Before this delegation the custom regex
16
- * only matched `+++ b/…` lines, dropping every binary file from
17
- * `filesAffected` — verify reported `files-affected-mismatch` against
18
- * branding patches and `doctor --repair-patches-manifest` "repaired" the
19
- * manifest by rewriting it to the text-only subset, hiding the true scope
20
- * of the patch.
15
+ * included alongside text hunks. Matching only `+++ b/…` lines drops every
16
+ * binary file from `filesAffected`, so verify reports
17
+ * `files-affected-mismatch` against branding patches and
18
+ * `doctor --repair-patches-manifest` "repairs" the manifest by rewriting it
19
+ * to the text-only subset, hiding the true scope of the patch.
21
20
  */
22
21
  export declare function getAllTargetFilesFromPatch(patchPath: string): Promise<string[]>;
@@ -40,12 +40,11 @@ export async function getTargetFileFromPatch(patchPath) {
40
40
  *
41
41
  * Delegates to {@link extractAffectedFiles} so `GIT binary patch` sections
42
42
  * (which have no `+++ b/…` line, only a `diff --git a/… b/…` header) are
43
- * included alongside text hunks. Before this delegation the custom regex
44
- * only matched `+++ b/…` lines, dropping every binary file from
45
- * `filesAffected` — verify reported `files-affected-mismatch` against
46
- * branding patches and `doctor --repair-patches-manifest` "repaired" the
47
- * manifest by rewriting it to the text-only subset, hiding the true scope
48
- * of the patch.
43
+ * included alongside text hunks. Matching only `+++ b/…` lines drops every
44
+ * binary file from `filesAffected`, so verify reports
45
+ * `files-affected-mismatch` against branding patches and
46
+ * `doctor --repair-patches-manifest` "repairs" the manifest by rewriting it
47
+ * to the text-only subset, hiding the true scope of the patch.
49
48
  */
50
49
  export async function getAllTargetFilesFromPatch(patchPath) {
51
50
  const content = await readText(patchPath);
@@ -2,18 +2,13 @@
2
2
  * Builds a concise "patch not found" error message with did-you-mean
3
3
  * suggestions in place of the full queue enumeration.
4
4
  *
5
- * 2026-04-26 eval Finding 12: pre-fix every `patch` subcommand
6
- * (`delete`, `reorder`, `tier`, `lint-ignore`) caught a missing
7
- * identifier by joining every queued patch's filename and (optional)
8
- * manifest name into a single comma-separated `Available: ...` tail.
9
- * On a 29-patch queue the resulting line ran ~1500 characters and
10
- * buried the actual error under noise that was almost never useful in
11
- * CI. The new shape ranks each known identifier (ordinal,
12
- * filename-with-and-without-`.patch`, manifest name) by Levenshtein
13
- * distance from the operator's input, surfaces up to three suggestions
14
- * close enough to be plausibly the intended target, and falls back to
15
- * a count-only summary that points at `fireforge patch list` when no
16
- * close match exists. The full enumeration is no longer ever inlined.
5
+ * Joining every queued patch's filename and manifest name into a
6
+ * comma-separated `Available: ...` tail runs ~1500 characters on a 29-patch
7
+ * queue and buries the actual error. This ranks each known identifier
8
+ * (ordinal, filename with and without `.patch`, manifest name) by
9
+ * Levenshtein distance from the operator's input, surfaces up to three
10
+ * plausible suggestions, and falls back to a count-only summary pointing at
11
+ * `fireforge patch list` when no close match exists.
17
12
  */
18
13
  import type { PatchMetadata } from '../types/commands/index.js';
19
14
  /**
@@ -3,18 +3,13 @@
3
3
  * Builds a concise "patch not found" error message with did-you-mean
4
4
  * suggestions in place of the full queue enumeration.
5
5
  *
6
- * 2026-04-26 eval Finding 12: pre-fix every `patch` subcommand
7
- * (`delete`, `reorder`, `tier`, `lint-ignore`) caught a missing
8
- * identifier by joining every queued patch's filename and (optional)
9
- * manifest name into a single comma-separated `Available: ...` tail.
10
- * On a 29-patch queue the resulting line ran ~1500 characters and
11
- * buried the actual error under noise that was almost never useful in
12
- * CI. The new shape ranks each known identifier (ordinal,
13
- * filename-with-and-without-`.patch`, manifest name) by Levenshtein
14
- * distance from the operator's input, surfaces up to three suggestions
15
- * close enough to be plausibly the intended target, and falls back to
16
- * a count-only summary that points at `fireforge patch list` when no
17
- * close match exists. The full enumeration is no longer ever inlined.
6
+ * Joining every queued patch's filename and manifest name into a
7
+ * comma-separated `Available: ...` tail runs ~1500 characters on a 29-patch
8
+ * queue and buries the actual error. This ranks each known identifier
9
+ * (ordinal, filename with and without `.patch`, manifest name) by
10
+ * Levenshtein distance from the operator's input, surfaces up to three
11
+ * plausible suggestions, and falls back to a count-only summary pointing at
12
+ * `fireforge patch list` when no close match exists.
18
13
  */
19
14
  /** Maximum Levenshtein distance accepted as a "did you mean" suggestion. */
20
15
  const SUGGESTION_DISTANCE_THRESHOLD = 3;
@@ -93,13 +88,13 @@ function rankSuggestions(identifier, candidates) {
93
88
  .map((candidate) => {
94
89
  const lower = candidate.toLowerCase();
95
90
  // Prefix relation in EITHER direction is a stronger signal than edit
96
- // distance and is not bounded by it: a partial ordinal or
97
- // an abbreviated slug ("ui-foo" for "002-ui-foo.patch") is many edits
98
- // away from the full identifier yet is obviously the intended target.
99
- // `lower.startsWith(needle)`: the operator typed an abbreviation of
100
- // a real identifier. The reverse relation is only meaningful when
101
- // the candidate is substantial — otherwise the single-character
102
- // ordinal "9" would "match" every input starting with a 9.
91
+ // distance and is not bounded by it: a partial ordinal or an
92
+ // abbreviated slug ("ui-foo" for "002-ui-foo.patch") is many edits away
93
+ // from the full identifier yet is obviously the intended target.
94
+ // `lower.startsWith(needle)`: the operator typed an abbreviation of a
95
+ // real identifier. The reverse relation is only meaningful when the
96
+ // candidate is substantial — otherwise the single-character ordinal
97
+ // "9" would "match" every input starting with a 9.
103
98
  const prefixMatch = needle.length >= MIN_PREFIX_MATCH_LENGTH &&
104
99
  (lower.startsWith(needle) ||
105
100
  (lower.length >= MIN_PREFIX_MATCH_LENGTH && needle.startsWith(lower)));
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Queue-wide lint for binary patch bodies that cannot recreate their file.
3
+ *
4
+ * `git diff` has two ways to render a binary change. `git diff --binary`
5
+ * emits a `GIT binary patch` section carrying the literal/delta payload —
6
+ * that body can be replayed by `git apply`. Plain `git diff` emits only the
7
+ * informational `Binary files a/x and b/x differ`, which records THAT the
8
+ * bytes changed and carries none of them.
9
+ *
10
+ * The stub form is dangerous rather than merely lossy because it still
11
+ * carries a correct `index <old>..<new>` line. Every identity-shaped check in
12
+ * the codebase — worktree classification, foreign-drift detection — keys on
13
+ * that hash, matches it against the live file, and concludes the patch is
14
+ * backed. So a queue can hold a patch that provably cannot rebuild its own
15
+ * file while every gate reports green, and the loss surfaces only at the next
16
+ * clean-room apply. This rule is the one check that reads the body itself and
17
+ * fails closed, whichever command wrote it.
18
+ *
19
+ * Body-only by design: it needs no engine checkout, so it runs anywhere the
20
+ * queue context is available and never pulls an engine dependency into the
21
+ * cross-patch lint graph.
22
+ */
23
+ import type { PatchLintIssue } from '../types/commands/index.js';
24
+ /**
25
+ * The slice of a queue entry this rule reads. Declared structurally rather
26
+ * than importing `PatchQueueEntry` from `patch-lint-cross.ts`, which imports
27
+ * this module back — the local shape keeps the dependency edge one-way and
28
+ * `dpdm` clean, matching `patch-lint-module-registration.ts`.
29
+ */
30
+ interface BinaryBodyQueueEntry {
31
+ filename: string;
32
+ diff: string;
33
+ }
34
+ /** Queue view accepted by {@link lintPatchQueueBinaryBodies}. */
35
+ interface BinaryBodyQueueContext {
36
+ entries: readonly BinaryBodyQueueEntry[];
37
+ }
38
+ /** Lint check identifier emitted by {@link lintPatchQueueBinaryBodies}. */
39
+ export declare const BINARY_BODY_CHECK = "binary-body-not-reconstructable";
40
+ /**
41
+ * Flags every binary diff section whose body carries no reconstructable
42
+ * payload.
43
+ *
44
+ * Deletions are exempt: a `deleted file mode` section needs no bytes to
45
+ * replay, so the informational form is complete for that case.
46
+ *
47
+ * @param ctx - Queue context (raw patch bodies in application order)
48
+ * @returns One error-severity issue per offending file per patch
49
+ */
50
+ export declare function lintPatchQueueBinaryBodies(ctx: BinaryBodyQueueContext): PatchLintIssue[];
51
+ export {};
@@ -0,0 +1,39 @@
1
+ import { parseDiffSections } from './patch-parse.js';
2
+ /** Lint check identifier emitted by {@link lintPatchQueueBinaryBodies}. */
3
+ export const BINARY_BODY_CHECK = 'binary-body-not-reconstructable';
4
+ /**
5
+ * Flags every binary diff section whose body carries no reconstructable
6
+ * payload.
7
+ *
8
+ * Deletions are exempt: a `deleted file mode` section needs no bytes to
9
+ * replay, so the informational form is complete for that case.
10
+ *
11
+ * @param ctx - Queue context (raw patch bodies in application order)
12
+ * @returns One error-severity issue per offending file per patch
13
+ */
14
+ export function lintPatchQueueBinaryBodies(ctx) {
15
+ const issues = [];
16
+ for (const entry of ctx.entries) {
17
+ const seen = new Set();
18
+ for (const section of parseDiffSections(entry.diff)) {
19
+ if (!section.isBinary || section.hasBinaryDelta || section.isDeletedFile)
20
+ continue;
21
+ const file = section.targetPath;
22
+ if (seen.has(file))
23
+ continue;
24
+ seen.add(file);
25
+ issues.push({
26
+ file,
27
+ check: BINARY_BODY_CHECK,
28
+ patches: [entry.filename],
29
+ fingerprint: `${BINARY_BODY_CHECK}|${entry.filename}|${file}`,
30
+ message: `Binary file "${file}" is recorded in ${entry.filename} as "Binary files … differ", ` +
31
+ 'which carries no data and cannot recreate the file on apply. ' +
32
+ `Re-export the patch from a tree where ${file} is present ` +
33
+ `("fireforge re-export ${entry.filename}") so the body carries a GIT binary patch delta.`,
34
+ severity: 'error',
35
+ });
36
+ }
37
+ }
38
+ return issues;
39
+ }
@@ -11,8 +11,8 @@ export interface PerPatchLintCacheEntry {
11
11
  /** Non-binary diff line count measured by the cached lint run. */
12
12
  lineCount: number;
13
13
  /**
14
- * Sorted lint-ignore waiver ids in force when this entry was computed
15
- *. A lookup presenting a different effective set misses.
14
+ * Sorted lint-ignore waiver ids in force when this entry was computed.
15
+ * A lookup presenting a different effective set misses.
16
16
  */
17
17
  lintIgnore: string[];
18
18
  updatedAt: string;
@@ -53,9 +53,9 @@ export interface CachedPerPatchLint {
53
53
  }
54
54
  /**
55
55
  * Returns the cached lint payload for a patch when the stored key still
56
- * matches AND the entry was computed under the same lint-ignore waiver set
57
- *. A waiver change makes a replayed verdict actively wrong, so
58
- * the waiver set is compared explicitly rather than trusted to the key.
56
+ * matches AND the entry was computed under the same lint-ignore waiver set.
57
+ * A waiver change makes a replayed verdict actively wrong, so the waiver set
58
+ * is compared explicitly rather than trusted to the key.
59
59
  */
60
60
  export declare function getCachedPerPatchLintIssues(cache: PerPatchLintCacheFile, patchFilename: string, key: string, lintIgnore?: Iterable<string>): CachedPerPatchLint | undefined;
61
61
  /** Stores the per-patch lint payload after a successful lint calculation. */