@hominis/fireforge 0.43.1 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +3 -3
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +13 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-patch-manifest.d.ts +8 -0
  22. package/dist/src/commands/doctor-patch-manifest.js +155 -0
  23. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  24. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  25. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  26. package/dist/src/commands/doctor-working-tree.js +11 -18
  27. package/dist/src/commands/doctor.d.ts +1 -1
  28. package/dist/src/commands/doctor.js +64 -96
  29. package/dist/src/commands/download.js +32 -48
  30. package/dist/src/commands/export-all.js +29 -33
  31. package/dist/src/commands/export-flow.js +6 -6
  32. package/dist/src/commands/export-placement-conflicts.js +10 -9
  33. package/dist/src/commands/export-placement-gate.js +5 -5
  34. package/dist/src/commands/export-shared.d.ts +30 -33
  35. package/dist/src/commands/export-shared.js +45 -43
  36. package/dist/src/commands/export.js +21 -27
  37. package/dist/src/commands/furnace/apply.js +14 -23
  38. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  39. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  40. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  41. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  42. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  43. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  44. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  45. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  46. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  47. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  48. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  49. package/dist/src/commands/furnace/create-readback.js +12 -13
  50. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  51. package/dist/src/commands/furnace/create-templates.js +35 -30
  52. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  53. package/dist/src/commands/furnace/create.js +33 -23
  54. package/dist/src/commands/furnace/deploy.js +16 -24
  55. package/dist/src/commands/furnace/diff.js +15 -10
  56. package/dist/src/commands/furnace/init.js +33 -36
  57. package/dist/src/commands/furnace/override.js +23 -25
  58. package/dist/src/commands/furnace/preview.js +47 -67
  59. package/dist/src/commands/furnace/refresh.js +12 -16
  60. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  61. package/dist/src/commands/furnace/remove-mutations.js +14 -17
  62. package/dist/src/commands/furnace/remove-state.js +1 -1
  63. package/dist/src/commands/furnace/remove.js +33 -38
  64. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  65. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  66. package/dist/src/commands/furnace/rename.js +59 -69
  67. package/dist/src/commands/furnace/scan.js +19 -33
  68. package/dist/src/commands/furnace/status.js +12 -9
  69. package/dist/src/commands/furnace/sync.js +9 -16
  70. package/dist/src/commands/furnace/validate.js +20 -20
  71. package/dist/src/commands/import.js +48 -37
  72. package/dist/src/commands/lint-per-patch.js +15 -10
  73. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  74. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  75. package/dist/src/commands/lint-report.js +6 -7
  76. package/dist/src/commands/lint.d.ts +15 -16
  77. package/dist/src/commands/lint.js +86 -102
  78. package/dist/src/commands/package.js +6 -11
  79. package/dist/src/commands/patch/compact.js +1 -1
  80. package/dist/src/commands/patch/delete.js +24 -33
  81. package/dist/src/commands/patch/index.d.ts +5 -6
  82. package/dist/src/commands/patch/index.js +10 -12
  83. package/dist/src/commands/patch/lint-ignore.js +14 -13
  84. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  85. package/dist/src/commands/patch/move-files-create.js +8 -8
  86. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  87. package/dist/src/commands/patch/move-files-into.js +8 -8
  88. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  89. package/dist/src/commands/patch/patch-context.js +2 -3
  90. package/dist/src/commands/patch/rename.d.ts +10 -11
  91. package/dist/src/commands/patch/rename.js +11 -12
  92. package/dist/src/commands/patch/reorder.js +8 -9
  93. package/dist/src/commands/patch/split-plan.js +1 -1
  94. package/dist/src/commands/patch/split.d.ts +8 -10
  95. package/dist/src/commands/patch/split.js +9 -11
  96. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  97. package/dist/src/commands/patch/staged-dependency.js +7 -3
  98. package/dist/src/commands/patch/tier.d.ts +9 -9
  99. package/dist/src/commands/patch/tier.js +18 -15
  100. package/dist/src/commands/re-export-adjacent.js +9 -8
  101. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  102. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  103. package/dist/src/commands/re-export-drift.js +10 -10
  104. package/dist/src/commands/re-export-files.d.ts +6 -7
  105. package/dist/src/commands/re-export-files.js +34 -44
  106. package/dist/src/commands/re-export-lint.d.ts +10 -13
  107. package/dist/src/commands/re-export-lint.js +16 -14
  108. package/dist/src/commands/re-export-options.d.ts +6 -6
  109. package/dist/src/commands/re-export-options.js +6 -6
  110. package/dist/src/commands/re-export-register.d.ts +4 -10
  111. package/dist/src/commands/re-export-register.js +5 -11
  112. package/dist/src/commands/re-export-scan.js +1 -1
  113. package/dist/src/commands/re-export-single.d.ts +3 -3
  114. package/dist/src/commands/re-export-single.js +33 -25
  115. package/dist/src/commands/re-export.js +13 -21
  116. package/dist/src/commands/rebase/abort.js +3 -3
  117. package/dist/src/commands/rebase/confirm.js +2 -1
  118. package/dist/src/commands/rebase/continue.d.ts +1 -1
  119. package/dist/src/commands/rebase/continue.js +14 -9
  120. package/dist/src/commands/rebase/index.js +11 -11
  121. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  122. package/dist/src/commands/rebase/patch-loop.js +60 -39
  123. package/dist/src/commands/rebase/summary.js +1 -1
  124. package/dist/src/commands/register.js +5 -7
  125. package/dist/src/commands/reset.js +2 -1
  126. package/dist/src/commands/resolve.d.ts +16 -13
  127. package/dist/src/commands/resolve.js +30 -33
  128. package/dist/src/commands/run.js +33 -35
  129. package/dist/src/commands/setup-support.js +15 -19
  130. package/dist/src/commands/setup.js +13 -9
  131. package/dist/src/commands/status-check.d.ts +6 -6
  132. package/dist/src/commands/status-json.d.ts +6 -6
  133. package/dist/src/commands/status-json.js +5 -0
  134. package/dist/src/commands/status-output.d.ts +5 -5
  135. package/dist/src/commands/status-output.js +6 -6
  136. package/dist/src/commands/status-ownership.d.ts +16 -14
  137. package/dist/src/commands/status-ownership.js +16 -14
  138. package/dist/src/commands/status.js +42 -34
  139. package/dist/src/commands/test-build-phase.js +26 -13
  140. package/dist/src/commands/test-diagnose.js +44 -44
  141. package/dist/src/commands/test-register.js +1 -0
  142. package/dist/src/commands/test-run.d.ts +14 -16
  143. package/dist/src/commands/test-run.js +21 -13
  144. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  145. package/dist/src/commands/test-stale-gate.js +15 -16
  146. package/dist/src/commands/test-verdict.d.ts +20 -3
  147. package/dist/src/commands/test-verdict.js +30 -0
  148. package/dist/src/commands/test.js +83 -76
  149. package/dist/src/commands/token-coverage.js +3 -4
  150. package/dist/src/commands/token.js +16 -18
  151. package/dist/src/commands/tree.js +47 -31
  152. package/dist/src/commands/typecheck.d.ts +10 -12
  153. package/dist/src/commands/typecheck.js +24 -27
  154. package/dist/src/commands/verify.js +13 -15
  155. package/dist/src/commands/watch.js +21 -23
  156. package/dist/src/commands/wire.js +52 -62
  157. package/dist/src/core/ast-utils.d.ts +8 -7
  158. package/dist/src/core/ast-utils.js +8 -7
  159. package/dist/src/core/branding.d.ts +9 -14
  160. package/dist/src/core/branding.js +7 -11
  161. package/dist/src/core/browser-wire.d.ts +1 -1
  162. package/dist/src/core/browser-wire.js +14 -19
  163. package/dist/src/core/build-audit-platform.js +25 -33
  164. package/dist/src/core/build-audit-registration.js +17 -25
  165. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  166. package/dist/src/core/build-audit-resolve.js +39 -36
  167. package/dist/src/core/build-audit-transforms.js +18 -19
  168. package/dist/src/core/build-audit.js +28 -42
  169. package/dist/src/core/build-baseline-types.d.ts +29 -35
  170. package/dist/src/core/build-baseline.d.ts +5 -4
  171. package/dist/src/core/build-baseline.js +14 -14
  172. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  173. package/dist/src/core/build-overwrite-guard.js +17 -27
  174. package/dist/src/core/build-prepare.d.ts +2 -2
  175. package/dist/src/core/build-prepare.js +8 -9
  176. package/dist/src/core/config-mutate.js +20 -19
  177. package/dist/src/core/config-state.js +12 -4
  178. package/dist/src/core/config-validate.js +8 -5
  179. package/dist/src/core/config.d.ts +5 -8
  180. package/dist/src/core/config.js +7 -16
  181. package/dist/src/core/coverage-extend.d.ts +15 -13
  182. package/dist/src/core/coverage-extend.js +15 -13
  183. package/dist/src/core/destructive.d.ts +31 -9
  184. package/dist/src/core/destructive.js +29 -26
  185. package/dist/src/core/diff-hunks.js +10 -12
  186. package/dist/src/core/discard-baseline.d.ts +8 -8
  187. package/dist/src/core/discard-baseline.js +16 -15
  188. package/dist/src/core/display-state.d.ts +12 -14
  189. package/dist/src/core/display-state.js +12 -14
  190. package/dist/src/core/engine-changes.d.ts +2 -4
  191. package/dist/src/core/engine-changes.js +2 -4
  192. package/dist/src/core/engine-precondition.d.ts +28 -13
  193. package/dist/src/core/engine-precondition.js +25 -10
  194. package/dist/src/core/engine-session-lock.d.ts +47 -21
  195. package/dist/src/core/engine-session-lock.js +168 -33
  196. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  197. package/dist/src/core/export-moved-code-shape.js +10 -10
  198. package/dist/src/core/file-lock.d.ts +62 -5
  199. package/dist/src/core/file-lock.js +196 -59
  200. package/dist/src/core/firefox-cache.js +1 -3
  201. package/dist/src/core/firefox-extract.js +10 -14
  202. package/dist/src/core/firefox.d.ts +7 -5
  203. package/dist/src/core/firefox.js +4 -5
  204. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  205. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  206. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  207. package/dist/src/core/furnace-apply-ftl.js +16 -13
  208. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  209. package/dist/src/core/furnace-apply-helpers.js +30 -21
  210. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  211. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  212. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  213. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  214. package/dist/src/core/furnace-apply.d.ts +5 -8
  215. package/dist/src/core/furnace-apply.js +19 -24
  216. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  217. package/dist/src/core/furnace-checksum-utils.js +16 -0
  218. package/dist/src/core/furnace-config.d.ts +21 -30
  219. package/dist/src/core/furnace-config.js +32 -54
  220. package/dist/src/core/furnace-constants.d.ts +8 -0
  221. package/dist/src/core/furnace-constants.js +10 -2
  222. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  223. package/dist/src/core/furnace-css-fragments.js +5 -5
  224. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  225. package/dist/src/core/furnace-jsconfig.js +11 -12
  226. package/dist/src/core/furnace-marker.d.ts +7 -8
  227. package/dist/src/core/furnace-marker.js +7 -8
  228. package/dist/src/core/furnace-operation.d.ts +31 -0
  229. package/dist/src/core/furnace-operation.js +54 -17
  230. package/dist/src/core/furnace-precondition.d.ts +61 -0
  231. package/dist/src/core/furnace-precondition.js +67 -0
  232. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  233. package/dist/src/core/furnace-registration-remove.js +6 -7
  234. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  235. package/dist/src/core/furnace-registration-validate.js +20 -1
  236. package/dist/src/core/furnace-registration.d.ts +5 -6
  237. package/dist/src/core/furnace-registration.js +10 -12
  238. package/dist/src/core/furnace-rollback.js +7 -7
  239. package/dist/src/core/furnace-scanner.d.ts +1 -0
  240. package/dist/src/core/furnace-scanner.js +1 -2
  241. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  242. package/dist/src/core/furnace-stale-export.js +10 -10
  243. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  244. package/dist/src/core/furnace-state-persist.js +6 -8
  245. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  246. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  247. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  248. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  249. package/dist/src/core/furnace-validate-helpers.js +0 -491
  250. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  251. package/dist/src/core/furnace-validate-registration.js +115 -41
  252. package/dist/src/core/furnace-validate.d.ts +16 -0
  253. package/dist/src/core/furnace-validate.js +188 -145
  254. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  255. package/dist/src/core/furnace-version-drift.js +10 -11
  256. package/dist/src/core/git-base.d.ts +21 -9
  257. package/dist/src/core/git-base.js +24 -9
  258. package/dist/src/core/git-diff.d.ts +20 -9
  259. package/dist/src/core/git-diff.js +148 -63
  260. package/dist/src/core/git-file-ops.d.ts +19 -19
  261. package/dist/src/core/git-file-ops.js +19 -19
  262. package/dist/src/core/git-readonly-index.d.ts +53 -19
  263. package/dist/src/core/git-readonly-index.js +75 -31
  264. package/dist/src/core/git-status.d.ts +5 -6
  265. package/dist/src/core/git-status.js +5 -6
  266. package/dist/src/core/git.d.ts +9 -10
  267. package/dist/src/core/git.js +57 -71
  268. package/dist/src/core/license-headers.d.ts +17 -23
  269. package/dist/src/core/license-headers.js +17 -23
  270. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  271. package/dist/src/core/mach-build-artifacts.js +57 -19
  272. package/dist/src/core/mach-error-hints.js +42 -29
  273. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  274. package/dist/src/core/mach-known-noise-filter.js +18 -20
  275. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  276. package/dist/src/core/mach-mozconfig.js +30 -0
  277. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  278. package/dist/src/core/mach-resource-shim.js +50 -67
  279. package/dist/src/core/mach.d.ts +37 -41
  280. package/dist/src/core/mach.js +50 -51
  281. package/dist/src/core/marionette-port.d.ts +36 -1
  282. package/dist/src/core/marionette-port.js +96 -31
  283. package/dist/src/core/marionette-preflight.d.ts +8 -12
  284. package/dist/src/core/marionette-preflight.js +86 -52
  285. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  286. package/dist/src/core/mochitest-server-port.js +119 -0
  287. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  288. package/dist/src/core/module-resolution-preflight.js +9 -11
  289. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  290. package/dist/src/core/moz-manifest-helpers.js +163 -0
  291. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  292. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  293. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  294. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  295. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  296. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  297. package/dist/src/core/ownership-table.d.ts +14 -16
  298. package/dist/src/core/ownership-table.js +14 -16
  299. package/dist/src/core/parser-fallback.d.ts +15 -1
  300. package/dist/src/core/parser-fallback.js +22 -3
  301. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  302. package/dist/src/core/patch-apply-fuzz.js +15 -18
  303. package/dist/src/core/patch-apply.d.ts +13 -34
  304. package/dist/src/core/patch-apply.js +16 -76
  305. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  306. package/dist/src/core/patch-artifact-normalize.js +13 -15
  307. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  308. package/dist/src/core/patch-export-metadata.js +13 -4
  309. package/dist/src/core/patch-export-update.d.ts +13 -1
  310. package/dist/src/core/patch-export-update.js +25 -8
  311. package/dist/src/core/patch-export.d.ts +15 -8
  312. package/dist/src/core/patch-export.js +10 -11
  313. package/dist/src/core/patch-files.d.ts +5 -6
  314. package/dist/src/core/patch-files.js +5 -6
  315. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  316. package/dist/src/core/patch-identifier-suggest.js +14 -19
  317. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  318. package/dist/src/core/patch-lint-binary.js +39 -0
  319. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  320. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  321. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  322. package/dist/src/core/patch-lint-checkjs.js +41 -20
  323. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  324. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  325. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  326. package/dist/src/core/patch-lint-creators.js +8 -8
  327. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  328. package/dist/src/core/patch-lint-cross.js +16 -16
  329. package/dist/src/core/patch-lint-css.d.ts +3 -5
  330. package/dist/src/core/patch-lint-css.js +17 -22
  331. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  332. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  333. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  334. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  335. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  336. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  337. package/dist/src/core/patch-lint-observer.js +7 -7
  338. package/dist/src/core/patch-lint.d.ts +38 -29
  339. package/dist/src/core/patch-lint.js +89 -121
  340. package/dist/src/core/patch-lock.d.ts +1 -1
  341. package/dist/src/core/patch-lock.js +45 -9
  342. package/dist/src/core/patch-manifest-consistency.d.ts +57 -6
  343. package/dist/src/core/patch-manifest-consistency.js +111 -40
  344. package/dist/src/core/patch-manifest-files-affected.d.ts +43 -0
  345. package/dist/src/core/patch-manifest-files-affected.js +77 -0
  346. package/dist/src/core/patch-manifest-io.js +14 -18
  347. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  348. package/dist/src/core/patch-manifest-resolve.js +9 -12
  349. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  350. package/dist/src/core/patch-manifest-validate.js +25 -13
  351. package/dist/src/core/patch-manifest.d.ts +2 -1
  352. package/dist/src/core/patch-manifest.js +2 -1
  353. package/dist/src/core/patch-parse.d.ts +24 -13
  354. package/dist/src/core/patch-parse.js +19 -14
  355. package/dist/src/core/patch-policy.d.ts +2 -2
  356. package/dist/src/core/patch-policy.js +2 -2
  357. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  358. package/dist/src/core/patch-registration-refs.js +9 -9
  359. package/dist/src/core/process-cpu-time.d.ts +12 -0
  360. package/dist/src/core/process-cpu-time.js +52 -0
  361. package/dist/src/core/rebase-session.d.ts +38 -26
  362. package/dist/src/core/rebase-session.js +55 -28
  363. package/dist/src/core/register-browser-content.js +9 -74
  364. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  365. package/dist/src/core/register-module.js +10 -43
  366. package/dist/src/core/register-scaffold.d.ts +8 -8
  367. package/dist/src/core/register-scaffold.js +10 -10
  368. package/dist/src/core/register-shared-css.d.ts +9 -12
  369. package/dist/src/core/register-shared-css.js +17 -87
  370. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  371. package/dist/src/core/register-xpcshell-test.js +7 -8
  372. package/dist/src/core/shared-ftl.js +12 -4
  373. package/dist/src/core/state-file.d.ts +45 -0
  374. package/dist/src/core/state-file.js +34 -0
  375. package/dist/src/core/status-binary.d.ts +18 -11
  376. package/dist/src/core/status-binary.js +19 -12
  377. package/dist/src/core/status-classify.d.ts +30 -36
  378. package/dist/src/core/status-classify.js +21 -26
  379. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  380. package/dist/src/core/test-changed-prefs.js +78 -0
  381. package/dist/src/core/test-harness-crash.d.ts +25 -63
  382. package/dist/src/core/test-harness-crash.js +121 -142
  383. package/dist/src/core/test-harness-signature.d.ts +18 -0
  384. package/dist/src/core/test-harness-signature.js +13 -0
  385. package/dist/src/core/test-path-scope.d.ts +12 -15
  386. package/dist/src/core/test-path-scope.js +15 -18
  387. package/dist/src/core/test-stale-check.d.ts +17 -17
  388. package/dist/src/core/test-stale-check.js +50 -43
  389. package/dist/src/core/test-stall-triage.d.ts +51 -0
  390. package/dist/src/core/test-stall-triage.js +126 -0
  391. package/dist/src/core/token-category.js +66 -14
  392. package/dist/src/core/token-coverage.js +9 -9
  393. package/dist/src/core/token-dark-mode.d.ts +9 -11
  394. package/dist/src/core/token-dark-mode.js +29 -13
  395. package/dist/src/core/token-docs.d.ts +2 -0
  396. package/dist/src/core/token-docs.js +3 -1
  397. package/dist/src/core/token-manager.d.ts +10 -2
  398. package/dist/src/core/token-manager.js +17 -8
  399. package/dist/src/core/token-scaffold.d.ts +7 -7
  400. package/dist/src/core/token-scaffold.js +7 -7
  401. package/dist/src/core/token-variant.d.ts +4 -4
  402. package/dist/src/core/token-variant.js +28 -6
  403. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  404. package/dist/src/core/toolchain-preflight.js +28 -31
  405. package/dist/src/core/tree-guard.js +12 -2
  406. package/dist/src/core/tree-store.d.ts +41 -27
  407. package/dist/src/core/tree-store.js +68 -43
  408. package/dist/src/core/typecheck-shim.d.ts +23 -24
  409. package/dist/src/core/typecheck-shim.js +23 -24
  410. package/dist/src/core/typecheck.js +15 -9
  411. package/dist/src/core/wire-destroy.d.ts +3 -3
  412. package/dist/src/core/wire-destroy.js +7 -15
  413. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  414. package/dist/src/core/wire-dom-fragment.js +11 -44
  415. package/dist/src/core/wire-init.d.ts +2 -3
  416. package/dist/src/core/wire-init.js +8 -19
  417. package/dist/src/core/wire-subscript.d.ts +2 -3
  418. package/dist/src/core/wire-subscript.js +4 -13
  419. package/dist/src/core/wire-utils.d.ts +7 -8
  420. package/dist/src/core/wire-utils.js +7 -8
  421. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  422. package/dist/src/core/xpcshell-appdir.js +38 -45
  423. package/dist/src/errors/base.d.ts +37 -16
  424. package/dist/src/errors/base.js +37 -16
  425. package/dist/src/errors/build.d.ts +13 -1
  426. package/dist/src/errors/build.js +14 -2
  427. package/dist/src/errors/codes.d.ts +16 -0
  428. package/dist/src/errors/codes.js +16 -0
  429. package/dist/src/errors/furnace.d.ts +4 -4
  430. package/dist/src/errors/git.d.ts +6 -10
  431. package/dist/src/errors/git.js +6 -10
  432. package/dist/src/errors/patch.d.ts +7 -7
  433. package/dist/src/errors/patch.js +7 -7
  434. package/dist/src/errors/rebase.d.ts +4 -4
  435. package/dist/src/errors/rebase.js +4 -4
  436. package/dist/src/index.d.ts +7 -1
  437. package/dist/src/index.js +5 -0
  438. package/dist/src/types/commands/index.d.ts +2 -2
  439. package/dist/src/types/commands/options.d.ts +111 -70
  440. package/dist/src/types/commands/patches.d.ts +24 -34
  441. package/dist/src/types/commands/project.d.ts +5 -34
  442. package/dist/src/types/config.d.ts +25 -23
  443. package/dist/src/types/config.js +6 -1
  444. package/dist/src/types/furnace.d.ts +37 -13
  445. package/dist/src/types/furnace.js +19 -1
  446. package/dist/src/types/index.d.ts +3 -3
  447. package/dist/src/utils/build-info.d.ts +7 -8
  448. package/dist/src/utils/build-info.js +12 -11
  449. package/dist/src/utils/errors.d.ts +6 -8
  450. package/dist/src/utils/errors.js +6 -8
  451. package/dist/src/utils/logger.d.ts +27 -10
  452. package/dist/src/utils/logger.js +28 -16
  453. package/dist/src/utils/machine-output.d.ts +12 -0
  454. package/dist/src/utils/machine-output.js +33 -0
  455. package/dist/src/utils/options.d.ts +31 -14
  456. package/dist/src/utils/options.js +86 -30
  457. package/dist/src/utils/paths.d.ts +10 -8
  458. package/dist/src/utils/paths.js +10 -8
  459. package/dist/src/utils/platform.d.ts +0 -25
  460. package/dist/src/utils/platform.js +1 -42
  461. package/dist/src/utils/process-group.d.ts +9 -4
  462. package/dist/src/utils/process-group.js +19 -5
  463. package/dist/src/utils/process.d.ts +42 -7
  464. package/dist/src/utils/process.js +44 -17
  465. package/dist/src/utils/ps-duration.d.ts +31 -0
  466. package/dist/src/utils/ps-duration.js +70 -0
  467. package/dist/src/utils/regex.d.ts +9 -10
  468. package/dist/src/utils/regex.js +9 -10
  469. package/dist/src/utils/validation.d.ts +58 -28
  470. package/dist/src/utils/validation.js +60 -33
  471. package/package.json +3 -3
  472. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  473. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  474. package/dist/src/core/manifest-helpers.d.ts +0 -38
  475. package/dist/src/core/manifest-helpers.js +0 -120
  476. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  477. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  478. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -1,10 +1,9 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * `doctor` check for stale furnace jar.mn registrations (0.34.0 field
4
- * report): a component-file rename left the old toolkit jar.mn line
5
- * pointing at the deleted file, every build failed at packaging, and
6
- * `doctor --repair-furnace` reported success without pruning. Split out
7
- * of `doctor-furnace.ts` to keep that file within the line budget.
3
+ * `doctor` check for stale furnace jar.mn registrations: a component-file
4
+ * rename can leave the old toolkit jar.mn line pointing at the deleted file,
5
+ * failing every build at packaging. Split out of `doctor-furnace.ts` to keep
6
+ * that file within the line budget.
8
7
  */
9
8
  import { getFurnacePaths } from '../core/furnace-config.js';
10
9
  import { findStaleJarMnEntries, pruneStaleJarMnEntries } from '../core/furnace-registration.js';
@@ -12,10 +11,9 @@ import { toError } from '../utils/errors.js';
12
11
  import { failure, ok, warning } from './doctor-check-core.js';
13
12
  /**
14
13
  * "Furnace jar.mn registrations" check: detect widget registration lines
15
- * pointing at component files that no longer exist in the workspace
16
- * (typically left by a rename under an older FireForge). These break
17
- * `mach build` at packaging; `--repair-furnace` prunes them (0.34.0 field
18
- * report: doctor --repair-furnace reported success without pruning).
14
+ * pointing at component files that no longer exist in the workspace,
15
+ * typically left by a rename. These break `mach build` at packaging;
16
+ * `--repair-furnace` prunes them.
19
17
  */
20
18
  export const furnaceStaleJarRegistrationCheck = {
21
19
  name: 'Furnace jar.mn registrations',
@@ -4,15 +4,15 @@ import { join } from 'node:path';
4
4
  import { applyAllComponents } from '../core/furnace-apply.js';
5
5
  import { hasCustomEngineDrift, hasOverrideEngineDrift } from '../core/furnace-apply-helpers.js';
6
6
  import { getFurnacePaths, loadFurnaceConfig, loadFurnaceState, updateFurnaceState, } from '../core/furnace-config.js';
7
- import { CUSTOM_ELEMENTS_JS, JAR_MN, resolveFtlDir } from '../core/furnace-constants.js';
7
+ import { CUSTOM_ELEMENTS_JS, JAR_MN, resolveFtlDir, WIDGETS_DIR, } from '../core/furnace-constants.js';
8
8
  import { getFurnaceLockPath, runFurnaceMutation } from '../core/furnace-operation.js';
9
9
  import { hasBlockingStepErrors } from '../core/furnace-step-errors.js';
10
10
  import { validateAllComponents } from '../core/furnace-validate.js';
11
11
  import { isProcessAlive, toError } from '../utils/errors.js';
12
12
  import { pathExists } from '../utils/fs.js';
13
13
  import { failure, ok, warning } from './doctor-check-core.js';
14
+ import { furnaceConfigSyncCheck } from './doctor-furnace-config-sync.js';
14
15
  import { furnaceStaleJarRegistrationCheck } from './doctor-furnace-jar.js';
15
- import { furnaceManifestSyncCheck } from './doctor-furnace-manifest-sync.js';
16
16
  const ENGINE_REPAIRABLE_OPERATIONS = [
17
17
  'preview-teardown',
18
18
  'apply-rollback',
@@ -98,7 +98,7 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
98
98
  continue;
99
99
  }
100
100
  try {
101
- if (await hasOverrideEngineDrift(engineDir, componentDir, overrideConfig, ftlDir)) {
101
+ if (await hasOverrideEngineDrift({ engineDir, componentDir, ftlDir }, overrideConfig)) {
102
102
  drifted.push(name);
103
103
  }
104
104
  }
@@ -115,7 +115,7 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
115
115
  continue;
116
116
  }
117
117
  try {
118
- if (await hasCustomEngineDrift(projectRoot, name, componentDir, customConfig, ftlDir)) {
118
+ if (await hasCustomEngineDrift({ root: projectRoot, name, componentDir, ftlDir }, customConfig)) {
119
119
  drifted.push(name);
120
120
  }
121
121
  }
@@ -336,7 +336,7 @@ const furnaceEnginePathsCheck = {
336
336
  const expectedPaths = [
337
337
  CUSTOM_ELEMENTS_JS,
338
338
  JAR_MN,
339
- 'toolkit/content/widgets',
339
+ WIDGETS_DIR,
340
340
  resolveFtlDir(ctx.furnaceConfig?.ftlBasePath),
341
341
  ...hostDocs,
342
342
  ];
@@ -437,18 +437,17 @@ async function readFurnaceLockPid(lockPath) {
437
437
  }
438
438
  }
439
439
  /**
440
- * "Furnace stale lock" check: detect and (under `--repair-furnace`)
441
- * remove a `.fireforge/furnace.lock` directory whose owner process is no
442
- * longer alive.
440
+ * "Furnace stale lock" check: detect and (under `--repair-furnace`) remove a
441
+ * `.fireforge/furnace.lock` directory whose owner process is no longer
442
+ * alive.
443
443
  *
444
444
  * This is the recovery path when the signal-handler sweep
445
445
  * (`forceReleaseFurnaceLocksForActiveOperations` in `bin/fireforge.ts`)
446
- * misses — e.g. a SIGKILL'd process that never got to run the handler, or
447
- * a lock created by an older FireForge release without a PID file. The
448
- * motivating eval scenario: SIGINT'ing `furnace preview` left the lock
449
- * behind, and the next `fireforge test --build` timed out waiting for it.
450
- * `doctor --repair-furnace` now clears the lock explicitly so the next
451
- * command runs immediately.
446
+ * misses — a SIGKILL'd process that never ran the handler, or a lock created
447
+ * by an older FireForge release without a PID file. SIGINT'ing `furnace
448
+ * preview` leaves the lock behind, and the next `fireforge test --build`
449
+ * then times out waiting for it; `doctor --repair-furnace` clears it so the
450
+ * next command runs immediately.
452
451
  */
453
452
  const furnaceStaleLockCheck = {
454
453
  name: 'Furnace lock',
@@ -466,16 +465,14 @@ const furnaceStaleLockCheck = {
466
465
  // Two signals mark a lock as stale:
467
466
  // 1. PID file says owner is dead → unambiguous, remove immediately.
468
467
  // 2. PID file absent AND lock is older than 60s → older FireForge
469
- // releases (or an externally-created lock directory) fall into
470
- // this bucket; the age gate avoids false positives on a lock
471
- // that was just acquired by a concurrent process that hadn't
472
- // written its PID yet.
468
+ // releases (or an externally-created lock directory) fall into this
469
+ // bucket; the age gate avoids false positives on a lock just
470
+ // acquired by a concurrent process that has not written its PID yet.
473
471
  //
474
- // `isProcessAlive` treats EPERM as ALIVE. The local copy it replaced
475
- // returned false for EPERM, so a furnace lock held by a live process
476
- // owned by another uid was reported as "owner is no longer running"
477
- // and deleted by --repair-furnace, dropping mutual exclusion under a
478
- // concurrent furnace operation.
472
+ // `isProcessAlive` treats EPERM as ALIVE. Returning false for EPERM
473
+ // reports a furnace lock held by a live process owned by another uid as
474
+ // "owner is no longer running", and --repair-furnace then deletes it,
475
+ // dropping mutual exclusion under a concurrent furnace operation.
479
476
  const ownerDead = pid !== null && !isProcessAlive(pid);
480
477
  const pidMissingAndOld = pid === null && (ageMs ?? 0) > 60_000;
481
478
  const isStale = ownerDead || pidMissingAndOld;
@@ -513,5 +510,5 @@ export const FURNACE_DOCTOR_CHECKS = [
513
510
  furnaceStaleLockCheck,
514
511
  furnaceEngineStateCheck,
515
512
  furnaceComponentValidationCheck,
516
- furnaceManifestSyncCheck,
513
+ furnaceConfigSyncCheck,
517
514
  ];
@@ -1,23 +1,20 @@
1
1
  /**
2
- * Doctor check for PRE-EXISTING orphaned test-harness workers (0.37.0
3
- * item 9b).
2
+ * Doctor check for PRE-EXISTING orphaned test-harness workers.
4
3
  *
5
- * Field incident: a mach invocation that died at harness startup stranded a
6
- * Python 3.14 `multiprocessing` spawn worker plus its resource tracker; the
7
- * worker reparented to launchd (PPID 1) and busy-spun at 100% CPU for ~26
8
- * days (~415 CPU-hours) undetected. The dispatch-side fix is the
9
- * process-group reaping in `utils/process.ts`; this check covers orphans
10
- * that predate it (or leaked from non-FireForge invocations), using the
11
- * detection recipe that found the incident process: PPID 1 + large
12
- * accumulated CPU TIME + a `multiprocessing.spawn`/`resource_tracker`
13
- * command line.
4
+ * A mach invocation that dies at harness startup can strand a Python
5
+ * `multiprocessing` spawn worker plus its resource tracker; the worker
6
+ * reparents to launchd (PPID 1) and busy-spins at 100% CPU indefinitely.
7
+ * The dispatch-side fix is the process-group reaping in `utils/process.ts`;
8
+ * this check covers orphans that predate it (or leaked from non-FireForge
9
+ * invocations), detecting them by PPID 1 + large accumulated CPU TIME + a
10
+ * `multiprocessing.spawn`/`resource_tracker` command line.
14
11
  *
15
- * Report-only by design: FireForge never kills pre-existing processes it
16
- * did not spawn — the check names each candidate and suggests the kill.
12
+ * Report-only by design: FireForge never kills pre-existing processes it did
13
+ * not spawn — the check names each candidate and suggests the kill.
17
14
  *
18
- * Canary integration was deliberately skipped: the friction log asked for
19
- * doctor AND/OR `test --canary`, and adding a system-wide process scan to
20
- * the canary hot path buys no extra coverage over the doctor check.
15
+ * Deliberately not wired into `test --canary`: a system-wide process scan on
16
+ * the canary hot path buys no coverage the doctor check does not already
17
+ * give.
21
18
  */
22
19
  import type { DoctorCheckDefinition } from './doctor-check-core.js';
23
20
  /** One process matching the orphaned-harness-worker shape. */
@@ -31,10 +28,9 @@ export interface OrphanedHarnessWorker {
31
28
  command: string;
32
29
  }
33
30
  /**
34
- * Parses a `ps` TIME value in either dialect:
35
- * - linux `[dd-]hh:mm:ss` (e.g. `26-03:14:12`, `03:14:12`)
36
- * - darwin/BSD `mm:ss.cc` with cumulative minutes (e.g. `38412:07.55`)
37
- * Returns NaN for unrecognized shapes.
31
+ * Parses a `ps` TIME (accumulated CPU) value. Implemented in terms of
32
+ * {@link parsePsDuration} — `time=` and `etime=` share one grammar, and a
33
+ * second copy is how the two would drift.
38
34
  */
39
35
  export declare function parseCpuTime(time: string): number;
40
36
  /**
@@ -1,27 +1,25 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Doctor check for PRE-EXISTING orphaned test-harness workers (0.37.0
4
- * item 9b).
3
+ * Doctor check for PRE-EXISTING orphaned test-harness workers.
5
4
  *
6
- * Field incident: a mach invocation that died at harness startup stranded a
7
- * Python 3.14 `multiprocessing` spawn worker plus its resource tracker; the
8
- * worker reparented to launchd (PPID 1) and busy-spun at 100% CPU for ~26
9
- * days (~415 CPU-hours) undetected. The dispatch-side fix is the
10
- * process-group reaping in `utils/process.ts`; this check covers orphans
11
- * that predate it (or leaked from non-FireForge invocations), using the
12
- * detection recipe that found the incident process: PPID 1 + large
13
- * accumulated CPU TIME + a `multiprocessing.spawn`/`resource_tracker`
14
- * command line.
5
+ * A mach invocation that dies at harness startup can strand a Python
6
+ * `multiprocessing` spawn worker plus its resource tracker; the worker
7
+ * reparents to launchd (PPID 1) and busy-spins at 100% CPU indefinitely.
8
+ * The dispatch-side fix is the process-group reaping in `utils/process.ts`;
9
+ * this check covers orphans that predate it (or leaked from non-FireForge
10
+ * invocations), detecting them by PPID 1 + large accumulated CPU TIME + a
11
+ * `multiprocessing.spawn`/`resource_tracker` command line.
15
12
  *
16
- * Report-only by design: FireForge never kills pre-existing processes it
17
- * did not spawn — the check names each candidate and suggests the kill.
13
+ * Report-only by design: FireForge never kills pre-existing processes it did
14
+ * not spawn — the check names each candidate and suggests the kill.
18
15
  *
19
- * Canary integration was deliberately skipped: the friction log asked for
20
- * doctor AND/OR `test --canary`, and adding a system-wide process scan to
21
- * the canary hot path buys no extra coverage over the doctor check.
16
+ * Deliberately not wired into `test --canary`: a system-wide process scan on
17
+ * the canary hot path buys no coverage the doctor check does not already
18
+ * give.
22
19
  */
23
20
  import { toError } from '../utils/errors.js';
24
21
  import { exec } from '../utils/process.js';
22
+ import { parsePsDuration } from '../utils/ps-duration.js';
25
23
  import { ok, warning } from './doctor-check-core.js';
26
24
  /**
27
25
  * Command-line shapes of Python multiprocessing helper processes: the
@@ -32,36 +30,12 @@ const HARNESS_WORKER_COMMAND_PATTERN = /multiprocessing\.(?:spawn|forkserver)\b|
32
30
  /** Minimum accumulated CPU time before a match is reported (10 minutes). */
33
31
  const DEFAULT_MIN_CPU_SECONDS = 600;
34
32
  /**
35
- * Parses a `ps` TIME value in either dialect:
36
- * - linux `[dd-]hh:mm:ss` (e.g. `26-03:14:12`, `03:14:12`)
37
- * - darwin/BSD `mm:ss.cc` with cumulative minutes (e.g. `38412:07.55`)
38
- * Returns NaN for unrecognized shapes.
33
+ * Parses a `ps` TIME (accumulated CPU) value. Implemented in terms of
34
+ * {@link parsePsDuration} — `time=` and `etime=` share one grammar, and a
35
+ * second copy is how the two would drift.
39
36
  */
40
37
  export function parseCpuTime(time) {
41
- const trimmed = time.trim();
42
- let days = 0;
43
- let rest = trimmed;
44
- const dayMatch = /^(\d+)-(.*)$/.exec(trimmed);
45
- if (dayMatch) {
46
- days = Number(dayMatch[1]);
47
- rest = dayMatch[2] ?? '';
48
- }
49
- const parts = rest.split(':');
50
- if (parts.length === 3) {
51
- // hh:mm:ss (linux; seconds may not carry fractions but tolerate them)
52
- const [h, m, s] = parts.map(Number);
53
- if ([h, m, s].some((n) => Number.isNaN(n)))
54
- return NaN;
55
- return days * 86400 + (h ?? 0) * 3600 + (m ?? 0) * 60 + (s ?? 0);
56
- }
57
- if (parts.length === 2) {
58
- // mm:ss.cc (darwin — the minutes field accumulates without wrapping)
59
- const [m, s] = parts.map(Number);
60
- if ([m, s].some((n) => Number.isNaN(n)))
61
- return NaN;
62
- return days * 86400 + (m ?? 0) * 60 + (s ?? 0);
63
- }
64
- return NaN;
38
+ return parsePsDuration(time);
65
39
  }
66
40
  /**
67
41
  * Scans `ps -axo pid=,ppid=,time=,command=` output for orphaned harness
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The patch-manifest consistency check and its two repair paths, split out of
3
+ * `doctor.ts` for the line budget. Exports a single `DoctorCheckDefinition`
4
+ * consumed by the doctor registry; no registrar is exported and none is wanted.
5
+ */
6
+ import type { DoctorCheckDefinition } from './doctor-check-core.js';
7
+ /** Patch manifest consistency check, with its opt-in repair paths. */
8
+ export declare const PATCH_MANIFEST_CONSISTENCY_CHECK: DoctorCheckDefinition;
@@ -0,0 +1,155 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * The patch-manifest consistency check and its two repair paths, split out of
4
+ * `doctor.ts` for the line budget. Exports a single `DoctorCheckDefinition`
5
+ * consumed by the doctor registry; no registrar is exported and none is wanted.
6
+ */
7
+ import { rebuildPatchesManifest, recommendManifestRepair, repairPatchesFilesAffected, validatePatchesManifestConsistency, } from '../core/patch-manifest.js';
8
+ import { FireForgeError } from '../errors/base.js';
9
+ import { toError } from '../utils/errors.js';
10
+ import { pathExists } from '../utils/fs.js';
11
+ import { info, warn } from '../utils/logger.js';
12
+ import { resolveWaitLockSeconds } from '../utils/options.js';
13
+ import { failure, ok, warning } from './doctor-check-core.js';
14
+ const CHECK_NAME = 'Patch manifest consistency';
15
+ /** Runs the narrow `filesAffected` repair over the drifted rows. */
16
+ async function runFilesAffectedRepair(ctx, issues) {
17
+ const drifted = issues.filter((issue) => issue.code === 'files-affected-mismatch');
18
+ const otherCodes = [
19
+ ...new Set(issues.filter((issue) => issue.code !== 'files-affected-mismatch').map((issue) => issue.code)),
20
+ ].sort((left, right) => left.localeCompare(right));
21
+ if (drifted.length === 0) {
22
+ return failure(CHECK_NAME, `--repair-files-affected has nothing to repair: no filesAffected drift, but ${issues.length} ` +
23
+ `other issue(s) remain (${otherCodes.join(', ')}).`, recommendManifestRepair(issues));
24
+ }
25
+ const dryRun = ctx.options.dryRun === true;
26
+ const result = await repairPatchesFilesAffected(ctx.paths.patches, drifted.map((issue) => issue.filename), {
27
+ waitLockSeconds: resolveWaitLockSeconds(ctx.options.waitLock),
28
+ command: 'doctor --repair-files-affected',
29
+ dryRun,
30
+ });
31
+ for (const repair of result.repairs) {
32
+ info(` ${describeFilesAffectedRepair(repair, dryRun)}`);
33
+ }
34
+ for (const filename of result.skippedFilenames) {
35
+ warn(`Skipped ${filename}: it has no manifest row, or no patch file on disk. ` +
36
+ 'That is a different consistency issue — re-run doctor without --repair-files-affected ' +
37
+ 'to see it reported.');
38
+ }
39
+ if (result.written) {
40
+ ctx.mutations.push(`patches/patches.json — filesAffected corrected on ${describeCount(result.repairs.length)} (--repair-files-affected)`);
41
+ }
42
+ const remaining = otherCodes.length > 0
43
+ ? ` ${otherCodes.length} other issue type(s) remain: ${otherCodes.join(', ')}.`
44
+ : '';
45
+ if (otherCodes.length > 0) {
46
+ return failure(CHECK_NAME, `${summarizeFilesAffected(result.repairs.length, dryRun)}${remaining}`, recommendManifestRepair(issues.filter((issue) => issue.code !== 'files-affected-mismatch')));
47
+ }
48
+ return warning(CHECK_NAME, summarizeFilesAffected(result.repairs.length, dryRun));
49
+ }
50
+ function describeFilesAffectedRepair(repair, dryRun) {
51
+ const verb = dryRun ? 'would set' : 'set';
52
+ return `${repair.filename}: ${verb} filesAffected to ${repair.after.length} file(s) (was ${repair.before.length}).`;
53
+ }
54
+ function summarizeFilesAffected(count, dryRun) {
55
+ if (count === 0)
56
+ return 'No filesAffected drift to repair.';
57
+ return dryRun
58
+ ? `Dry run — would correct filesAffected on ${describeCount(count)}. Nothing was written.`
59
+ : `Corrected filesAffected on ${describeCount(count)}. No other manifest field was touched.`;
60
+ }
61
+ function describeCount(count) {
62
+ return `${count} patch${count === 1 ? '' : 'es'}`;
63
+ }
64
+ /** Runs the whole-manifest rebuild. */
65
+ async function runManifestRebuild(ctx) {
66
+ // Repair stamps sourceEsrVersion into every recovered entry. If the
67
+ // earlier "fireforge.json is valid" check failed, ctx.config is
68
+ // undefined and we must refuse rather than fabricate a fallback —
69
+ // persisting 'unknown' into manifest metadata is hard to reverse
70
+ // and would mislead every later command that reads it.
71
+ if (!ctx.config) {
72
+ return failure(CHECK_NAME, 'Cannot repair patches.json: fireforge.json could not be loaded, so the Firefox version to stamp into recovered manifest entries is unknown.', 'Fix the fireforge.json errors reported above and re-run "fireforge doctor --repair-patches-manifest". ' +
73
+ 'If the drift is only in filesAffected, "fireforge doctor --repair-files-affected" needs no config.');
74
+ }
75
+ const dryRun = ctx.options.dryRun === true;
76
+ const repaired = await rebuildPatchesManifest(ctx.paths.patches, ctx.config.firefox.version, {
77
+ waitLockSeconds: resolveWaitLockSeconds(ctx.options.waitLock),
78
+ command: 'doctor --repair-patches-manifest',
79
+ dryRun,
80
+ ...(ctx.options.allowMetadataLoss === true ? { allowMetadataLoss: true } : {}),
81
+ });
82
+ // The repair path must not silently overwrite human-written
83
+ // descriptions on recovered entries, which leaves the queue less
84
+ // trustworthy as an audit trail. The rebuilder returns the list of
85
+ // filenames whose metadata was entirely invented, named explicitly
86
+ // here so the operator knows which patches to review. Entries that
87
+ // WERE preserved (only `filesAffected` / ordering drifted) are not
88
+ // flagged.
89
+ for (const filename of repaired.recoveredFilenames) {
90
+ // Telling the operator to hand-edit patches.json contradicts the
91
+ // README and downstream docs, which treat the manifest as
92
+ // FireForge-owned. Point at the existing `re-export` / `export`
93
+ // workflow so the fix stays inside the tool: re-exporting the
94
+ // same files with an explicit `--description` overwrites the
95
+ // recovered entry with operator-supplied metadata and supersedes
96
+ // the mtime-based createdAt stamp.
97
+ warn(`Recovered manifest entry for ${filename} with generic description and mtime-based createdAt. ` +
98
+ 'Re-export the affected files with `fireforge re-export <filename> --description "<your description>"` ' +
99
+ '(or `fireforge export <paths...> --name <name> --category <category> --description "<your description>"`) ' +
100
+ 'to overwrite the reconstructed metadata, or accept the generic description if the original text is not recoverable. ' +
101
+ 'Avoid hand-editing patches.json — FireForge owns that file and will regenerate it on the next manifest consistency pass.');
102
+ }
103
+ // A row whose patch file is gone is dropped by the rebuild. That is
104
+ // correct — the patch file is the source of truth — but a manifest that
105
+ // quietly loses rows is exactly what makes a repair hard to audit
106
+ // afterwards, so each one is named.
107
+ for (const filename of repaired.droppedFilenames) {
108
+ warn(`Dropped the manifest entry for ${filename}: no such patch file on disk. ` +
109
+ 'Restore the .patch file and re-run the repair if the entry should have survived.');
110
+ }
111
+ if (repaired.written) {
112
+ ctx.mutations.push('patches/patches.json — rebuilt from the on-disk patch files (--repair-patches-manifest)');
113
+ }
114
+ const patchCount = repaired.manifest.patches.length;
115
+ const recovered = repaired.recoveredFilenames.length > 0
116
+ ? ` (${repaired.recoveredFilenames.length} with reconstructed metadata — see warnings above)`
117
+ : '';
118
+ return warning(CHECK_NAME, dryRun
119
+ ? `Dry run — would rebuild patches.json from ${describeCount(patchCount)}${recovered}. Nothing was written.`
120
+ : `Rebuilt patches.json from ${describeCount(patchCount)}${recovered}. Review recovered metadata before release.`);
121
+ }
122
+ /** Patch manifest consistency check, with its opt-in repair paths. */
123
+ export const PATCH_MANIFEST_CONSISTENCY_CHECK = {
124
+ name: CHECK_NAME,
125
+ dependsOn: ['fireforge.json is valid'],
126
+ run: async (ctx) => {
127
+ if (!(await pathExists(ctx.paths.patches))) {
128
+ return [];
129
+ }
130
+ const issues = await validatePatchesManifestConsistency(ctx.paths.patches);
131
+ if (issues.length === 0) {
132
+ return ok(CHECK_NAME);
133
+ }
134
+ const wantsFilesAffected = ctx.options.repairFilesAffected === true;
135
+ const wantsRebuild = ctx.options.repairPatchesManifest === true;
136
+ if (!wantsFilesAffected && !wantsRebuild) {
137
+ return failure(CHECK_NAME, issues.map((issue) => issue.message).join(' '), recommendManifestRepair(issues));
138
+ }
139
+ try {
140
+ return wantsFilesAffected
141
+ ? await runFilesAffectedRepair(ctx, issues)
142
+ : await runManifestRebuild(ctx);
143
+ }
144
+ catch (err) {
145
+ const error = toError(err);
146
+ // A refusal from the repair itself already carries the remedy that
147
+ // fits it (which flag, which file to fix). Appending the generic hint
148
+ // under it buries the specific one and reads as a second, vaguer
149
+ // instruction. Only an unexpected throw gets the generic hint.
150
+ return error instanceof FireForgeError
151
+ ? failure(CHECK_NAME, error.message)
152
+ : failure(CHECK_NAME, error.message, 'Repair failed. Fix the underlying patch metadata issue and retry the doctor command.');
153
+ }
154
+ },
155
+ };
@@ -0,0 +1,2 @@
1
+ import type { DoctorCheckDefinition } from './doctor-check-core.js';
2
+ export declare const POST_REBASE_AUDIT_CHECK: DoctorCheckDefinition;
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { readdir } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import { toError } from '../../utils/errors.js';
5
- import { pathExists, readText } from '../../utils/fs.js';
6
- import { ok, warning } from '../doctor-check-core.js';
4
+ import { toError } from '../utils/errors.js';
5
+ import { pathExists, readText } from '../utils/fs.js';
6
+ import { ok, warning } from './doctor-check-core.js';
7
7
  async function readEngineText(engineDir, relativePath) {
8
8
  const fullPath = join(engineDir, relativePath);
9
9
  if (!(await pathExists(fullPath)))
@@ -12,18 +12,16 @@
12
12
  import type { DoctorCheck } from '../types/commands/index.js';
13
13
  import type { DoctorCheckContext } from './doctor-check-core.js';
14
14
  /**
15
- * Inspects the engine working tree and returns a single
16
- * `DoctorCheck`. Ownership-aware: patch-backed / branding / furnace
17
- * rows are reported as OK with an ownership summary; unmanaged drift
18
- * warns; cross-patch conflicts warn loudly with a pointer at
19
- * `fireforge status --ownership` + `fireforge verify`.
15
+ * Inspects the engine working tree and returns a single `DoctorCheck`.
16
+ * Ownership-aware: patch-backed / branding / furnace rows are reported as OK
17
+ * with an ownership summary; unmanaged drift warns; cross-patch conflicts
18
+ * warn loudly with a pointer at `fireforge status --ownership` +
19
+ * `fireforge verify`.
20
20
  *
21
- * Before 0.16.1 this check warned on every dirty row regardless of
22
- * ownership and told the operator to export/discard/reset — advice
23
- * that was actively destructive on a patch-backed import (eval
24
- * Finding: a correctly imported 126-file patch stack was reported as
25
- * unhealthy and the suggested fix would have dropped the entire
26
- * import). Returns `undefined` when the worktree is clean so the
27
- * caller can emit its own ok() row.
21
+ * Ownership is what makes the advice safe: warning on every dirty row and
22
+ * telling the operator to export/discard/reset is actively destructive on a
23
+ * patch-backed import, where the suggested fix would drop the entire patch
24
+ * stack. Returns `undefined` when the worktree is clean so the caller can
25
+ * emit its own ok() row.
28
26
  */
29
27
  export declare function inspectEngineWorkingTree(ctx: DoctorCheckContext): Promise<DoctorCheck | undefined>;
@@ -28,19 +28,17 @@ function formatManagedDetail(counts) {
28
28
  .join(', ');
29
29
  }
30
30
  /**
31
- * Inspects the engine working tree and returns a single
32
- * `DoctorCheck`. Ownership-aware: patch-backed / branding / furnace
33
- * rows are reported as OK with an ownership summary; unmanaged drift
34
- * warns; cross-patch conflicts warn loudly with a pointer at
35
- * `fireforge status --ownership` + `fireforge verify`.
31
+ * Inspects the engine working tree and returns a single `DoctorCheck`.
32
+ * Ownership-aware: patch-backed / branding / furnace rows are reported as OK
33
+ * with an ownership summary; unmanaged drift warns; cross-patch conflicts
34
+ * warn loudly with a pointer at `fireforge status --ownership` +
35
+ * `fireforge verify`.
36
36
  *
37
- * Before 0.16.1 this check warned on every dirty row regardless of
38
- * ownership and told the operator to export/discard/reset — advice
39
- * that was actively destructive on a patch-backed import (eval
40
- * Finding: a correctly imported 126-file patch stack was reported as
41
- * unhealthy and the suggested fix would have dropped the entire
42
- * import). Returns `undefined` when the worktree is clean so the
43
- * caller can emit its own ok() row.
37
+ * Ownership is what makes the advice safe: warning on every dirty row and
38
+ * telling the operator to export/discard/reset is actively destructive on a
39
+ * patch-backed import, where the suggested fix would drop the entire patch
40
+ * stack. Returns `undefined` when the worktree is clean so the caller can
41
+ * emit its own ok() row.
44
42
  */
45
43
  export async function inspectEngineWorkingTree(ctx) {
46
44
  const { paths } = ctx;
@@ -82,12 +80,7 @@ export async function inspectEngineWorkingTree(ctx) {
82
80
  const managedTotal = counts.branding + counts.furnace + counts.patchBacked + counts.patchOwnedDrift;
83
81
  if (counts.unmanaged === 0) {
84
82
  const managedDetail = formatManagedDetail(counts);
85
- return {
86
- name: 'Engine working tree',
87
- passed: true,
88
- severity: 'ok',
89
- message: `${managedTotal} tool-managed change${managedTotal === 1 ? '' : 's'} (${managedDetail}), 0 unmanaged. Use "fireforge status --ownership" for details.`,
90
- };
83
+ return ok('Engine working tree', `${managedTotal} tool-managed change${managedTotal === 1 ? '' : 's'} (${managedDetail}), 0 unmanaged. Use "fireforge status --ownership" for details.`);
91
84
  }
92
85
  const managedTail = managedTotal > 0
93
86
  ? ` (${managedTotal} other change${managedTotal === 1 ? '' : 's'} are tool-managed: ${formatManagedDetail(counts)}).`
@@ -29,7 +29,7 @@ export declare const DOCTOR_CHECK_ORDER: readonly string[];
29
29
  * @param checks - The check results to display
30
30
  * @returns The exit code reflecting the overall result
31
31
  */
32
- export declare function reportDoctorResults(checks: DoctorCheck[]): ExitCode;
32
+ export declare function reportDoctorResults(checks: DoctorCheck[], mutations?: readonly string[]): ExitCode;
33
33
  /**
34
34
  * Result of the doctor command, carrying the exit code so the caller
35
35
  * (or test) can inspect it without relying on process.exitCode.