@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
@@ -1,32 +1,30 @@
1
1
  /**
2
2
  * Private-index scope for FireForge's READ-ONLY git plumbing.
3
3
  *
4
- * `git status` and `git diff HEAD` are read-only in the sense operators
5
- * care about — they never change tracked content — but they are NOT
6
- * read-only to git: both refresh the index's stat cache and write
7
- * `.git/index` (through `.git/index.lock`) when a file's stat data has
8
- * moved. That makes `fireforge verify` / `lint --per-patch` / `typecheck`
9
- * a second WRITER of the primary `engine/` checkout, even when the command
10
- * was pointed at a CoW tree clone.
4
+ * `git status` and `git diff HEAD` are read-only in the sense operators care
5
+ * about — they never change tracked content — but they are NOT read-only to
6
+ * git: both refresh the index's stat cache and write `.git/index` (through
7
+ * `.git/index.lock`) when a file's stat data has moved. That makes
8
+ * `fireforge verify` / `lint --per-patch` / `typecheck` a second WRITER of
9
+ * the primary `engine/` checkout, even when the command was pointed at a CoW
10
+ * tree clone.
11
11
  *
12
12
  * The consequence is not cosmetic. A concurrent `fireforge test`
13
13
  * fingerprints `engine/` before and after the harness run and refuses a
14
- * verdict taken across a change (`FAIL reason=inconclusive`). That refusal
15
- * is CORRECT and stays; the defect is that FireForge's own read-only
16
- * commands were tripping it. Measured downstream: perfect correlation
17
- * between lane overlap and inconclusive verdicts, on suites that had
18
- * actually passed.
14
+ * verdict taken across a change (`FAIL reason=inconclusive`). That refusal is
15
+ * CORRECT and stays; the defect is FireForge's own read-only commands
16
+ * tripping it.
19
17
  *
20
18
  * The fix is the standard git one: point the plumbing at a PRIVATE index
21
- * (`GIT_INDEX_FILE`) seeded from the repository's own, in a temp
22
- * directory. Refreshes land there and are thrown away; the primary
23
- * `.git/index` — and `.git/index.lock`, which is what made a concurrent
24
- * `git status` fail outright rather than merely churn — is never touched.
19
+ * (`GIT_INDEX_FILE`) seeded from the repository's own, in a temp directory.
20
+ * Refreshes land there and are thrown away; the primary `.git/index` — and
21
+ * `.git/index.lock`, which is what makes a concurrent `git status` fail
22
+ * outright rather than merely churn — is never touched.
25
23
  *
26
24
  * Fail-open by design: if the git dir or the index cannot be resolved or
27
- * copied, the scope simply does not activate and the commands behave
28
- * exactly as before. A read-only command must not start failing because
29
- * an optimisation could not be set up.
25
+ * copied, the scope does not activate and the commands behave exactly as
26
+ * before. A read-only command must not start failing because an optimisation
27
+ * could not be set up.
30
28
  *
31
29
  * The scope is process-global and non-reentrant on purpose: FireForge
32
30
  * commands are one-shot CLI invocations, and nesting two different private
@@ -57,3 +55,39 @@ export declare function hasReadOnlyGitIndexScope(): boolean;
57
55
  * @returns Whatever `operation` returns
58
56
  */
59
57
  export declare function withPrivateGitIndex<T>(repoDir: string, operation: () => Promise<T>): Promise<T>;
58
+ /**
59
+ * A private index file plus the cleanup that removes it.
60
+ *
61
+ * `env` is meant to be handed to a SINGLE git invocation (or a small
62
+ * sequence of them), rather than installed process-wide the way
63
+ * {@link withPrivateGitIndex} installs a scope.
64
+ */
65
+ export interface DisposableGitIndex {
66
+ /** Environment overlay pointing git at the private index. */
67
+ env: Record<string, string>;
68
+ /** Removes the private index. Never throws. */
69
+ dispose: () => Promise<void>;
70
+ }
71
+ /**
72
+ * Mints a private index seeded from `repoDir`'s own, for a caller that
73
+ * needs to WRITE the index without the write being visible to anyone else.
74
+ *
75
+ * The distinction from {@link withPrivateGitIndex} matters. That one exists
76
+ * so a read-only command's incidental index refreshes do not touch the
77
+ * primary checkout, and it is process-global, non-reentrant, and fail-open,
78
+ * all of which are right for that job. This one serves a caller whose index
79
+ * write is DELIBERATE and whose visibility is the defect: it is per-call, so
80
+ * two concurrent callers cannot collide, and it never depends on an ambient
81
+ * scope having been installed by whichever command happens to be running.
82
+ *
83
+ * The seed is a plain copy, which is safe against a concurrent writer: git
84
+ * writes the index through `index.lock` and an atomic rename, so a reader
85
+ * sees either the old file or the new one, never a torn one. Seeding is
86
+ * REQUIRED rather than merely tidy — an empty index makes a tracked,
87
+ * unmodified file look like a fresh add.
88
+ *
89
+ * @param repoDir - Repository whose index should be shadowed
90
+ * @returns The overlay and its cleanup, or undefined when one could not be
91
+ * minted (a non-git directory, an unreadable index, no writable tmpdir)
92
+ */
93
+ export declare function mintDisposableGitIndex(repoDir: string): Promise<DisposableGitIndex | undefined>;
@@ -2,32 +2,30 @@
2
2
  /**
3
3
  * Private-index scope for FireForge's READ-ONLY git plumbing.
4
4
  *
5
- * `git status` and `git diff HEAD` are read-only in the sense operators
6
- * care about — they never change tracked content — but they are NOT
7
- * read-only to git: both refresh the index's stat cache and write
8
- * `.git/index` (through `.git/index.lock`) when a file's stat data has
9
- * moved. That makes `fireforge verify` / `lint --per-patch` / `typecheck`
10
- * a second WRITER of the primary `engine/` checkout, even when the command
11
- * was pointed at a CoW tree clone.
5
+ * `git status` and `git diff HEAD` are read-only in the sense operators care
6
+ * about — they never change tracked content — but they are NOT read-only to
7
+ * git: both refresh the index's stat cache and write `.git/index` (through
8
+ * `.git/index.lock`) when a file's stat data has moved. That makes
9
+ * `fireforge verify` / `lint --per-patch` / `typecheck` a second WRITER of
10
+ * the primary `engine/` checkout, even when the command was pointed at a CoW
11
+ * tree clone.
12
12
  *
13
13
  * The consequence is not cosmetic. A concurrent `fireforge test`
14
14
  * fingerprints `engine/` before and after the harness run and refuses a
15
- * verdict taken across a change (`FAIL reason=inconclusive`). That refusal
16
- * is CORRECT and stays; the defect is that FireForge's own read-only
17
- * commands were tripping it. Measured downstream: perfect correlation
18
- * between lane overlap and inconclusive verdicts, on suites that had
19
- * actually passed.
15
+ * verdict taken across a change (`FAIL reason=inconclusive`). That refusal is
16
+ * CORRECT and stays; the defect is FireForge's own read-only commands
17
+ * tripping it.
20
18
  *
21
19
  * The fix is the standard git one: point the plumbing at a PRIVATE index
22
- * (`GIT_INDEX_FILE`) seeded from the repository's own, in a temp
23
- * directory. Refreshes land there and are thrown away; the primary
24
- * `.git/index` — and `.git/index.lock`, which is what made a concurrent
25
- * `git status` fail outright rather than merely churn — is never touched.
20
+ * (`GIT_INDEX_FILE`) seeded from the repository's own, in a temp directory.
21
+ * Refreshes land there and are thrown away; the primary `.git/index` — and
22
+ * `.git/index.lock`, which is what makes a concurrent `git status` fail
23
+ * outright rather than merely churn — is never touched.
26
24
  *
27
25
  * Fail-open by design: if the git dir or the index cannot be resolved or
28
- * copied, the scope simply does not activate and the commands behave
29
- * exactly as before. A read-only command must not start failing because
30
- * an optimisation could not be set up.
26
+ * copied, the scope does not activate and the commands behave exactly as
27
+ * before. A read-only command must not start failing because an optimisation
28
+ * could not be set up.
31
29
  *
32
30
  * The scope is process-global and non-reentrant on purpose: FireForge
33
31
  * commands are one-shot CLI invocations, and nesting two different private
@@ -106,6 +104,56 @@ export async function withPrivateGitIndex(repoDir, operation) {
106
104
  const gitDir = await resolveGitDir(repoDir);
107
105
  if (gitDir === undefined)
108
106
  return operation();
107
+ const minted = await mintPrivateIndex(gitDir);
108
+ if (minted === undefined)
109
+ return operation();
110
+ activeScope = { repoDir: resolve(repoDir), indexFile: minted.indexFile };
111
+ verbose(`Private git index active for ${repoDir} (${minted.indexFile}).`);
112
+ try {
113
+ return await operation();
114
+ }
115
+ finally {
116
+ activeScope = undefined;
117
+ await minted.dispose();
118
+ }
119
+ }
120
+ /**
121
+ * Mints a private index seeded from `repoDir`'s own, for a caller that
122
+ * needs to WRITE the index without the write being visible to anyone else.
123
+ *
124
+ * The distinction from {@link withPrivateGitIndex} matters. That one exists
125
+ * so a read-only command's incidental index refreshes do not touch the
126
+ * primary checkout, and it is process-global, non-reentrant, and fail-open,
127
+ * all of which are right for that job. This one serves a caller whose index
128
+ * write is DELIBERATE and whose visibility is the defect: it is per-call, so
129
+ * two concurrent callers cannot collide, and it never depends on an ambient
130
+ * scope having been installed by whichever command happens to be running.
131
+ *
132
+ * The seed is a plain copy, which is safe against a concurrent writer: git
133
+ * writes the index through `index.lock` and an atomic rename, so a reader
134
+ * sees either the old file or the new one, never a torn one. Seeding is
135
+ * REQUIRED rather than merely tidy — an empty index makes a tracked,
136
+ * unmodified file look like a fresh add.
137
+ *
138
+ * @param repoDir - Repository whose index should be shadowed
139
+ * @returns The overlay and its cleanup, or undefined when one could not be
140
+ * minted (a non-git directory, an unreadable index, no writable tmpdir)
141
+ */
142
+ export async function mintDisposableGitIndex(repoDir) {
143
+ const gitDir = await resolveGitDir(repoDir);
144
+ if (gitDir === undefined)
145
+ return undefined;
146
+ const minted = await mintPrivateIndex(gitDir);
147
+ if (minted === undefined)
148
+ return undefined;
149
+ return { env: { GIT_INDEX_FILE: minted.indexFile }, dispose: minted.dispose };
150
+ }
151
+ /**
152
+ * Copies `gitDir`'s index into a fresh temp directory. Returns undefined
153
+ * rather than throwing: every caller has a defined behaviour for "no private
154
+ * index available", and none of them wants an exception from an optimisation.
155
+ */
156
+ async function mintPrivateIndex(gitDir) {
109
157
  let tempDir;
110
158
  try {
111
159
  tempDir = await mkdtemp(join(tmpdir(), 'fireforge-roindex-'));
@@ -116,22 +164,18 @@ export async function withPrivateGitIndex(repoDir, operation) {
116
164
  if (await pathExists(sourceIndex)) {
117
165
  await copyFile(sourceIndex, privateIndex);
118
166
  }
119
- activeScope = { repoDir: resolve(repoDir), indexFile: privateIndex };
120
- verbose(`Private git index active for ${repoDir} (${privateIndex}).`);
167
+ const dir = tempDir;
168
+ return {
169
+ indexFile: privateIndex,
170
+ dispose: async () => {
171
+ await rm(dir, { recursive: true, force: true });
172
+ },
173
+ };
121
174
  }
122
175
  catch (error) {
123
- // Fail-open: an unset-up scope must never fail a read-only command.
124
176
  verbose(`Private git index unavailable — ${toError(error).message}`);
125
- activeScope = undefined;
126
177
  if (tempDir !== undefined)
127
178
  await rm(tempDir, { recursive: true, force: true });
128
- return operation();
129
- }
130
- try {
131
- return await operation();
132
- }
133
- finally {
134
- activeScope = undefined;
135
- await rm(tempDir, { recursive: true, force: true });
179
+ return undefined;
136
180
  }
137
181
  }
@@ -22,15 +22,14 @@ export declare function resolveMaxUntrackedFilesPerDir(): number;
22
22
  * Git status may report "?? dir/" instead of listing each file underneath.
23
23
  *
24
24
  * Expansion is capped per directory (FIREFORGE_MAX_UNTRACKED_FILES, default
25
- * 5000) with a warning on overflow. The cap used to exist only in the
26
- * status command's private expander; this shared one — used by reset,
27
- * discard, verify, lint, export-all — was unbounded, so e.g. `reset
28
- * --dry-run` after an interrupted download (unborn HEAD, the entire ~300k
29
- * file tree untracked) enumerated and printed every file.
25
+ * 5000) with a warning on overflow. Without the cap, `reset --dry-run` after
26
+ * an interrupted download — unborn HEAD, the entire ~300k file tree
27
+ * untracked — enumerates and prints every file.
30
28
  *
31
29
  * @param repoDir - Repository directory
32
30
  * @param entries - Parsed status entries
33
- * @returns Status entries with untracked directories expanded to individual files
31
+ * @returns Status entries with untracked directories expanded to individual
32
+ * files
34
33
  */
35
34
  export declare function expandUntrackedDirectoryEntries(repoDir: string, entries: GitStatusEntry[]): Promise<GitStatusEntry[]>;
36
35
  /**
@@ -67,15 +67,14 @@ export function resolveMaxUntrackedFilesPerDir() {
67
67
  * Git status may report "?? dir/" instead of listing each file underneath.
68
68
  *
69
69
  * Expansion is capped per directory (FIREFORGE_MAX_UNTRACKED_FILES, default
70
- * 5000) with a warning on overflow. The cap used to exist only in the
71
- * status command's private expander; this shared one — used by reset,
72
- * discard, verify, lint, export-all — was unbounded, so e.g. `reset
73
- * --dry-run` after an interrupted download (unborn HEAD, the entire ~300k
74
- * file tree untracked) enumerated and printed every file.
70
+ * 5000) with a warning on overflow. Without the cap, `reset --dry-run` after
71
+ * an interrupted download — unborn HEAD, the entire ~300k file tree
72
+ * untracked — enumerates and prints every file.
75
73
  *
76
74
  * @param repoDir - Repository directory
77
75
  * @param entries - Parsed status entries
78
- * @returns Status entries with untracked directories expanded to individual files
76
+ * @returns Status entries with untracked directories expanded to individual
77
+ * files
79
78
  */
80
79
  export async function expandUntrackedDirectoryEntries(repoDir, entries) {
81
80
  const expanded = [];
@@ -50,20 +50,19 @@ export declare function applyPatch(patchPath: string, repoDir: string, options?:
50
50
  reject?: boolean;
51
51
  }): Promise<void>;
52
52
  /**
53
- * Applies a patch idempotently using reverse-forward pattern.
54
- * First tries to reverse the patch (in case it's already applied),
55
- * then applies it forward.
53
+ * Applies a patch idempotently using reverse-forward pattern. First tries to
54
+ * reverse the patch (in case it is already applied), then applies it forward.
56
55
  *
57
56
  * @param patchPath - Path to the patch file
58
57
  * @param repoDir - Repository directory
59
58
  * @param options.reject - Fall back to `git apply --reject`
60
- * @param options.protectedFiles - Files that must NOT be reset to HEAD by
61
- * the recovery step. Callers applying a patch QUEUE pass the files
62
- * already touched by previously applied patches in the same run: two
63
- * overlapping patches (an `--allow-overlap` queue) share files, and the
64
- * blanket `checkout HEAD` used to wipe the earlier patch's changes from
65
- * the shared file before applying the later one — leaving the engine in
66
- * a hybrid state the summary never described.
59
+ * @param options.protectedFiles - Files that must NOT be reset to HEAD by the
60
+ * recovery step. Callers applying a patch QUEUE pass the files already
61
+ * touched by previously applied patches in the same run: two overlapping
62
+ * patches (an `--allow-overlap` queue) share files, and a blanket
63
+ * `checkout HEAD` would wipe the earlier patch's changes from the shared
64
+ * file before applying the later one, leaving the engine in a hybrid state
65
+ * the summary never describes.
67
66
  */
68
67
  export declare function applyPatchIdempotent(patchPath: string, repoDir: string, options?: {
69
68
  reject?: boolean;
@@ -40,12 +40,10 @@ export async function ensureOriginRemote(dir) {
40
40
  // ── Large-tree staging helpers ──
41
41
  const GIT_ADD_ENV = { GIT_INDEX_THREADS: '0' };
42
42
  /**
43
- * Returns true when the error looks like a process killed by the spawn timeout
44
- * (SIGTERM → exit code 143) OR an AbortError raised by
45
- * `AbortSignal.timeout`. The AbortSignal path is the one observed during
46
- * the 2026-04-24 eval (Finding 10): Node's `child_process` layer
47
- * rejects with an AbortError when the signal fires, so the timeout
48
- * detection here needs to recognise that shape too.
43
+ * Returns true when the error looks like a process killed by the spawn
44
+ * timeout (SIGTERM → exit code 143) OR an AbortError raised by
45
+ * `AbortSignal.timeout` — Node's `child_process` layer rejects with an
46
+ * AbortError when the signal fires, so both shapes have to be recognised.
49
47
  */
50
48
  function isTimeoutError(error) {
51
49
  // `exec` now rejects with a typed ExecTimeoutError when its `timeout`
@@ -74,23 +72,20 @@ async function cleanupIndexLock(dir) {
74
72
  }
75
73
  }
76
74
  /**
77
- * Returns true when {@link relativePath} is ignored by `.gitignore` (or
78
- * any other exclusion mechanism git considers, e.g. `.git/info/exclude`,
79
- * core.excludesFile). Used by the chunked staging fallback to skip
80
- * entries that would otherwise fail `git add -- <path>` with the fatal
81
- * "The following paths are ignored by one of your .gitignore files"
82
- * error — a state the monolithic `git add -A` path silently handles.
75
+ * Returns true when {@link relativePath} is ignored by `.gitignore` (or any
76
+ * other exclusion mechanism git considers, e.g. `.git/info/exclude`,
77
+ * core.excludesFile). Used by the chunked staging fallback to skip entries
78
+ * that would otherwise fail `git add -- <path>` with the fatal "The
79
+ * following paths are ignored by one of your .gitignore files" error — a
80
+ * state the monolithic `git add -A` path silently handles. A Firefox
81
+ * checkout's top-level `.vscode/` is the common case: without this, the
82
+ * chunked invocation aborts the whole fallback and turns a recoverable
83
+ * monolithic timeout into a hard setup failure.
83
84
  *
84
- * Implementation: `git check-ignore -q -- <path>` exits 0 when the path
85
- * is ignored, 1 when it isn't, and >=128 on real failures. Treat
86
- * anything other than 0/1 as "unknown" and conservatively return false
87
- * so the chunk runs and any real underlying failure surfaces normally.
88
- *
89
- * 2026-04-26 eval Finding 4: a Firefox checkout's top-level `.vscode/`
90
- * is gitignored by the source tree's own `.gitignore`. Pre-fix, the
91
- * chunked `git add -- .vscode` invocation aborted the entire fallback
92
- * and turned a recoverable monolithic timeout into a hard setup
93
- * failure that required `fireforge download --force`.
85
+ * `git check-ignore -q -- <path>` exits 0 when the path is ignored, 1 when
86
+ * it is not, and >=128 on real failures. Anything other than 0/1 is treated
87
+ * as "unknown" and conservatively returns false, so the chunk runs and any
88
+ * real underlying failure surfaces normally.
94
89
  */
95
90
  async function isPathIgnored(dir, relativePath) {
96
91
  const result = await exec('git', ['check-ignore', '-q', '--', relativePath], { cwd: dir });
@@ -103,15 +98,14 @@ async function isPathIgnored(dir, relativePath) {
103
98
  return false;
104
99
  }
105
100
  /**
106
- * Stages every file by walking top-level directories one at a time.
107
- * This avoids a single monolithic `git add -A` that may time out on
108
- * very large (~300 K file) trees like Firefox.
101
+ * Stages every file by walking top-level directories one at a time. This
102
+ * avoids a single monolithic `git add -A` that may time out on very large
103
+ * (~300 K file) trees like Firefox.
109
104
  *
110
- * 2026-04-24 eval Finding 10: a chunked pass that hits its own timeout
111
- * now raises a typed {@link GitIndexingTimeoutError} rather than the
112
- * opaque `AbortError: The operation was aborted` the caller otherwise
113
- * saw. The typed error carries the environment-variable override so the
114
- * operator can extend the budget and re-run.
105
+ * A chunked pass that hits its own timeout raises a typed
106
+ * {@link GitIndexingTimeoutError} rather than an opaque `AbortError: The
107
+ * operation was aborted`; the typed error carries the environment-variable
108
+ * override so the operator can extend the budget and re-run.
115
109
  */
116
110
  async function stageAllFilesChunked(dir, scan, options = {}) {
117
111
  const { directories, topLevelFiles: topLevelCandidates } = scan;
@@ -160,10 +154,9 @@ async function stageAllFilesChunked(dir, scan, options = {}) {
160
154
  /**
161
155
  * Interval between heartbeat progress messages during the monolithic
162
156
  * `git add -A`. On a fresh ~600 MB Firefox tree the monolithic add runs
163
- * 60–120 seconds, during which git emits nothing to stdout/stderr. Without
164
- * a heartbeat the CLI spinner stays pinned on "Indexing Firefox source …"
165
- * for the full window, looks hung, and in the eval scenario operators
166
- * SIGINT'd mid-way assuming the process had stalled.
157
+ * 60–120 seconds, during which git emits nothing to stdout/stderr. Without a
158
+ * heartbeat the CLI spinner stays pinned on "Indexing Firefox source …" for
159
+ * the full window and looks hung, which invites a SIGINT mid-way.
167
160
  */
168
161
  const GIT_ADD_HEARTBEAT_MS = 15_000;
169
162
  const GIT_COMMIT_HEARTBEAT_MS = 15_000;
@@ -191,16 +184,12 @@ export async function stageAllFiles(dir, options = {}) {
191
184
  reportProgress?.('Scanning Firefox source tree before indexing...');
192
185
  const scan = await scanTopLevelSource(dir);
193
186
  reportProgress?.(`Source scan complete: ${scan.directories.length} top-level director${scan.directories.length === 1 ? 'y' : 'ies'}, ${scan.topLevelFiles.length} top-level file${scan.topLevelFiles.length === 1 ? '' : 's'}`);
194
- // 2026-04-26 eval Finding 5: the pre-fix heartbeat used a single
195
- // `heartbeatStartedAt` set at function entry and reported cumulative
196
- // elapsed for the whole `stageAllFiles` invocation. After a
197
- // monolithic timeout, the chunked-phase ticks therefore named
198
- // numbers that already included the entire monolithic budget plus
199
- // any host-sleep time, with no way for an operator watching the log
200
- // to tell where the monolithic attempt ended and the chunked pass
201
- // began. The heartbeat now tracks a per-phase start timestamp and
202
- // labels each tick with the phase, so the chunked pass reports its
203
- // own elapsed window and the monolithic→chunked handoff is visible.
187
+ // The heartbeat tracks a PER-PHASE start timestamp and labels each tick
188
+ // with the phase. A single start time set at function entry reports
189
+ // cumulative elapsed for the whole `stageAllFiles` invocation, so after a
190
+ // monolithic timeout the chunked-phase ticks name numbers that already
191
+ // include the entire monolithic budget, with no way to tell from the log
192
+ // where one attempt ended and the next began.
204
193
  let phase = 'monolithic';
205
194
  let phaseStartedAt = Date.now();
206
195
  const heartbeatTimer = reportProgress
@@ -223,13 +212,10 @@ export async function stageAllFiles(dir, options = {}) {
223
212
  if (!isTimeoutError(error)) {
224
213
  throw await maybeWrapIndexLockError(dir, error);
225
214
  }
226
- // 2026-04-24 eval Finding 10: the fallback transition used to be
227
- // an implementation detail invisible to operators watching the
228
- // spinner. Emit a loud, one-line banner so non-TTY log scrapers
229
- // and TTY operators both see that the monolithic attempt lost and
230
- // the chunked pass is starting. This was the missing signal in
231
- // the eval log where the heartbeat went quiet for ~600s between
232
- // the monolithic timeout and the chunked-pass failure.
215
+ // Emit a loud, one-line banner so non-TTY log scrapers and TTY
216
+ // operators both see that the monolithic attempt lost and the chunked
217
+ // pass is starting. Without it the fallback transition is invisible
218
+ // and the heartbeat simply goes quiet for minutes.
233
219
  options.onProgress?.(`Monolithic git add reached the ${Math.round(timeout / 1000)}s timeout; falling back to chunked staging. This pass may take several more minutes on a large tree.`);
234
220
  }
235
221
  // The killed process may have left an index lock
@@ -413,20 +399,19 @@ export async function applyPatch(patchPath, repoDir, options = {}) {
413
399
  }
414
400
  }
415
401
  /**
416
- * Applies a patch idempotently using reverse-forward pattern.
417
- * First tries to reverse the patch (in case it's already applied),
418
- * then applies it forward.
402
+ * Applies a patch idempotently using reverse-forward pattern. First tries to
403
+ * reverse the patch (in case it is already applied), then applies it forward.
419
404
  *
420
405
  * @param patchPath - Path to the patch file
421
406
  * @param repoDir - Repository directory
422
407
  * @param options.reject - Fall back to `git apply --reject`
423
- * @param options.protectedFiles - Files that must NOT be reset to HEAD by
424
- * the recovery step. Callers applying a patch QUEUE pass the files
425
- * already touched by previously applied patches in the same run: two
426
- * overlapping patches (an `--allow-overlap` queue) share files, and the
427
- * blanket `checkout HEAD` used to wipe the earlier patch's changes from
428
- * the shared file before applying the later one — leaving the engine in
429
- * a hybrid state the summary never described.
408
+ * @param options.protectedFiles - Files that must NOT be reset to HEAD by the
409
+ * recovery step. Callers applying a patch QUEUE pass the files already
410
+ * touched by previously applied patches in the same run: two overlapping
411
+ * patches (an `--allow-overlap` queue) share files, and a blanket
412
+ * `checkout HEAD` would wipe the earlier patch's changes from the shared
413
+ * file before applying the later one, leaving the engine in a hybrid state
414
+ * the summary never describes.
430
415
  */
431
416
  export async function applyPatchIdempotent(patchPath, repoDir, options = {}) {
432
417
  await ensureGit();
@@ -452,16 +437,15 @@ export async function applyPatchIdempotent(patchPath, repoDir, options = {}) {
452
437
  await applyPatch(patchPath, repoDir, options);
453
438
  }
454
439
  /**
455
- * Restores `files` to their HEAD state, deleting files the patch would
456
- * CREATE (present on disk from a partial apply but absent in HEAD — for
457
- * those, `git checkout HEAD --` fails, and the historical code ignored
458
- * that failure entirely, leaving stray files that made the subsequent
459
- * forward apply die with "already exists" and no hint why).
440
+ * Restores `files` to their HEAD state, deleting files the patch would CREATE
441
+ * (present on disk from a partial apply but absent in HEAD — for those,
442
+ * `git checkout HEAD --` fails, and ignoring that failure leaves stray files
443
+ * that make the subsequent forward apply die with "already exists" and no
444
+ * hint why).
460
445
  *
461
- * Every git invocation is chunked via {@link chunkPathspecs} so a very
462
- * large patch cannot hit `E2BIG`, and every exit code is checked — a
463
- * silent failed restore is precisely the confusing state this recovery
464
- * step exists to prevent.
446
+ * Every git invocation is chunked via {@link chunkPathspecs} so a very large
447
+ * patch cannot hit `E2BIG`, and every exit code is checked — a silent failed
448
+ * restore is the confusing state this recovery step exists to prevent.
465
449
  */
466
450
  async function restoreFilesToHead(repoDir, patchPath, files) {
467
451
  // Partition into tracked-in-HEAD (restore via checkout) and absent-in-HEAD
@@ -23,21 +23,19 @@ export declare function getLicenseHeader(license: ProjectLicense, style: Comment
23
23
  *
24
24
  * For `js` files, MPL-2.0 is also accepted in the upstream Mozilla block-
25
25
  * comment form (`/* ... *\/`) used by the Firefox source tree, not just the
26
- * `// ` line-comment form `getLicenseHeader` emits. Without that, a new JS
27
- * file copied from upstream Firefox (or written to match the surrounding
28
- * code's convention) hit `missing-license-header` even with a verbatim
29
- * standard MPL header — operators were forced to `--skip-lint` over a real
30
- * false positive.
26
+ * `// ` line-comment form `getLicenseHeader` emits — otherwise a new JS file
27
+ * copied from upstream Firefox hits `missing-license-header` even with a
28
+ * verbatim standard MPL header.
31
29
  *
32
30
  * Editor-directive block comments (`/* -*- ... -*- *\/`, `/* vim: ... *\/`)
33
- * leading the file are tolerated — Mozilla's canonical layout puts those
34
- * on lines 1–2 with the MPL header on lines 3+, which the raw
35
- * `startsWith` check would otherwise miss.
31
+ * leading the file are tolerated: Mozilla's canonical layout puts those on
32
+ * lines 1–2 with the MPL header on lines 3+, which a raw `startsWith` check
33
+ * would miss.
36
34
  *
37
- * The MPL-2.0 header is additionally matched on normalized whitespace
38
- * (see {@link normalizeCommentHead}) so upstream files using the older
39
- * Mozilla wrap — breaking after "file," instead of "with this" — are
40
- * accepted too; only the wrap position differs, never the wording.
35
+ * The MPL-2.0 header is additionally matched on normalized whitespace (see
36
+ * {@link normalizeCommentHead}) so upstream files using the older Mozilla
37
+ * wrap — breaking after "file," instead of "with this" — are accepted too;
38
+ * only the wrap position differs, never the wording.
41
39
  *
42
40
  * @param content - File content to check
43
41
  * @param style - Comment syntax of the file
@@ -46,22 +44,18 @@ export declare function hasAnyLicenseHeader(content: string, style: CommentStyle
46
44
  /**
47
45
  * Returns true if `content` starts with the verbatim upstream Mozilla
48
46
  * MPL-2.0 block header (`/* This Source Code Form … *\/`), optionally
49
- * preceded by editor-directive comments — the exact shape a JS file
50
- * copied from the Firefox source tree carries.
47
+ * preceded by editor-directive comments — the exact shape a JS file copied
48
+ * from the Firefox source tree carries.
51
49
  *
52
50
  * Deliberately independent of the project license: a new JS file that
53
- * legitimately keeps its upstream MPL block header (copied-from-upstream
54
- * provenance) is valid in an EUPL/GPL/0BSD project too. Before 0.35.0
55
- * this acceptance only existed behind a `license === 'MPL-2.0'` gate in
56
- * patch-lint, making it dead code for every other project license and
57
- * forcing repo-side audit workarounds.
51
+ * legitimately keeps its upstream MPL block header is valid in an
52
+ * EUPL/GPL/0BSD project too.
58
53
  *
59
54
  * Matching is wrap-agnostic: after the exact `startsWith` fast path, the
60
55
  * leading block comment is compared on normalized whitespace (see
61
- * {@link normalizeCommentHead}) so the older upstream wrap — breaking
62
- * after "file," instead of "with this", as `ext-browser.js` ships —
63
- * passes too. Only the line-break position may differ; altered wording
64
- * still rejects.
56
+ * {@link normalizeCommentHead}) so the older upstream wrap — breaking after
57
+ * "file," instead of "with this", as `ext-browser.js` ships — passes too.
58
+ * Only the line-break position may differ; altered wording still rejects.
65
59
  *
66
60
  * @param content - File content to check
67
61
  */
@@ -145,21 +145,19 @@ function normalizeCommentHead(content, style) {
145
145
  *
146
146
  * For `js` files, MPL-2.0 is also accepted in the upstream Mozilla block-
147
147
  * comment form (`/* ... *\/`) used by the Firefox source tree, not just the
148
- * `// ` line-comment form `getLicenseHeader` emits. Without that, a new JS
149
- * file copied from upstream Firefox (or written to match the surrounding
150
- * code's convention) hit `missing-license-header` even with a verbatim
151
- * standard MPL header — operators were forced to `--skip-lint` over a real
152
- * false positive.
148
+ * `// ` line-comment form `getLicenseHeader` emits — otherwise a new JS file
149
+ * copied from upstream Firefox hits `missing-license-header` even with a
150
+ * verbatim standard MPL header.
153
151
  *
154
152
  * Editor-directive block comments (`/* -*- ... -*- *\/`, `/* vim: ... *\/`)
155
- * leading the file are tolerated — Mozilla's canonical layout puts those
156
- * on lines 1–2 with the MPL header on lines 3+, which the raw
157
- * `startsWith` check would otherwise miss.
153
+ * leading the file are tolerated: Mozilla's canonical layout puts those on
154
+ * lines 1–2 with the MPL header on lines 3+, which a raw `startsWith` check
155
+ * would miss.
158
156
  *
159
- * The MPL-2.0 header is additionally matched on normalized whitespace
160
- * (see {@link normalizeCommentHead}) so upstream files using the older
161
- * Mozilla wrap — breaking after "file," instead of "with this" — are
162
- * accepted too; only the wrap position differs, never the wording.
157
+ * The MPL-2.0 header is additionally matched on normalized whitespace (see
158
+ * {@link normalizeCommentHead}) so upstream files using the older Mozilla
159
+ * wrap — breaking after "file," instead of "with this" — are accepted too;
160
+ * only the wrap position differs, never the wording.
163
161
  *
164
162
  * @param content - File content to check
165
163
  * @param style - Comment syntax of the file
@@ -183,22 +181,18 @@ export function hasAnyLicenseHeader(content, style) {
183
181
  /**
184
182
  * Returns true if `content` starts with the verbatim upstream Mozilla
185
183
  * MPL-2.0 block header (`/* This Source Code Form … *\/`), optionally
186
- * preceded by editor-directive comments — the exact shape a JS file
187
- * copied from the Firefox source tree carries.
184
+ * preceded by editor-directive comments — the exact shape a JS file copied
185
+ * from the Firefox source tree carries.
188
186
  *
189
187
  * Deliberately independent of the project license: a new JS file that
190
- * legitimately keeps its upstream MPL block header (copied-from-upstream
191
- * provenance) is valid in an EUPL/GPL/0BSD project too. Before 0.35.0
192
- * this acceptance only existed behind a `license === 'MPL-2.0'` gate in
193
- * patch-lint, making it dead code for every other project license and
194
- * forcing repo-side audit workarounds.
188
+ * legitimately keeps its upstream MPL block header is valid in an
189
+ * EUPL/GPL/0BSD project too.
195
190
  *
196
191
  * Matching is wrap-agnostic: after the exact `startsWith` fast path, the
197
192
  * leading block comment is compared on normalized whitespace (see
198
- * {@link normalizeCommentHead}) so the older upstream wrap — breaking
199
- * after "file," instead of "with this", as `ext-browser.js` ships —
200
- * passes too. Only the line-break position may differ; altered wording
201
- * still rejects.
193
+ * {@link normalizeCommentHead}) so the older upstream wrap — breaking after
194
+ * "file," instead of "with this", as `ext-browser.js` ships — passes too.
195
+ * Only the line-break position may differ; altered wording still rejects.
202
196
  *
203
197
  * @param content - File content to check
204
198
  */