@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
@@ -15,7 +15,7 @@
15
15
  import { appendFile } from 'node:fs/promises';
16
16
  import { join } from 'node:path';
17
17
  import { confirm } from '@clack/prompts';
18
- import { InvalidArgumentError } from '../errors/base.js';
18
+ import { CancellationError, InvalidArgumentError } from '../errors/base.js';
19
19
  import { ensureDir } from '../utils/fs.js';
20
20
  import { info, isCancel, warn } from '../utils/logger.js';
21
21
  /** Filename of the audit log, relative to the patches directory. */
@@ -40,16 +40,20 @@ function printConflicts(conflicts) {
40
40
  }
41
41
  }
42
42
  /**
43
- * True when BOTH standard handles are real TTYs, i.e. a `confirm()` prompt
43
+ * True when BOTH standard handles are real TTYs, i.e. an interactive prompt
44
44
  * can actually be answered.
45
45
  *
46
+ * Named for the condition rather than for confirmation specifically: many
47
+ * call sites gate a `text()` / `multiselect()` input prompt or a mode
48
+ * switch, not a destructive confirmation.
49
+ *
46
50
  * Node types `isTTY` as `boolean`, but at runtime it is `true | undefined`
47
51
  * (absent when the handle is not a TTY). Unusual harnesses (vitest stdio
48
52
  * capture, CI spawners, mocked pipes) can also leave it unset on only one
49
53
  * handle, so every falsy variant — false, undefined, a null-patched mock —
50
54
  * must route to the non-interactive path.
51
55
  */
52
- function confirmationIsAnswerable() {
56
+ export function stdioIsInteractive() {
53
57
  const stdinIsTTY = process.stdin.isTTY;
54
58
  const stdoutIsTTY = process.stdout.isTTY;
55
59
  return stdinIsTTY === true && stdoutIsTTY === true;
@@ -64,8 +68,7 @@ function confirmationIsAnswerable() {
64
68
  * --create` that is minutes of work before a scripted run learns it needed
65
69
  * `--yes`, and the failure reads as an obscure late error rather than a
66
70
  * usage problem. Calling this at command entry turns it into a usage
67
- * refusal that names the flag, in the same shape as the 0.41.0
68
- * `move-files --create` / `--description` refusal.
71
+ * refusal that names the flag.
69
72
  *
70
73
  * A `--yes` or `--dry-run` run never prompts, so neither is refused.
71
74
  *
@@ -76,7 +79,7 @@ function confirmationIsAnswerable() {
76
79
  export function assertConfirmationAvailable(operation, options) {
77
80
  if (options.yes === true || options.dryRun === true)
78
81
  return;
79
- if (confirmationIsAnswerable())
82
+ if (stdioIsInteractive())
80
83
  return;
81
84
  throw new InvalidArgumentError(`"${operation}" ends in an interactive confirmation, but this run has no TTY to answer it ` +
82
85
  '(stdin/stdout are not both terminals). Re-run with --yes to confirm non-interactively ' +
@@ -87,14 +90,14 @@ export function assertConfirmationAvailable(operation, options) {
87
90
  * Executes the destructive-operation contract: summary → conflict refusal →
88
91
  * dry-run / force / prompt / non-TTY refusal.
89
92
  *
90
- * Returns the decision for the caller to act on; callers must not execute the
91
- * mutation when the result is `'dry-run'` or `'cancelled'`, and must call
92
- * {@link appendHistory} only after the mutation succeeds (never on dry-run or
93
- * cancellation).
93
+ * Returns the decision for the caller to act on; callers must not execute
94
+ * the mutation when the result is `'dry-run'` or `'declined'`, and must call
95
+ * {@link appendHistory} only after the mutation succeeds (never on dry-run
96
+ * or decline).
94
97
  *
95
98
  * @param input - Operation description, flags, and optional conflict report
96
99
  * @returns `'proceed'` to execute, `'dry-run'` to skip execution, or
97
- * `'cancelled'` when the user declined the prompt
100
+ * `'declined'` when the user declined the prompt
98
101
  */
99
102
  export async function confirmDestructive(input) {
100
103
  const { operation, title, summary, yes, dryRun, unsafeOverride, conflicts } = input;
@@ -129,31 +132,31 @@ export async function confirmDestructive(input) {
129
132
  printSummary(title, summary);
130
133
  return 'proceed';
131
134
  }
132
- // Non-TTY without --yes: refuse with a clear message pointing at --yes.
133
- // Never silently proceed.
134
- // Node types `isTTY` as `boolean`, but at runtime it is `true | undefined`
135
- // (absent when the handle is not a TTY). Unusual harnesses (vitest stdio
136
- // capture, CI spawners, mocked pipes) can also leave it unset on only
137
- // one handle. We cast to the real runtime type and compare against
138
- // literal `true` so any falsy variant — false, undefined, or a
139
- // null-patched mock — routes to the non-interactive path.
140
- if (!confirmationIsAnswerable()) {
135
+ // Non-TTY without --yes: refuse with a message pointing at --yes rather
136
+ // than silently proceeding.
137
+ if (!stdioIsInteractive()) {
141
138
  printSummary(title, summary);
142
139
  throw new InvalidArgumentError(`Interactive confirmation not available for "${operation}". ` +
143
140
  'Use --yes to run non-interactively (required for CI).', '--yes');
144
141
  }
145
142
  // Interactive path: print the summary first so the user sees the full
146
- // picture, then prompt. Cancellation and negative answer both map to
147
- // 'cancelled' so the caller can return without running anything.
143
+ // picture, then prompt.
148
144
  printSummary(title, summary);
149
145
  const confirmed = await confirm({
150
146
  message: `${title} — proceed?`,
151
147
  initialValue: false,
152
148
  });
153
- // `isCancel` narrows the clack sentinel away, leaving a plain boolean —
154
- // the defensive `!== true` this replaced is now provably redundant.
155
- if (isCancel(confirmed) || !confirmed) {
156
- return 'cancelled';
149
+ // An INTERRUPT and a "no" are different outcomes and must not share an
150
+ // exit code. Esc / Ctrl+C is a real interrupt — 130 is 128+SIGINT and is
151
+ // what a script needs to tell "the operator aborted" from "the operator
152
+ // considered it and declined". Answering "no" is a successful run.
153
+ //
154
+ // `isCancel` narrows the clack sentinel away, leaving a plain boolean.
155
+ if (isCancel(confirmed)) {
156
+ throw new CancellationError();
157
+ }
158
+ if (!confirmed) {
159
+ return 'declined';
157
160
  }
158
161
  return 'proceed';
159
162
  }
@@ -1,12 +1,11 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { assert, expectDefined } from '../utils/assert.js';
3
3
  /**
4
- * Maximum combined LCS table side-length before we bail out of the exact
5
- * O(m·n) diff and fall back to the simpler single-region coalesce. Chosen so
6
- * the worst-case Int32Array allocation stays under ~16 MB. Typical Firefox
7
- * widget files are a few hundred lines, so the fast path handles the
8
- * everyday case; the fallback exists purely to keep the command usable if
9
- * someone overrides a very large file.
4
+ * Maximum combined LCS table side-length before bailing out of the exact
5
+ * O(m·n) diff and falling back to the simpler single-region coalesce. Chosen
6
+ * so the worst-case Int32Array allocation stays under ~16 MB. Typical
7
+ * Firefox widget files are a few hundred lines, so the fast path handles the
8
+ * everyday case; the fallback keeps the command usable on a very large file.
10
9
  */
11
10
  const LCS_LINE_LIMIT = 2000;
12
11
  /** Splits a string on `\n`, discarding a single trailing empty line from a terminal newline. */
@@ -219,12 +218,11 @@ function coalescedHunk(oldLines, newLines, context) {
219
218
  for (let k = firstDiff; k <= lastNewDiff; k++) {
220
219
  hunkLines.push({ marker: '+', content: expectDefined(newLines[k], () => `new line ${k}`) });
221
220
  }
222
- // Trailing context comes from the common suffix, which lives at
223
- // DIFFERENT indices on each side (lastOldDiff+1… vs lastNewDiff+1…).
224
- // The previous mixed-coordinate loop (max() of both sides indexing
225
- // newLines) emitted wrong context on asymmetric edits, and the trailing
226
- // lines were excluded from the @@ header lengths entirely — so on
227
- // >LCS_LINE_LIMIT files the rendered header disagreed with the body.
221
+ // Trailing context comes from the common suffix, which lives at DIFFERENT
222
+ // indices on each side (lastOldDiff+1… vs lastNewDiff+1…). Mixing the two
223
+ // coordinate spaces emits wrong context on asymmetric edits and drops the
224
+ // trailing lines from the @@ header lengths, so the rendered header
225
+ // disagrees with the body.
228
226
  for (let k = lastNewDiff + 1; k <= contextEndNew; k++) {
229
227
  hunkLines.push({ marker: ' ', content: expectDefined(newLines[k], () => `new line ${k}`) });
230
228
  }
@@ -1,18 +1,18 @@
1
1
  /**
2
- * Patch-aware restore planning for `fireforge discard` (P0).
2
+ * Patch-aware restore planning for `fireforge discard`.
3
3
  *
4
4
  * The engine convention is: HEAD = pristine upstream Firefox, and the
5
5
  * applied patch queue lives as UNCOMMITTED worktree changes on top of it
6
6
  * (`git apply` without `--index` → patch-edited tracked files are unstaged
7
- * modifications, patch-created files are untracked). The pre-0.39.0
8
- * `discard` was purely git-mechanical — it restored to HEAD and deleted
9
- * untracked files, silently reverting patch-backed files PAST their owning
10
- * patch and deleting patch-created files outright.
7
+ * modifications, patch-created files are untracked). A purely git-mechanical
8
+ * discard — restore to HEAD, delete untracked files — therefore reverts
9
+ * patch-backed files PAST their owning patch and deletes patch-created files
10
+ * outright.
11
11
  *
12
12
  * This module classifies each status entry against the patch manifest's
13
13
  * ownership claims and plans the correct restore target: the PATCH-APPLIED
14
14
  * baseline (HEAD content folded through every affecting patch in order) for
15
- * claimed files, and the legacy git mechanics for unmanaged ones.
15
+ * claimed files, and the plain git mechanics for unmanaged ones.
16
16
  */
17
17
  import type { GitStatusEntry } from './git-base.js';
18
18
  /** How one status entry's canonical path will be restored. */
@@ -35,8 +35,8 @@ export declare function planUpstreamDiscards(entries: readonly GitStatusEntry[])
35
35
  /**
36
36
  * Plans the restore target for each status entry. Entries claimed by the
37
37
  * patch manifest restore to the patch-applied baseline; unclaimed entries
38
- * keep the legacy git mechanics. A missing patches dir or empty manifest
39
- * degrades every plan to `unmanaged` (identical to pre-0.39.0 behavior).
38
+ * keep the plain git mechanics. A missing patches dir or empty manifest
39
+ * degrades every plan to `unmanaged`.
40
40
  *
41
41
  * A corrupt manifest or an unreconstructible patch baseline REFUSES with a
42
42
  * GeneralError naming `--to-upstream` — silently falling back to pristine
@@ -1,19 +1,19 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Patch-aware restore planning for `fireforge discard` (P0).
3
+ * Patch-aware restore planning for `fireforge discard`.
4
4
  *
5
5
  * The engine convention is: HEAD = pristine upstream Firefox, and the
6
6
  * applied patch queue lives as UNCOMMITTED worktree changes on top of it
7
7
  * (`git apply` without `--index` → patch-edited tracked files are unstaged
8
- * modifications, patch-created files are untracked). The pre-0.39.0
9
- * `discard` was purely git-mechanical — it restored to HEAD and deleted
10
- * untracked files, silently reverting patch-backed files PAST their owning
11
- * patch and deleting patch-created files outright.
8
+ * modifications, patch-created files are untracked). A purely git-mechanical
9
+ * discard — restore to HEAD, delete untracked files — therefore reverts
10
+ * patch-backed files PAST their owning patch and deletes patch-created files
11
+ * outright.
12
12
  *
13
13
  * This module classifies each status entry against the patch manifest's
14
14
  * ownership claims and plans the correct restore target: the PATCH-APPLIED
15
15
  * baseline (HEAD content folded through every affecting patch in order) for
16
- * claimed files, and the legacy git mechanics for unmanaged ones.
16
+ * claimed files, and the plain git mechanics for unmanaged ones.
17
17
  */
18
18
  import { join } from 'node:path';
19
19
  import { GeneralError } from '../errors/base.js';
@@ -31,8 +31,8 @@ export function planUpstreamDiscards(entries) {
31
31
  /**
32
32
  * Plans the restore target for each status entry. Entries claimed by the
33
33
  * patch manifest restore to the patch-applied baseline; unclaimed entries
34
- * keep the legacy git mechanics. A missing patches dir or empty manifest
35
- * degrades every plan to `unmanaged` (identical to pre-0.39.0 behavior).
34
+ * keep the plain git mechanics. A missing patches dir or empty manifest
35
+ * degrades every plan to `unmanaged`.
36
36
  *
37
37
  * A corrupt manifest or an unreconstructible patch baseline REFUSES with a
38
38
  * GeneralError naming `--to-upstream` — silently falling back to pristine
@@ -85,17 +85,18 @@ export async function planDiscardBaselines(patchesDir, engineDir, entries) {
85
85
  sections = parseDiffSections(await readText(join(patchesDir, owner)));
86
86
  }
87
87
  catch (error) {
88
- // Fail closed. Swallowing this yielded no sections, which falls
88
+ // Fail closed. Swallowing this yields no sections, which falls
89
89
  // through to `return false` — "not deleted at baseline" — so a path
90
90
  // the owning patch DELETES would be restored as present, i.e.
91
91
  // rewritten instead of removed: silent data loss on the command
92
- // whose header promises a refusal for exactly this class of failure.
92
+ // whose header promises a refusal for exactly this class of
93
+ // failure.
93
94
  //
94
- // In the current flow `computeExpected` above reads the same patch
95
- // first and refuses, so this is defence-in-depth against a TOCTOU
96
- // (the patch file removed or made unreadable mid-plan) rather than a
97
- // reachable branch today. It refuses with the same remediation as
98
- // its sibling so the two cannot drift into disagreeing.
95
+ // `computeExpected` above reads the same patch first and refuses,
96
+ // so this is defence-in-depth against a TOCTOU (the patch file
97
+ // removed or made unreadable mid-plan) rather than a reachable
98
+ // branch today. It uses the same remediation as its sibling so the
99
+ // two cannot drift into disagreeing.
99
100
  throw new GeneralError(`Cannot read the owning patch ${owner} to determine the baseline for ${path} ` +
100
101
  `(${toError(error).message}). ` +
101
102
  'Fix the owning patch, or pass --to-upstream to explicitly revert to pristine ' +
@@ -2,21 +2,20 @@
2
2
  * macOS display power-state probe for the headed no-output stall.
3
3
  *
4
4
  * `TIMEOUT … application timed out after N seconds with no output` /
5
- * `Ran 0 checks` has three recorded causes, and one of them is purely
6
- * environmental: a HEADED run on an unattended machine whose display is
7
- * asleep or locked. A headed Firefox on a sleeping display never paints,
8
- * never reaches its first test, and dies at the no-output timeout —
9
- * indistinguishable, from the log alone, from a product hang.
5
+ * `Ran 0 checks` has three known causes, one of them purely environmental:
6
+ * a HEADED run on an unattended machine whose display is asleep or locked.
7
+ * A headed Firefox on a sleeping display never paints, never reaches its
8
+ * first test, and dies at the no-output timeout — indistinguishable, from
9
+ * the log alone, from a product hang.
10
10
  *
11
11
  * `caffeinate -disu` does not cure it. It PREVENTS sleep; it cannot WAKE a
12
12
  * display that is already asleep, so wrapping the run changes nothing once
13
- * the machine has already dimmed. `fireforge test` defaults to headed, so
14
- * an unattended run walks straight into this and the operator burns whole
15
- * cycles hunting a product cause.
13
+ * the machine has dimmed. `fireforge test` defaults to headed, so an
14
+ * unattended run walks straight into this.
16
15
  *
17
16
  * The probe is advisory and fail-open: anything unexpected reports
18
- * `'unknown'` and the caller degrades to the generic triage list rather
19
- * than asserting an environment it could not measure.
17
+ * `'unknown'` and the caller degrades to the generic triage list rather than
18
+ * asserting an environment it could not measure.
20
19
  */
21
20
  /** Measured display power state, or `'unknown'` when nothing was measured. */
22
21
  export type DisplaySleepState = 'asleep' | 'awake' | 'unknown';
@@ -41,10 +40,9 @@ export type DisplaySleepState = 'asleep' | 'awake' | 'unknown';
41
40
  */
42
41
  export declare function parseDisplayPowerState(stdout: string): DisplaySleepState;
43
42
  /**
44
- * Probes the display's power state. Non-darwin platforms report
45
- * `'unknown'` without spawning anything — the stall shape this serves is
46
- * a macOS field report and no equivalent single-command probe is wired for
47
- * other platforms.
43
+ * Probes the display's power state. Non-darwin platforms report `'unknown'`
44
+ * without spawning anything — the stall shape this serves is macOS-specific
45
+ * and no equivalent single-command probe is wired for other platforms.
48
46
  *
49
47
  * @param platform - `process.platform`-style id (injected for testability)
50
48
  * @returns The measured state, or `'unknown'` when unmeasurable
@@ -3,21 +3,20 @@
3
3
  * macOS display power-state probe for the headed no-output stall.
4
4
  *
5
5
  * `TIMEOUT … application timed out after N seconds with no output` /
6
- * `Ran 0 checks` has three recorded causes, and one of them is purely
7
- * environmental: a HEADED run on an unattended machine whose display is
8
- * asleep or locked. A headed Firefox on a sleeping display never paints,
9
- * never reaches its first test, and dies at the no-output timeout —
10
- * indistinguishable, from the log alone, from a product hang.
6
+ * `Ran 0 checks` has three known causes, one of them purely environmental:
7
+ * a HEADED run on an unattended machine whose display is asleep or locked.
8
+ * A headed Firefox on a sleeping display never paints, never reaches its
9
+ * first test, and dies at the no-output timeout — indistinguishable, from
10
+ * the log alone, from a product hang.
11
11
  *
12
12
  * `caffeinate -disu` does not cure it. It PREVENTS sleep; it cannot WAKE a
13
13
  * display that is already asleep, so wrapping the run changes nothing once
14
- * the machine has already dimmed. `fireforge test` defaults to headed, so
15
- * an unattended run walks straight into this and the operator burns whole
16
- * cycles hunting a product cause.
14
+ * the machine has dimmed. `fireforge test` defaults to headed, so an
15
+ * unattended run walks straight into this.
17
16
  *
18
17
  * The probe is advisory and fail-open: anything unexpected reports
19
- * `'unknown'` and the caller degrades to the generic triage list rather
20
- * than asserting an environment it could not measure.
18
+ * `'unknown'` and the caller degrades to the generic triage list rather than
19
+ * asserting an environment it could not measure.
21
20
  */
22
21
  import { toError } from '../utils/errors.js';
23
22
  import { verbose } from '../utils/logger.js';
@@ -61,10 +60,9 @@ export function parseDisplayPowerState(stdout) {
61
60
  return 'unknown';
62
61
  }
63
62
  /**
64
- * Probes the display's power state. Non-darwin platforms report
65
- * `'unknown'` without spawning anything — the stall shape this serves is
66
- * a macOS field report and no equivalent single-command probe is wired for
67
- * other platforms.
63
+ * Probes the display's power state. Non-darwin platforms report `'unknown'`
64
+ * without spawning anything — the stall shape this serves is macOS-specific
65
+ * and no equivalent single-command probe is wired for other platforms.
68
66
  *
69
67
  * @param platform - `process.platform`-style id (injected for testability)
70
68
  * @returns The measured state, or `'unknown'` when unmeasurable
@@ -1,9 +1,7 @@
1
1
  /**
2
2
  * Shared collector for "what changed in the engine tree since the last
3
- * successful build". Three preflight/audit paths previously carried their
4
- * own copy of this logic (`build-audit`, `build-prepare`,
5
- * `test-stale-check`), differing only in the verbose-log label; they all
6
- * call this module now.
3
+ * successful build", used by `build-audit`, `build-prepare` and
4
+ * `test-stale-check`.
7
5
  */
8
6
  import type { BuildBaseline } from './build-baseline-types.js';
9
7
  /**
@@ -1,10 +1,8 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
3
  * Shared collector for "what changed in the engine tree since the last
4
- * successful build". Three preflight/audit paths previously carried their
5
- * own copy of this logic (`build-audit`, `build-prepare`,
6
- * `test-stale-check`), differing only in the verbose-log label; they all
7
- * call this module now.
4
+ * successful build", used by `build-audit`, `build-prepare` and
5
+ * `test-stale-check`.
8
6
  */
9
7
  import { toError } from '../utils/errors.js';
10
8
  import { verbose } from '../utils/logger.js';
@@ -2,28 +2,43 @@
2
2
  * Shared engine precondition ladder for commands that read or mutate
3
3
  * `engine/` through git.
4
4
  *
5
- * Five commands carried their own copy of this three-rung check, and **two of
6
- * them were truncated**: `resolve.ts` and `token-coverage.ts` stopped after
7
- * the `isGitRepository` rung and omitted the unborn-HEAD guard entirely
8
- * (neither even imported `getHead`/`isMissingHeadError`). Both then went on to
9
- * enumerate working-tree status, and against an unborn HEAD the whole
10
- * ~300k-file Firefox tree reads as untracked — so an engine left half
11
- * initialised by an interrupted `download` produced a nonsensical result
12
- * rather than the actionable refusal the other three commands gave.
5
+ * The rungs matter in order. Skipping the unborn-HEAD guard and going
6
+ * straight to enumerating working-tree status makes the whole ~300k-file
7
+ * Firefox tree read as untracked, so an engine left half-initialised by an
8
+ * interrupted `download` produces a nonsensical result instead of an
9
+ * actionable refusal.
13
10
  *
14
- * The remediation paragraph also existed in three independently-editable
15
- * copies that had already drifted. It lives here once now.
11
+ * The remediation wording lives here once so the callers cannot drift apart.
16
12
  */
17
13
  /** Options for {@link assertEngineGitReady}. */
18
14
  export interface EngineGitReadyOptions {
19
15
  /**
20
16
  * Appended to the unborn-HEAD remediation, e.g. `', then retry the rebase.'`
21
- * Preserves the one deliberate wording divergence between the copies. The
22
- * base message deliberately ends WITHOUT punctuation so the suffix reads as
23
- * one sentence; callers that pass nothing get a plain full stop.
17
+ * The base message deliberately ends WITHOUT punctuation so the suffix
18
+ * reads as one sentence; callers that pass nothing get a plain full stop.
24
19
  */
25
20
  unbornHeadSuffix?: string;
26
21
  }
22
+ /**
23
+ * Error factory for callers whose domain uses a class other than
24
+ * `GeneralError`. The furnace family raises `FurnaceError`, which carries
25
+ * its own `userMessage` and exit code 9, so a helper hardcoding
26
+ * `GeneralError` would silently change both.
27
+ */
28
+ export type PreconditionErrorFactory = (message: string) => Error;
29
+ /**
30
+ * Asserts only that the engine checkout EXISTS.
31
+ *
32
+ * The first rung of {@link assertEngineGitReady}. Most callers want exactly
33
+ * this rung and no more: `build`, `run`, `test`, `package`, `watch`,
34
+ * `import` and `bootstrap` never run git against the engine and each has its
35
+ * own richer follow-up gate, so promoting them to the full three-rung ladder
36
+ * would refuse runs that work today.
37
+ *
38
+ * @param engineDir - Absolute path to the engine checkout
39
+ * @param errorFactory - Optional domain-specific error constructor
40
+ */
41
+ export declare function assertEngineExists(engineDir: string, errorFactory?: PreconditionErrorFactory): Promise<void>;
27
42
  /**
28
43
  * Asserts that `engineDir` exists, is a git repository, and has a baseline
29
44
  * commit — in that order, so the operator gets the most specific applicable
@@ -3,17 +3,13 @@
3
3
  * Shared engine precondition ladder for commands that read or mutate
4
4
  * `engine/` through git.
5
5
  *
6
- * Five commands carried their own copy of this three-rung check, and **two of
7
- * them were truncated**: `resolve.ts` and `token-coverage.ts` stopped after
8
- * the `isGitRepository` rung and omitted the unborn-HEAD guard entirely
9
- * (neither even imported `getHead`/`isMissingHeadError`). Both then went on to
10
- * enumerate working-tree status, and against an unborn HEAD the whole
11
- * ~300k-file Firefox tree reads as untracked — so an engine left half
12
- * initialised by an interrupted `download` produced a nonsensical result
13
- * rather than the actionable refusal the other three commands gave.
6
+ * The rungs matter in order. Skipping the unborn-HEAD guard and going
7
+ * straight to enumerating working-tree status makes the whole ~300k-file
8
+ * Firefox tree read as untracked, so an engine left half-initialised by an
9
+ * interrupted `download` produces a nonsensical result instead of an
10
+ * actionable refusal.
14
11
  *
15
- * The remediation paragraph also existed in three independently-editable
16
- * copies that had already drifted. It lives here once now.
12
+ * The remediation wording lives here once so the callers cannot drift apart.
17
13
  */
18
14
  import { GeneralError } from '../errors/base.js';
19
15
  import { pathExists } from '../utils/fs.js';
@@ -24,6 +20,25 @@ const UNBORN_HEAD_REMEDIATION = 'Engine repository has no baseline commit yet
24
20
  // No terminating period: the suffix below supplies its own punctuation, and
25
21
  // hardcoding one here rendered as "…cleanly., then retry the rebase."
26
22
  'Re-run "fireforge download --force" to recreate the baseline repository cleanly';
23
+ /** Default factory: the message every non-furnace command already used. */
24
+ const defaultErrorFactory = (message) => new GeneralError(message);
25
+ /**
26
+ * Asserts only that the engine checkout EXISTS.
27
+ *
28
+ * The first rung of {@link assertEngineGitReady}. Most callers want exactly
29
+ * this rung and no more: `build`, `run`, `test`, `package`, `watch`,
30
+ * `import` and `bootstrap` never run git against the engine and each has its
31
+ * own richer follow-up gate, so promoting them to the full three-rung ladder
32
+ * would refuse runs that work today.
33
+ *
34
+ * @param engineDir - Absolute path to the engine checkout
35
+ * @param errorFactory - Optional domain-specific error constructor
36
+ */
37
+ export async function assertEngineExists(engineDir, errorFactory = defaultErrorFactory) {
38
+ if (!(await pathExists(engineDir))) {
39
+ throw errorFactory('Firefox source not found. Run "fireforge download" first.');
40
+ }
41
+ }
27
42
  /**
28
43
  * Asserts that `engineDir` exists, is a git repository, and has a baseline
29
44
  * commit — in that order, so the operator gets the most specific applicable
@@ -2,12 +2,22 @@ import { type LockStatusSnapshot } from './file-lock.js';
2
2
  export interface EngineSessionLockOptions {
3
3
  /**
4
4
  * Wait up to this many seconds for the engine session lock instead of the
5
- * legacy ~1 s fail-fast. Enables exponential poll backoff (100 ms → 2 s)
6
- * and a holder-identified progress line roughly every 5 s. `undefined`
7
- * preserves the historical fail-fast behavior exactly.
5
+ * ~1 s fail-fast. Enables exponential poll backoff (100 ms → 2 s) and a
6
+ * holder-identified progress line roughly every 5 s. `undefined` keeps the
7
+ * fail-fast behaviour.
8
8
  */
9
9
  waitLockSeconds?: number | undefined;
10
10
  }
11
+ /**
12
+ * Formats the notice printed when the wait budget is EXTENDED because the
13
+ * queue advanced.
14
+ *
15
+ * Exported for direct unit testing. It names both figures — the requested
16
+ * budget and the one now in force — because the whole point is that the two
17
+ * have diverged, and an operator comparing the elapsed time against the
18
+ * number they typed would otherwise conclude the timeout is broken.
19
+ */
20
+ export declare function formatWaitExtendedLine(ahead: number, budgetMs: number, requestedMs: number): string;
11
21
  /**
12
22
  * Runs `operation` while holding the project's engine-session lock, so only
13
23
  * one engine-mutating FireForge command touches `engine/` at a time.
@@ -25,7 +35,7 @@ export declare function readEngineSessionLockStatus(projectRoot: string): Promis
25
35
  * Renders the engine-session lock snapshot as operator-facing lines.
26
36
  * Pure, so the wording is unit-testable without a lock on disk.
27
37
  */
28
- export declare function formatEngineSessionLockStatus(snapshot: LockStatusSnapshot): string[];
38
+ export declare function formatEngineSessionLockStatus(snapshot: LockStatusSnapshot, holderCpuSeconds?: number): string[];
29
39
  /**
30
40
  * Captures an opaque token describing the engine's current commit and working
31
41
  * tree, for comparison by {@link assertEngineGenerationUnchanged}.
@@ -49,30 +59,46 @@ export declare function isIndexLockError(error: unknown): boolean;
49
59
  export declare function isUnavailableGenerationToken(token: string): boolean;
50
60
  /** Strips the marker prefix off an unavailable token for display. */
51
61
  export declare function unavailableGenerationReason(token: string): string;
62
+ /**
63
+ * Describes what moved between two generation tokens, in operator terms.
64
+ *
65
+ * The refusal used to say only THAT the engine changed, which left the
66
+ * operator to reconstruct the writer by hand — `find -newermt` against the
67
+ * run window, minus the objdir, minus git's own bookkeeping. Everything
68
+ * needed to answer it is already in the two tokens, so the refusal answers
69
+ * it. Pure and total: an unparseable token yields an empty list rather than
70
+ * an exception, because a diagnostic must never convert a refusal into a
71
+ * crash.
72
+ *
73
+ * @param before - Token captured before the run
74
+ * @param after - Token captured after the run
75
+ * @returns Human-readable lines describing the delta; empty when nothing
76
+ * could be attributed
77
+ */
78
+ export declare function describeEngineGenerationDelta(before: string, after: string): string[];
52
79
  /**
53
80
  * Throws when the engine's generation token differs from `before`, i.e. the
54
81
  * engine was mutated by another writer while a test run was in flight.
55
82
  *
56
- * **An unmeasurable engine warns rather than throws.** `engine/` is not always
57
- * a git checkout — `fireforge download` extracts a source tarball — so a
58
- * failed probe is a legitimate state and must not fail the run.
83
+ * **An unmeasurable engine warns rather than throws.** `engine/` is not
84
+ * always a git checkout — `fireforge download` extracts a source tarball —
85
+ * so a failed probe is a legitimate state and must not fail the run.
59
86
  *
60
- * What it must also not do is pass *silently*. Before 0.41.0 the failure token
61
- * was `unavailable:<message>` and was compared for equality like any other, so
62
- * a git failure that reproduced across both probes (unreadable `.git`, a
63
- * permissions problem, a corrupt index) produced identical tokens, took the
64
- * `after === before` early return, and blessed a verdict the guard had never
65
- * verified — the precise outcome this guard exists to prevent. Two *differing*
66
- * failure messages were worse still: they fell through to the mutation branch
67
- * and reported a spurious "engine/ changed".
87
+ * What it must also not do is pass *silently*. A failure token compared for
88
+ * equality like any other would let a git failure that reproduces across
89
+ * both probes (unreadable `.git`, a permissions problem, a corrupt index)
90
+ * take the `after === before` early return and bless a verdict the guard
91
+ * never verified. Two *differing* failure messages are worse still: they
92
+ * fall through to the mutation branch and report a spurious
93
+ * "engine/ changed". Hence the prefix comparison rather than a token
94
+ * comparison — the token embeds the error message, and two genuine failures
95
+ * rarely phrase it identically.
68
96
  *
69
97
  * The tolerance is deliberately limited to a probe that failed *both* times:
70
98
  * that is the steady state of a non-git `engine/`, and it warns. A one-sided
71
- * transition is not that state. `engine/` that was measurable and then was not
72
- * means the second probe measured nothing about a checkout that demonstrably
73
- * had something to measure; the reverse means there was never a baseline to
74
- * compare against. Neither is a run whose verdict can be trusted, so both
75
- * throw. Compare on the prefix rather than the token, because the token embeds
76
- * the error message and two genuine failures rarely phrase it identically.
99
+ * transition is not that state. An `engine/` that was measurable and then
100
+ * was not means the second probe measured nothing about a checkout that
101
+ * demonstrably had something to measure; the reverse means there was never a
102
+ * baseline to compare against. Neither verdict can be trusted, so both throw.
77
103
  */
78
104
  export declare function assertEngineGenerationUnchanged(engineDir: string, before: string): Promise<void>;