@hominis/fireforge 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (662) hide show
  1. package/CHANGELOG.md +409 -446
  2. package/dist/bin/fireforge.d.ts +1 -1
  3. package/dist/bin/fireforge.js +21 -15
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/cli-usage-error.d.ts +46 -0
  6. package/dist/src/cli-usage-error.js +81 -0
  7. package/dist/src/cli.d.ts +7 -2
  8. package/dist/src/cli.js +47 -47
  9. package/dist/src/commands/bootstrap-checks.js +2 -1
  10. package/dist/src/commands/bootstrap.js +3 -4
  11. package/dist/src/commands/build.js +27 -17
  12. package/dist/src/commands/config.js +9 -9
  13. package/dist/src/commands/destructive-decision.d.ts +19 -0
  14. package/dist/src/commands/destructive-decision.js +31 -0
  15. package/dist/src/commands/discard.js +5 -5
  16. package/dist/src/commands/doctor-check-core.d.ts +4 -10
  17. package/dist/src/commands/doctor-check-core.js +0 -8
  18. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  19. package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
  20. package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
  21. package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
  22. package/dist/src/commands/doctor-furnace-jar.js +1 -1
  23. package/dist/src/commands/doctor-furnace.js +22 -22
  24. package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
  25. package/dist/src/commands/doctor-orphaned-harness.js +14 -23
  26. package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
  27. package/dist/src/commands/doctor-patch-manifest.js +7 -6
  28. package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
  29. package/dist/src/commands/doctor-source-pin.d.ts +12 -12
  30. package/dist/src/commands/doctor-source-pin.js +14 -14
  31. package/dist/src/commands/doctor-working-tree.d.ts +3 -3
  32. package/dist/src/commands/doctor-working-tree.js +3 -3
  33. package/dist/src/commands/doctor.d.ts +3 -1
  34. package/dist/src/commands/doctor.js +15 -16
  35. package/dist/src/commands/download.js +50 -37
  36. package/dist/src/commands/export-all.js +29 -12
  37. package/dist/src/commands/export-flow.d.ts +5 -5
  38. package/dist/src/commands/export-flow.js +29 -59
  39. package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
  40. package/dist/src/commands/export-placement-conflicts.js +12 -12
  41. package/dist/src/commands/export-placement-gate.d.ts +2 -2
  42. package/dist/src/commands/export-placement-gate.js +7 -13
  43. package/dist/src/commands/export-placement-policy.d.ts +1 -1
  44. package/dist/src/commands/export-placement-policy.js +4 -6
  45. package/dist/src/commands/export-shared.d.ts +51 -32
  46. package/dist/src/commands/export-shared.js +17 -32
  47. package/dist/src/commands/export.js +14 -5
  48. package/dist/src/commands/furnace/apply.js +16 -16
  49. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  50. package/dist/src/commands/furnace/authoring-config.js +19 -0
  51. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
  52. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  53. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
  54. package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
  55. package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
  56. package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
  57. package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
  58. package/dist/src/commands/furnace/chrome-doc.js +18 -18
  59. package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
  60. package/dist/src/commands/furnace/create-browser-test.js +7 -12
  61. package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
  62. package/dist/src/commands/furnace/create-dry-run.js +6 -9
  63. package/dist/src/commands/furnace/create-features.d.ts +2 -2
  64. package/dist/src/commands/furnace/create-features.js +2 -2
  65. package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
  66. package/dist/src/commands/furnace/create-mochikit.js +7 -7
  67. package/dist/src/commands/furnace/create-templates.d.ts +31 -15
  68. package/dist/src/commands/furnace/create-templates.js +20 -19
  69. package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
  70. package/dist/src/commands/furnace/create-xpcshell.js +8 -8
  71. package/dist/src/commands/furnace/create.d.ts +1 -1
  72. package/dist/src/commands/furnace/create.js +35 -29
  73. package/dist/src/commands/furnace/deploy.js +15 -6
  74. package/dist/src/commands/furnace/diff.js +7 -7
  75. package/dist/src/commands/furnace/index.js +1 -1
  76. package/dist/src/commands/furnace/init.js +17 -16
  77. package/dist/src/commands/furnace/list.js +2 -2
  78. package/dist/src/commands/furnace/override.d.ts +1 -1
  79. package/dist/src/commands/furnace/override.js +43 -34
  80. package/dist/src/commands/furnace/preview.js +17 -17
  81. package/dist/src/commands/furnace/refresh.js +15 -7
  82. package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
  83. package/dist/src/commands/furnace/remove-mutations.js +19 -19
  84. package/dist/src/commands/furnace/remove-state.d.ts +1 -1
  85. package/dist/src/commands/furnace/remove-state.js +1 -1
  86. package/dist/src/commands/furnace/remove.js +4 -8
  87. package/dist/src/commands/furnace/rename-browser-test.js +10 -15
  88. package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
  89. package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
  90. package/dist/src/commands/furnace/rename.js +36 -36
  91. package/dist/src/commands/furnace/scan.js +3 -3
  92. package/dist/src/commands/furnace/status.js +19 -16
  93. package/dist/src/commands/furnace/sync.js +6 -6
  94. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  95. package/dist/src/commands/furnace/test-file-name.js +39 -0
  96. package/dist/src/commands/furnace/validate.js +11 -12
  97. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  98. package/dist/src/commands/furnace/validation-output.js +3 -8
  99. package/dist/src/commands/import.js +22 -29
  100. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  101. package/dist/src/commands/lint-per-patch.js +27 -12
  102. package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
  103. package/dist/src/commands/lint-per-run-checkjs.js +14 -15
  104. package/dist/src/commands/lint-report.d.ts +3 -3
  105. package/dist/src/commands/lint-report.js +4 -4
  106. package/dist/src/commands/lint.d.ts +5 -4
  107. package/dist/src/commands/lint.js +36 -36
  108. package/dist/src/commands/manifest.d.ts +4 -4
  109. package/dist/src/commands/manifest.js +1 -1
  110. package/dist/src/commands/package.js +4 -6
  111. package/dist/src/commands/patch/compact.d.ts +2 -2
  112. package/dist/src/commands/patch/compact.js +19 -20
  113. package/dist/src/commands/patch/delete.d.ts +1 -1
  114. package/dist/src/commands/patch/delete.js +23 -33
  115. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  116. package/dist/src/commands/patch/entry-projection.js +24 -0
  117. package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
  118. package/dist/src/commands/patch/lint-ignore.js +33 -44
  119. package/dist/src/commands/patch/move-files-create.d.ts +2 -2
  120. package/dist/src/commands/patch/move-files-create.js +29 -15
  121. package/dist/src/commands/patch/move-files-into.d.ts +2 -2
  122. package/dist/src/commands/patch/move-files-into.js +41 -37
  123. package/dist/src/commands/patch/move-files.js +5 -14
  124. package/dist/src/commands/patch/patch-context.d.ts +1 -1
  125. package/dist/src/commands/patch/rename.d.ts +4 -4
  126. package/dist/src/commands/patch/rename.js +35 -49
  127. package/dist/src/commands/patch/reorder.js +35 -48
  128. package/dist/src/commands/patch/split-plan.d.ts +7 -8
  129. package/dist/src/commands/patch/split-plan.js +10 -13
  130. package/dist/src/commands/patch/split.d.ts +2 -2
  131. package/dist/src/commands/patch/split.js +50 -48
  132. package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
  133. package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
  134. package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
  135. package/dist/src/commands/patch/staged-dependency.js +22 -28
  136. package/dist/src/commands/patch/tier.d.ts +2 -2
  137. package/dist/src/commands/patch/tier.js +20 -30
  138. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  139. package/dist/src/commands/patch-rename-map.js +36 -0
  140. package/dist/src/commands/pending-resolution.d.ts +15 -0
  141. package/dist/src/commands/pending-resolution.js +25 -0
  142. package/dist/src/commands/re-export-adjacent.d.ts +25 -3
  143. package/dist/src/commands/re-export-adjacent.js +40 -24
  144. package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
  145. package/dist/src/commands/re-export-bulk-scan.js +23 -27
  146. package/dist/src/commands/re-export-drift.d.ts +10 -10
  147. package/dist/src/commands/re-export-drift.js +33 -33
  148. package/dist/src/commands/re-export-files.d.ts +2 -3
  149. package/dist/src/commands/re-export-files.js +52 -44
  150. package/dist/src/commands/re-export-lint.d.ts +29 -30
  151. package/dist/src/commands/re-export-lint.js +36 -29
  152. package/dist/src/commands/re-export-options.d.ts +1 -1
  153. package/dist/src/commands/re-export-options.js +1 -1
  154. package/dist/src/commands/re-export-register.d.ts +1 -1
  155. package/dist/src/commands/re-export-register.js +1 -1
  156. package/dist/src/commands/re-export-scan.d.ts +1 -1
  157. package/dist/src/commands/re-export-scan.js +12 -9
  158. package/dist/src/commands/re-export-single.d.ts +23 -4
  159. package/dist/src/commands/re-export-single.js +39 -31
  160. package/dist/src/commands/re-export.js +35 -17
  161. package/dist/src/commands/rebase/abort.js +9 -14
  162. package/dist/src/commands/rebase/continue.js +20 -19
  163. package/dist/src/commands/rebase/index.d.ts +1 -1
  164. package/dist/src/commands/rebase/index.js +5 -5
  165. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  166. package/dist/src/commands/rebase/patch-loop.js +20 -24
  167. package/dist/src/commands/register.js +5 -5
  168. package/dist/src/commands/reset.js +1 -1
  169. package/dist/src/commands/resolve.d.ts +2 -2
  170. package/dist/src/commands/resolve.js +21 -13
  171. package/dist/src/commands/run.d.ts +0 -13
  172. package/dist/src/commands/run.js +38 -51
  173. package/dist/src/commands/setup-support.d.ts +16 -4
  174. package/dist/src/commands/setup-support.js +20 -20
  175. package/dist/src/commands/setup.js +4 -10
  176. package/dist/src/commands/source.js +9 -2
  177. package/dist/src/commands/status-check.d.ts +3 -3
  178. package/dist/src/commands/status-check.js +6 -6
  179. package/dist/src/commands/status-json.d.ts +14 -13
  180. package/dist/src/commands/status-json.js +9 -8
  181. package/dist/src/commands/status-output.d.ts +3 -3
  182. package/dist/src/commands/status-output.js +5 -5
  183. package/dist/src/commands/status-ownership.d.ts +3 -3
  184. package/dist/src/commands/status-ownership.js +3 -3
  185. package/dist/src/commands/status.js +25 -26
  186. package/dist/src/commands/test-build-phase.d.ts +3 -3
  187. package/dist/src/commands/test-build-phase.js +48 -24
  188. package/dist/src/commands/test-diagnose.d.ts +1 -1
  189. package/dist/src/commands/test-diagnose.js +20 -20
  190. package/dist/src/commands/test-modes.d.ts +4 -4
  191. package/dist/src/commands/test-modes.js +4 -5
  192. package/dist/src/commands/test-register.js +5 -3
  193. package/dist/src/commands/test-run.d.ts +11 -11
  194. package/dist/src/commands/test-run.js +40 -33
  195. package/dist/src/commands/test-stale-gate.d.ts +12 -12
  196. package/dist/src/commands/test-stale-gate.js +17 -17
  197. package/dist/src/commands/test-verdict.d.ts +19 -5
  198. package/dist/src/commands/test-verdict.js +26 -11
  199. package/dist/src/commands/test.d.ts +3 -3
  200. package/dist/src/commands/test.js +73 -36
  201. package/dist/src/commands/token-coverage.js +3 -3
  202. package/dist/src/commands/token-list.d.ts +26 -0
  203. package/dist/src/commands/token-list.js +153 -0
  204. package/dist/src/commands/token.js +26 -10
  205. package/dist/src/commands/tree.js +26 -21
  206. package/dist/src/commands/typecheck.d.ts +6 -6
  207. package/dist/src/commands/typecheck.js +16 -16
  208. package/dist/src/commands/verify.d.ts +3 -3
  209. package/dist/src/commands/verify.js +10 -10
  210. package/dist/src/commands/watch.js +11 -11
  211. package/dist/src/commands/wire.js +17 -16
  212. package/dist/src/core/ast-utils.d.ts +7 -7
  213. package/dist/src/core/ast-utils.js +8 -8
  214. package/dist/src/core/branding.d.ts +5 -12
  215. package/dist/src/core/branding.js +6 -5
  216. package/dist/src/core/browser-wire.d.ts +1 -1
  217. package/dist/src/core/browser-wire.js +10 -7
  218. package/dist/src/core/build-audit-platform.d.ts +32 -3
  219. package/dist/src/core/build-audit-platform.js +153 -13
  220. package/dist/src/core/build-audit-registration.d.ts +5 -5
  221. package/dist/src/core/build-audit-registration.js +10 -9
  222. package/dist/src/core/build-audit-resolve.d.ts +5 -5
  223. package/dist/src/core/build-audit-resolve.js +6 -6
  224. package/dist/src/core/build-audit-skip.d.ts +57 -0
  225. package/dist/src/core/build-audit-skip.js +112 -0
  226. package/dist/src/core/build-audit-transforms.d.ts +2 -2
  227. package/dist/src/core/build-audit-transforms.js +3 -3
  228. package/dist/src/core/build-audit.d.ts +21 -8
  229. package/dist/src/core/build-audit.js +142 -40
  230. package/dist/src/core/build-baseline-types.d.ts +19 -18
  231. package/dist/src/core/build-baseline-types.js +1 -1
  232. package/dist/src/core/build-baseline.d.ts +48 -31
  233. package/dist/src/core/build-baseline.js +20 -43
  234. package/dist/src/core/build-jar-escalation.d.ts +8 -8
  235. package/dist/src/core/build-jar-escalation.js +18 -17
  236. package/dist/src/core/build-overwrite-guard.d.ts +4 -4
  237. package/dist/src/core/build-overwrite-guard.js +14 -14
  238. package/dist/src/core/build-prepare.d.ts +4 -12
  239. package/dist/src/core/build-prepare.js +22 -26
  240. package/dist/src/core/config-mutate.js +4 -4
  241. package/dist/src/core/config-paths.d.ts +2 -6
  242. package/dist/src/core/config-paths.js +4 -2
  243. package/dist/src/core/config-state.d.ts +0 -6
  244. package/dist/src/core/config-state.js +3 -21
  245. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  246. package/dist/src/core/config-validate-build-audit.js +80 -0
  247. package/dist/src/core/config-validate-file-size.d.ts +1 -1
  248. package/dist/src/core/config-validate-file-size.js +3 -3
  249. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  250. package/dist/src/core/config-validate-patch-policy.js +3 -3
  251. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  252. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  253. package/dist/src/core/config-validate.js +22 -12
  254. package/dist/src/core/config.d.ts +12 -12
  255. package/dist/src/core/config.js +21 -25
  256. package/dist/src/core/coverage-extend.d.ts +16 -16
  257. package/dist/src/core/coverage-extend.js +20 -20
  258. package/dist/src/core/destructive.d.ts +14 -14
  259. package/dist/src/core/destructive.js +9 -9
  260. package/dist/src/core/diff-hunks.d.ts +2 -2
  261. package/dist/src/core/diff-hunks.js +7 -7
  262. package/dist/src/core/discard-baseline.d.ts +10 -10
  263. package/dist/src/core/discard-baseline.js +22 -23
  264. package/dist/src/core/display-state.d.ts +11 -11
  265. package/dist/src/core/display-state.js +12 -12
  266. package/dist/src/core/engine-changes.d.ts +2 -2
  267. package/dist/src/core/engine-changes.js +2 -2
  268. package/dist/src/core/engine-precondition.d.ts +5 -13
  269. package/dist/src/core/engine-precondition.js +5 -10
  270. package/dist/src/core/engine-session-lock.d.ts +18 -18
  271. package/dist/src/core/engine-session-lock.js +50 -54
  272. package/dist/src/core/export-moved-code-shape.d.ts +7 -7
  273. package/dist/src/core/export-moved-code-shape.js +10 -10
  274. package/dist/src/core/file-lock-owner.d.ts +103 -0
  275. package/dist/src/core/file-lock-owner.js +259 -0
  276. package/dist/src/core/file-lock.d.ts +14 -19
  277. package/dist/src/core/file-lock.js +90 -128
  278. package/dist/src/core/firefox-cache.d.ts +13 -1
  279. package/dist/src/core/firefox-cache.js +61 -36
  280. package/dist/src/core/firefox-download.d.ts +15 -0
  281. package/dist/src/core/firefox-download.js +38 -22
  282. package/dist/src/core/firefox-extract.d.ts +8 -7
  283. package/dist/src/core/firefox-extract.js +45 -27
  284. package/dist/src/core/firefox.d.ts +34 -36
  285. package/dist/src/core/firefox.js +13 -44
  286. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  287. package/dist/src/core/furnace-apply-dry-run.js +2 -8
  288. package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
  289. package/dist/src/core/furnace-apply-ftl.js +8 -8
  290. package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
  291. package/dist/src/core/furnace-apply-helpers.js +28 -39
  292. package/dist/src/core/furnace-apply-output.js +1 -1
  293. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
  294. package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
  295. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
  296. package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
  297. package/dist/src/core/furnace-apply.d.ts +4 -4
  298. package/dist/src/core/furnace-apply.js +50 -29
  299. package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
  300. package/dist/src/core/furnace-checksum-utils.js +5 -5
  301. package/dist/src/core/furnace-config-custom.d.ts +1 -1
  302. package/dist/src/core/furnace-config-custom.js +2 -2
  303. package/dist/src/core/furnace-config-order.js +1 -1
  304. package/dist/src/core/furnace-config-tokens.d.ts +3 -3
  305. package/dist/src/core/furnace-config-tokens.js +3 -3
  306. package/dist/src/core/furnace-config-validate.js +2 -2
  307. package/dist/src/core/furnace-config.d.ts +5 -5
  308. package/dist/src/core/furnace-config.js +40 -53
  309. package/dist/src/core/furnace-constants.d.ts +6 -6
  310. package/dist/src/core/furnace-constants.js +9 -8
  311. package/dist/src/core/furnace-css-fragments.d.ts +6 -6
  312. package/dist/src/core/furnace-css-fragments.js +11 -11
  313. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  314. package/dist/src/core/furnace-dir-entry.js +21 -0
  315. package/dist/src/core/furnace-jsconfig.d.ts +7 -7
  316. package/dist/src/core/furnace-jsconfig.js +22 -20
  317. package/dist/src/core/furnace-operation.d.ts +22 -19
  318. package/dist/src/core/furnace-operation.js +38 -34
  319. package/dist/src/core/furnace-precondition.d.ts +10 -10
  320. package/dist/src/core/furnace-precondition.js +8 -8
  321. package/dist/src/core/furnace-refresh.d.ts +18 -6
  322. package/dist/src/core/furnace-refresh.js +5 -8
  323. package/dist/src/core/furnace-registration-ast.d.ts +2 -3
  324. package/dist/src/core/furnace-registration-ast.js +9 -12
  325. package/dist/src/core/furnace-registration-remove.d.ts +4 -4
  326. package/dist/src/core/furnace-registration-remove.js +6 -6
  327. package/dist/src/core/furnace-registration-validate.d.ts +2 -2
  328. package/dist/src/core/furnace-registration-validate.js +2 -2
  329. package/dist/src/core/furnace-registration.d.ts +7 -6
  330. package/dist/src/core/furnace-registration.js +29 -36
  331. package/dist/src/core/furnace-rollback.d.ts +1 -1
  332. package/dist/src/core/furnace-rollback.js +5 -5
  333. package/dist/src/core/furnace-scanner.js +3 -6
  334. package/dist/src/core/furnace-stale-export.d.ts +17 -16
  335. package/dist/src/core/furnace-stale-export.js +16 -15
  336. package/dist/src/core/furnace-staleness.d.ts +2 -2
  337. package/dist/src/core/furnace-staleness.js +2 -2
  338. package/dist/src/core/furnace-state-persist.d.ts +12 -12
  339. package/dist/src/core/furnace-state-persist.js +10 -10
  340. package/dist/src/core/furnace-step-errors.d.ts +6 -6
  341. package/dist/src/core/furnace-step-errors.js +6 -6
  342. package/dist/src/core/furnace-validate-accessibility.js +14 -14
  343. package/dist/src/core/furnace-validate-compatibility.js +9 -9
  344. package/dist/src/core/furnace-validate-registration.d.ts +2 -2
  345. package/dist/src/core/furnace-validate-registration.js +18 -20
  346. package/dist/src/core/furnace-validate-structure.d.ts +1 -1
  347. package/dist/src/core/furnace-validate-structure.js +4 -4
  348. package/dist/src/core/furnace-validate.js +9 -9
  349. package/dist/src/core/furnace-version-drift.d.ts +5 -5
  350. package/dist/src/core/furnace-version-drift.js +5 -5
  351. package/dist/src/core/git-base.d.ts +6 -4
  352. package/dist/src/core/git-base.js +29 -7
  353. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  354. package/dist/src/core/git-diff-new-file.js +119 -0
  355. package/dist/src/core/git-diff.d.ts +13 -13
  356. package/dist/src/core/git-diff.js +121 -189
  357. package/dist/src/core/git-file-ops.d.ts +6 -13
  358. package/dist/src/core/git-file-ops.js +11 -35
  359. package/dist/src/core/git-readonly-index.d.ts +12 -14
  360. package/dist/src/core/git-readonly-index.js +12 -16
  361. package/dist/src/core/git-status.d.ts +9 -2
  362. package/dist/src/core/git-status.js +23 -11
  363. package/dist/src/core/git.d.ts +3 -9
  364. package/dist/src/core/git.js +28 -57
  365. package/dist/src/core/harness-orphans.d.ts +17 -17
  366. package/dist/src/core/harness-orphans.js +28 -27
  367. package/dist/src/core/history-log.d.ts +19 -0
  368. package/dist/src/core/history-log.js +29 -0
  369. package/dist/src/core/license-headers.d.ts +19 -18
  370. package/dist/src/core/license-headers.js +29 -28
  371. package/dist/src/core/mach-build-artifacts.d.ts +21 -21
  372. package/dist/src/core/mach-build-artifacts.js +23 -23
  373. package/dist/src/core/mach-error-hints.d.ts +5 -10
  374. package/dist/src/core/mach-error-hints.js +14 -14
  375. package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
  376. package/dist/src/core/mach-known-noise-filter.js +57 -56
  377. package/dist/src/core/mach-mozconfig.d.ts +6 -6
  378. package/dist/src/core/mach-mozconfig.js +17 -16
  379. package/dist/src/core/mach-python.d.ts +3 -0
  380. package/dist/src/core/mach-python.js +13 -7
  381. package/dist/src/core/mach-resource-shim.d.ts +24 -12
  382. package/dist/src/core/mach-resource-shim.js +124 -21
  383. package/dist/src/core/mach.d.ts +59 -73
  384. package/dist/src/core/mach.js +47 -115
  385. package/dist/src/core/marionette-port.d.ts +15 -30
  386. package/dist/src/core/marionette-port.js +46 -89
  387. package/dist/src/core/marionette-preflight.d.ts +6 -6
  388. package/dist/src/core/marionette-preflight.js +32 -50
  389. package/dist/src/core/markdown-table.d.ts +9 -9
  390. package/dist/src/core/markdown-table.js +14 -14
  391. package/dist/src/core/mochitest-server-port.d.ts +8 -8
  392. package/dist/src/core/mochitest-server-port.js +17 -17
  393. package/dist/src/core/module-resolution-preflight.d.ts +8 -8
  394. package/dist/src/core/module-resolution-preflight.js +11 -11
  395. package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
  396. package/dist/src/core/moz-manifest-helpers.js +7 -7
  397. package/dist/src/core/moz-manifest-register.d.ts +1 -1
  398. package/dist/src/core/moz-manifest-register.js +2 -2
  399. package/dist/src/core/moz-manifest-rules.js +46 -42
  400. package/dist/src/core/moz-manifest-tokenizers.js +1 -1
  401. package/dist/src/core/ownership-table.d.ts +5 -5
  402. package/dist/src/core/ownership-table.js +7 -7
  403. package/dist/src/core/parser-fallback.d.ts +3 -3
  404. package/dist/src/core/parser-fallback.js +3 -3
  405. package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
  406. package/dist/src/core/patch-apply-fuzz.js +13 -13
  407. package/dist/src/core/patch-apply.d.ts +13 -14
  408. package/dist/src/core/patch-apply.js +36 -42
  409. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  410. package/dist/src/core/patch-export-coverage.js +1 -30
  411. package/dist/src/core/patch-export-update.d.ts +21 -4
  412. package/dist/src/core/patch-export-update.js +7 -6
  413. package/dist/src/core/patch-export.d.ts +20 -30
  414. package/dist/src/core/patch-export.js +55 -77
  415. package/dist/src/core/patch-files.d.ts +0 -4
  416. package/dist/src/core/patch-files.js +0 -11
  417. package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
  418. package/dist/src/core/patch-identifier-suggest.js +4 -4
  419. package/dist/src/core/patch-lint-binary.d.ts +12 -18
  420. package/dist/src/core/patch-lint-cache.d.ts +18 -2
  421. package/dist/src/core/patch-lint-cache.js +16 -19
  422. package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
  423. package/dist/src/core/patch-lint-checkjs.js +78 -64
  424. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
  425. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
  426. package/dist/src/core/patch-lint-creators.d.ts +5 -9
  427. package/dist/src/core/patch-lint-creators.js +3 -3
  428. package/dist/src/core/patch-lint-cross.d.ts +27 -19
  429. package/dist/src/core/patch-lint-cross.js +67 -110
  430. package/dist/src/core/patch-lint-css.d.ts +1 -1
  431. package/dist/src/core/patch-lint-css.js +15 -11
  432. package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
  433. package/dist/src/core/patch-lint-diff-tag.js +5 -5
  434. package/dist/src/core/patch-lint-diff.d.ts +4 -4
  435. package/dist/src/core/patch-lint-diff.js +4 -4
  436. package/dist/src/core/patch-lint-file-size.d.ts +3 -3
  437. package/dist/src/core/patch-lint-file-size.js +6 -6
  438. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  439. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  440. package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
  441. package/dist/src/core/patch-lint-jsdoc.js +46 -46
  442. package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
  443. package/dist/src/core/patch-lint-module-registration.js +1 -1
  444. package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
  445. package/dist/src/core/patch-lint-mozbuild.js +10 -10
  446. package/dist/src/core/patch-lint-observer.d.ts +3 -3
  447. package/dist/src/core/patch-lint-observer.js +7 -7
  448. package/dist/src/core/patch-lint-ownership.d.ts +6 -6
  449. package/dist/src/core/patch-lint-ownership.js +6 -6
  450. package/dist/src/core/patch-lint-prettier.d.ts +6 -6
  451. package/dist/src/core/patch-lint-prettier.js +7 -7
  452. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  453. package/dist/src/core/patch-lint-queue-types.js +12 -0
  454. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  455. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  456. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
  457. package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
  458. package/dist/src/core/patch-lint.d.ts +41 -35
  459. package/dist/src/core/patch-lint.js +52 -49
  460. package/dist/src/core/patch-lock.d.ts +1 -1
  461. package/dist/src/core/patch-lock.js +11 -11
  462. package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
  463. package/dist/src/core/patch-manifest-consistency.js +16 -17
  464. package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
  465. package/dist/src/core/patch-manifest-files-affected.js +3 -3
  466. package/dist/src/core/patch-manifest-io.d.ts +14 -14
  467. package/dist/src/core/patch-manifest-io.js +35 -34
  468. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  469. package/dist/src/core/patch-manifest-query.js +4 -4
  470. package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
  471. package/dist/src/core/patch-manifest-resolve.js +7 -7
  472. package/dist/src/core/patch-manifest-validate.js +3 -3
  473. package/dist/src/core/patch-manifest.d.ts +2 -2
  474. package/dist/src/core/patch-manifest.js +2 -2
  475. package/dist/src/core/patch-parse.d.ts +32 -21
  476. package/dist/src/core/patch-parse.js +40 -15
  477. package/dist/src/core/patch-policy.js +15 -27
  478. package/dist/src/core/patch-registration-refs.d.ts +4 -4
  479. package/dist/src/core/patch-registration-refs.js +7 -7
  480. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  481. package/dist/src/core/patch-source-metadata.js +0 -4
  482. package/dist/src/core/patch-transform.d.ts +8 -16
  483. package/dist/src/core/patch-transform.js +13 -23
  484. package/dist/src/core/process-cpu-time.d.ts +1 -1
  485. package/dist/src/core/process-cpu-time.js +6 -6
  486. package/dist/src/core/rebase-session.d.ts +9 -15
  487. package/dist/src/core/rebase-session.js +13 -25
  488. package/dist/src/core/register-browser-content.js +3 -2
  489. package/dist/src/core/register-browser-test.js +2 -1
  490. package/dist/src/core/register-module.js +2 -1
  491. package/dist/src/core/register-result.d.ts +1 -1
  492. package/dist/src/core/register-result.js +1 -1
  493. package/dist/src/core/register-scaffold.d.ts +2 -2
  494. package/dist/src/core/register-scaffold.js +8 -7
  495. package/dist/src/core/register-shared-css.d.ts +3 -3
  496. package/dist/src/core/register-shared-css.js +6 -5
  497. package/dist/src/core/register-xpcshell-test.d.ts +2 -2
  498. package/dist/src/core/register-xpcshell-test.js +2 -2
  499. package/dist/src/core/run-log-redact.d.ts +38 -0
  500. package/dist/src/core/run-log-redact.js +69 -0
  501. package/dist/src/core/run-log.d.ts +21 -10
  502. package/dist/src/core/run-log.js +76 -27
  503. package/dist/src/core/shared-ftl.d.ts +2 -2
  504. package/dist/src/core/shared-ftl.js +6 -6
  505. package/dist/src/core/signal-critical.d.ts +2 -2
  506. package/dist/src/core/signal-critical.js +4 -6
  507. package/dist/src/core/smoke-patterns.d.ts +5 -6
  508. package/dist/src/core/smoke-patterns.js +15 -20
  509. package/dist/src/core/state-file.d.ts +15 -4
  510. package/dist/src/core/state-file.js +14 -1
  511. package/dist/src/core/status-binary.d.ts +8 -8
  512. package/dist/src/core/status-binary.js +12 -12
  513. package/dist/src/core/status-classify.d.ts +17 -17
  514. package/dist/src/core/status-classify.js +13 -12
  515. package/dist/src/core/test-changed-prefs.d.ts +12 -12
  516. package/dist/src/core/test-changed-prefs.js +40 -25
  517. package/dist/src/core/test-harness-crash.d.ts +39 -39
  518. package/dist/src/core/test-harness-crash.js +69 -69
  519. package/dist/src/core/test-harness-output.d.ts +7 -7
  520. package/dist/src/core/test-harness-output.js +7 -7
  521. package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
  522. package/dist/src/core/test-harness-verdict-notes.js +4 -4
  523. package/dist/src/core/test-path-scope.d.ts +8 -8
  524. package/dist/src/core/test-path-scope.js +11 -11
  525. package/dist/src/core/test-stale-check.d.ts +22 -23
  526. package/dist/src/core/test-stale-check.js +31 -30
  527. package/dist/src/core/test-stale-symlink.d.ts +1 -1
  528. package/dist/src/core/test-stale-symlink.js +1 -1
  529. package/dist/src/core/test-stall-triage.d.ts +9 -9
  530. package/dist/src/core/test-stall-triage.js +22 -22
  531. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  532. package/dist/src/core/test-xpcshell-retry.js +14 -11
  533. package/dist/src/core/token-category.d.ts +35 -2
  534. package/dist/src/core/token-category.js +67 -58
  535. package/dist/src/core/token-coverage.js +4 -5
  536. package/dist/src/core/token-dark-mode.d.ts +9 -9
  537. package/dist/src/core/token-dark-mode.js +13 -25
  538. package/dist/src/core/token-docs.d.ts +1 -1
  539. package/dist/src/core/token-inventory.d.ts +56 -0
  540. package/dist/src/core/token-inventory.js +109 -0
  541. package/dist/src/core/token-manager.d.ts +4 -4
  542. package/dist/src/core/token-manager.js +22 -22
  543. package/dist/src/core/token-scaffold.d.ts +4 -4
  544. package/dist/src/core/token-scaffold.js +4 -4
  545. package/dist/src/core/token-variant.d.ts +14 -14
  546. package/dist/src/core/token-variant.js +52 -53
  547. package/dist/src/core/toolchain-preflight.d.ts +15 -15
  548. package/dist/src/core/toolchain-preflight.js +23 -23
  549. package/dist/src/core/tree-cow.d.ts +3 -5
  550. package/dist/src/core/tree-cow.js +8 -8
  551. package/dist/src/core/tree-guard.d.ts +3 -3
  552. package/dist/src/core/tree-guard.js +23 -23
  553. package/dist/src/core/tree-store.d.ts +15 -15
  554. package/dist/src/core/tree-store.js +39 -38
  555. package/dist/src/core/typecheck-shim.d.ts +16 -15
  556. package/dist/src/core/typecheck-shim.js +26 -25
  557. package/dist/src/core/typecheck.d.ts +12 -12
  558. package/dist/src/core/typecheck.js +33 -33
  559. package/dist/src/core/wire-destroy.d.ts +2 -2
  560. package/dist/src/core/wire-destroy.js +5 -5
  561. package/dist/src/core/wire-dom-fragment.d.ts +3 -3
  562. package/dist/src/core/wire-dom-fragment.js +12 -23
  563. package/dist/src/core/wire-init.d.ts +2 -2
  564. package/dist/src/core/wire-init.js +7 -7
  565. package/dist/src/core/wire-subscript.d.ts +1 -1
  566. package/dist/src/core/wire-subscript.js +3 -3
  567. package/dist/src/core/wire-utils.d.ts +9 -9
  568. package/dist/src/core/wire-utils.js +16 -28
  569. package/dist/src/core/xpcshell-appdir.d.ts +20 -20
  570. package/dist/src/core/xpcshell-appdir.js +28 -30
  571. package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
  572. package/dist/src/core/xpcshell-profile-dir.js +7 -7
  573. package/dist/src/errors/base.d.ts +69 -16
  574. package/dist/src/errors/base.js +95 -26
  575. package/dist/src/errors/build.d.ts +6 -6
  576. package/dist/src/errors/build.js +26 -34
  577. package/dist/src/errors/codes.d.ts +10 -10
  578. package/dist/src/errors/codes.js +10 -10
  579. package/dist/src/errors/config.d.ts +0 -14
  580. package/dist/src/errors/config.js +13 -34
  581. package/dist/src/errors/download.d.ts +13 -0
  582. package/dist/src/errors/download.js +53 -24
  583. package/dist/src/errors/furnace.d.ts +2 -2
  584. package/dist/src/errors/furnace.js +8 -9
  585. package/dist/src/errors/git.d.ts +9 -9
  586. package/dist/src/errors/git.js +21 -31
  587. package/dist/src/errors/patch.d.ts +3 -3
  588. package/dist/src/errors/patch.js +11 -13
  589. package/dist/src/errors/rebase.d.ts +1 -1
  590. package/dist/src/errors/rebase.js +8 -8
  591. package/dist/src/errors/run.d.ts +1 -1
  592. package/dist/src/errors/run.js +1 -1
  593. package/dist/src/index.d.ts +4 -4
  594. package/dist/src/index.js +4 -4
  595. package/dist/src/types/commands/options.d.ts +155 -200
  596. package/dist/src/types/commands/patches.d.ts +19 -19
  597. package/dist/src/types/commands/project.d.ts +3 -3
  598. package/dist/src/types/config.d.ts +52 -19
  599. package/dist/src/types/furnace.d.ts +17 -17
  600. package/dist/src/types/index.d.ts +0 -1
  601. package/dist/src/types/json.d.ts +3 -3
  602. package/dist/src/types/json.js +2 -2
  603. package/dist/src/types/typecheck.d.ts +3 -3
  604. package/dist/src/utils/assert.d.ts +4 -16
  605. package/dist/src/utils/assert.js +7 -24
  606. package/dist/src/utils/build-info.d.ts +6 -6
  607. package/dist/src/utils/build-info.js +6 -6
  608. package/dist/src/utils/child-env.d.ts +7 -6
  609. package/dist/src/utils/child-env.js +5 -5
  610. package/dist/src/utils/concurrency.d.ts +2 -2
  611. package/dist/src/utils/concurrency.js +2 -2
  612. package/dist/src/utils/elapsed.js +10 -1
  613. package/dist/src/utils/errors.d.ts +8 -8
  614. package/dist/src/utils/errors.js +8 -8
  615. package/dist/src/utils/fs.d.ts +1 -1
  616. package/dist/src/utils/fs.js +15 -20
  617. package/dist/src/utils/hash.d.ts +12 -0
  618. package/dist/src/utils/hash.js +16 -0
  619. package/dist/src/utils/line-dispatch.d.ts +15 -0
  620. package/dist/src/utils/line-dispatch.js +48 -0
  621. package/dist/src/utils/logger.d.ts +4 -4
  622. package/dist/src/utils/logger.js +11 -11
  623. package/dist/src/utils/machine-output.js +2 -2
  624. package/dist/src/utils/options.d.ts +14 -20
  625. package/dist/src/utils/options.js +26 -27
  626. package/dist/src/utils/package-root.js +5 -14
  627. package/dist/src/utils/paths.d.ts +4 -4
  628. package/dist/src/utils/paths.js +4 -4
  629. package/dist/src/utils/platform.d.ts +0 -4
  630. package/dist/src/utils/process-group.d.ts +10 -9
  631. package/dist/src/utils/process-group.js +37 -36
  632. package/dist/src/utils/process.d.ts +70 -55
  633. package/dist/src/utils/process.js +129 -179
  634. package/dist/src/utils/ps-duration.d.ts +4 -4
  635. package/dist/src/utils/ps-duration.js +9 -9
  636. package/dist/src/utils/regex.d.ts +4 -4
  637. package/dist/src/utils/regex.js +7 -7
  638. package/dist/src/utils/sleep.d.ts +26 -0
  639. package/dist/src/utils/sleep.js +31 -0
  640. package/dist/src/utils/stdio-drain.d.ts +7 -7
  641. package/dist/src/utils/stdio-drain.js +8 -8
  642. package/dist/src/utils/validation.d.ts +12 -49
  643. package/dist/src/utils/validation.js +26 -36
  644. package/docs/README.md +2 -2
  645. package/docs/configuration.md +163 -69
  646. package/docs/exit-codes.md +66 -49
  647. package/docs/furnace.md +20 -19
  648. package/docs/lifecycle-invariants.md +414 -247
  649. package/docs/machine-output.md +58 -34
  650. package/docs/patch-workflow.md +48 -44
  651. package/docs/run-logs.md +72 -28
  652. package/docs/testing.md +105 -98
  653. package/docs/verification-trees.md +23 -22
  654. package/package.json +7 -6
  655. package/dist/src/commands/rebase.d.ts +0 -4
  656. package/dist/src/commands/rebase.js +0 -5
  657. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  658. package/dist/src/core/patch-artifact-normalize.js +0 -24
  659. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  660. package/dist/src/core/patch-lint-reexports.js +0 -8
  661. package/dist/src/core/wire-targets.d.ts +0 -7
  662. package/dist/src/core/wire-targets.js +0 -8
@@ -11,27 +11,16 @@ import { chunkPathspecs, ensureGit, git } from './git-base.js';
11
11
  * @param filePath - Path to the file (relative to repo)
12
12
  */
13
13
  export async function restoreTrackedPath(repoDir, filePath) {
14
- await ensureGit();
15
14
  await git(['restore', '--source', 'HEAD', '--staged', '--worktree', '--', filePath], repoDir);
16
15
  }
17
- /**
18
- * Removes an untracked path from disk.
19
- * @param repoDir - Repository directory
20
- * @param filePath - Path to the file (relative to repo)
21
- */
22
- async function removeUntrackedPath(repoDir, filePath) {
23
- const fullPath = join(repoDir, filePath);
24
- await removeFile(fullPath);
25
- }
26
16
  /**
27
17
  * Removes a path that is present only in the index/worktree and not in HEAD.
28
18
  * @param repoDir - Repository directory
29
19
  * @param filePath - Path to remove
30
20
  */
31
21
  async function removeAddedPath(repoDir, filePath) {
32
- await ensureGit();
33
22
  await git(['reset', 'HEAD', '--', filePath], repoDir);
34
- await removeUntrackedPath(repoDir, filePath);
23
+ await removeFile(join(repoDir, filePath));
35
24
  }
36
25
  /**
37
26
  * Discards a status entry according to its git state.
@@ -40,7 +29,7 @@ async function removeAddedPath(repoDir, filePath) {
40
29
  */
41
30
  export async function discardStatusEntry(repoDir, entry) {
42
31
  if (entry.isUntracked) {
43
- await removeUntrackedPath(repoDir, entry.file);
32
+ await removeFile(join(repoDir, entry.file));
44
33
  return;
45
34
  }
46
35
  if (entry.isRenameOrCopy && entry.originalPath) {
@@ -65,7 +54,6 @@ export async function discardStatusEntry(repoDir, entry) {
65
54
  * @param files - File paths to stage (relative to repo)
66
55
  */
67
56
  export async function stageFiles(repoDir, files) {
68
- await ensureGit();
69
57
  await git(['add', '--', ...files], repoDir);
70
58
  }
71
59
  /**
@@ -74,7 +62,6 @@ export async function stageFiles(repoDir, files) {
74
62
  * @param files - File paths to unstage (relative to repo)
75
63
  */
76
64
  export async function unstageFiles(repoDir, files) {
77
- await ensureGit();
78
65
  await git(['reset', 'HEAD', '--', ...files], repoDir);
79
66
  }
80
67
  /**
@@ -84,16 +71,15 @@ export async function unstageFiles(repoDir, files) {
84
71
  * @returns true if file exists in HEAD
85
72
  */
86
73
  export async function fileExistsInHead(repoDir, filePath) {
87
- await ensureGit();
88
74
  return (await git(['ls-tree', 'HEAD', '--', filePath], repoDir)).trim().length > 0;
89
75
  }
90
76
  /**
91
77
  * Batched equivalent of {@link fileExistsInHead}: returns the subset of
92
78
  * `files` that are tracked in HEAD, using a single `git ls-tree` per ARG_MAX
93
- * chunk instead of one spawn per file. This is the cold-run hot path — a
94
- * Firefox-sized checkout has hundreds of affected files.
79
+ * chunk instead of one spawn per file. This is the cold-run hot path, and
80
+ * a Firefox-sized checkout has hundreds of affected files.
95
81
  *
96
- * `-r` lists nested blobs by full repo-relative path; `--name-only -z` makes
82
+ * `-r` lists nested blobs by full repo-relative path. `--name-only -z` makes
97
83
  * the output a trivial NUL-split with no quoting to undo. Membership in the
98
84
  * returned Set is exactly `await fileExistsInHead(repoDir, file)` for any
99
85
  * non-directory `file`. Throws (via {@link git}) when HEAD itself is
@@ -107,13 +93,12 @@ export async function listTrackedInHead(repoDir, files) {
107
93
  const tracked = new Set();
108
94
  if (files.length === 0)
109
95
  return tracked;
110
- await ensureGit();
111
96
  const wanted = new Set(files);
112
97
  for (const chunk of chunkPathspecs(files)) {
113
98
  const output = await git(['ls-tree', '-r', 'HEAD', '--name-only', '-z', '--', ...chunk], repoDir);
114
99
  for (const name of output.split('\0')) {
115
100
  // `ls-tree -r` can surface entries beyond the literal inputs only when an
116
- // input is itself a directory in HEAD; intersect with `wanted` so the
101
+ // input is itself a directory in HEAD. Intersect with `wanted` so the
117
102
  // result is always a subset of the requested files, never a superset.
118
103
  if (name.length > 0 && wanted.has(name))
119
104
  tracked.add(name);
@@ -130,10 +115,10 @@ export async function listTrackedInHead(repoDir, files) {
130
115
  * Uses {@link import('../utils/process.js').exec} rather than {@link git}
131
116
  * (which throws on a non-zero exit) because `git hash-object f1 f2 …` is
132
117
  * all-or-nothing: it aborts at the first unreadable path and emits nothing
133
- * for the rest. To keep the per-file contract — where one bad path zeroes
134
- * only its own index line — a chunk that does not return exactly one hash
118
+ * for the rest. To keep the per-file contract, where one bad path zeroes
119
+ * only its own index line, a chunk that does not return exactly one hash
135
120
  * per input falls back to hashing that chunk's paths individually. A path
136
- * that is still unhashable is left out of the map; the caller applies the
121
+ * that is still unhashable is left out of the map. The caller applies the
137
122
  * `0000000000` zero-hash fallback for any miss. Hashing stays in git rather
138
123
  * than in-process so filters and `.gitattributes` are applied per path and
139
124
  * the result cannot diverge under `core.autocrlf`/`text` attributes.
@@ -151,8 +136,8 @@ export async function hashObjectBatch(repoDir, fullPaths) {
151
136
  const result = await exec('git', ['hash-object', '--', ...chunk], { cwd: repoDir });
152
137
  const lines = result.stdout.split('\n').filter((line) => line.length > 0);
153
138
  if (result.exitCode === 0 && lines.length === chunk.length) {
154
- for (let i = 0; i < chunk.length; i++) {
155
- hashes.set(chunk[i], lines[i]);
139
+ for (const [i, path] of chunk.entries()) {
140
+ hashes.set(path, lines[i]);
156
141
  }
157
142
  continue;
158
143
  }
@@ -190,15 +175,6 @@ export async function getFileContentAtRef(repoDir, filePath, ref = 'HEAD') {
190
175
  }
191
176
  return result.stdout;
192
177
  }
193
- /**
194
- * Gets the content of a file from HEAD commit.
195
- * @param repoDir - Repository directory
196
- * @param filePath - Path to the file (relative to repo)
197
- * @returns File content or null if file doesn't exist in HEAD
198
- */
199
- export async function getFileContentFromHead(repoDir, filePath) {
200
- return getFileContentAtRef(repoDir, filePath, 'HEAD');
201
- }
202
178
  /**
203
179
  * Checks if a file is binary by looking for NUL bytes in the first 8KB.
204
180
  * Uses the same heuristic as git.
@@ -1,25 +1,25 @@
1
1
  /**
2
- * Private-index scope for FireForge's READ-ONLY git plumbing.
2
+ * Private-index scope for FireForge's read-only git plumbing.
3
3
  *
4
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
5
+ * about (they never change tracked content), but they are not read-only to
6
6
  * git: both refresh the index's stat cache and write `.git/index` (through
7
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
8
+ * `fireforge verify` / `lint --per-patch` / `typecheck` a second writer of
9
9
  * the primary `engine/` checkout, even when the command was pointed at a CoW
10
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
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
15
+ * correct and stays. The defect is FireForge's own read-only commands
16
16
  * tripping it.
17
17
  *
18
- * The fix is the standard git one: point the plumbing at a PRIVATE index
18
+ * The fix is the standard git one: point the plumbing at a private index
19
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.
20
+ * Refreshes land there and are thrown away. The primary `.git/index` is
21
+ * never touched, and neither is `.git/index.lock`, which is what makes a
22
+ * concurrent `git status` fail outright rather than merely churn.
23
23
  *
24
24
  * Fail-open by design: if the git dir or the index cannot be resolved or
25
25
  * copied, the scope does not activate and the commands behave exactly as
@@ -43,8 +43,6 @@
43
43
  * @returns `{ GIT_INDEX_FILE }` when scoped, otherwise undefined
44
44
  */
45
45
  export declare function readOnlyGitIndexEnv(cwd: string): Record<string, string> | undefined;
46
- /** True while a private-index scope is installed (diagnostics and tests). */
47
- export declare function hasReadOnlyGitIndexScope(): boolean;
48
46
  /**
49
47
  * Runs `operation` with FireForge's git plumbing pointed at a private
50
48
  * index seeded from `repoDir`'s own, so the primary checkout's
@@ -58,7 +56,7 @@ export declare function withPrivateGitIndex<T>(repoDir: string, operation: () =>
58
56
  /**
59
57
  * A private index file plus the cleanup that removes it.
60
58
  *
61
- * `env` is meant to be handed to a SINGLE git invocation (or a small
59
+ * `env` is meant to be handed to a single git invocation (or a small
62
60
  * sequence of them), rather than installed process-wide the way
63
61
  * {@link withPrivateGitIndex} installs a scope.
64
62
  */
@@ -70,20 +68,20 @@ export interface DisposableGitIndex {
70
68
  }
71
69
  /**
72
70
  * 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.
71
+ * needs to write the index without the write being visible to anyone else.
74
72
  *
75
73
  * The distinction from {@link withPrivateGitIndex} matters. That one exists
76
74
  * so a read-only command's incidental index refreshes do not touch the
77
75
  * primary checkout, and it is process-global, non-reentrant, and fail-open,
78
76
  * 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
77
+ * write is intentional and whose visibility is the defect: it is per-call, so
80
78
  * two concurrent callers cannot collide, and it never depends on an ambient
81
79
  * scope having been installed by whichever command happens to be running.
82
80
  *
83
81
  * The seed is a plain copy, which is safe against a concurrent writer: git
84
82
  * writes the index through `index.lock` and an atomic rename, so a reader
85
83
  * 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,
84
+ * required rather than merely tidy: an empty index makes a tracked,
87
85
  * unmodified file look like a fresh add.
88
86
  *
89
87
  * @param repoDir - Repository whose index should be shadowed
@@ -1,26 +1,26 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * Private-index scope for FireForge's READ-ONLY git plumbing.
3
+ * Private-index scope for FireForge's read-only git plumbing.
4
4
  *
5
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
6
+ * about (they never change tracked content), but they are not read-only to
7
7
  * git: both refresh the index's stat cache and write `.git/index` (through
8
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
9
+ * `fireforge verify` / `lint --per-patch` / `typecheck` a second writer of
10
10
  * the primary `engine/` checkout, even when the command was pointed at a CoW
11
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
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
16
+ * correct and stays. The defect is FireForge's own read-only commands
17
17
  * tripping it.
18
18
  *
19
- * The fix is the standard git one: point the plumbing at a PRIVATE index
19
+ * The fix is the standard git one: point the plumbing at a private index
20
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.
21
+ * Refreshes land there and are thrown away. The primary `.git/index` is
22
+ * never touched, and neither is `.git/index.lock`, which is what makes a
23
+ * concurrent `git status` fail outright rather than merely churn.
24
24
  *
25
25
  * Fail-open by design: if the git dir or the index cannot be resolved or
26
26
  * copied, the scope does not activate and the commands behave exactly as
@@ -64,13 +64,9 @@ export function readOnlyGitIndexEnv(cwd) {
64
64
  return undefined;
65
65
  return { GIT_INDEX_FILE: activeScope.indexFile };
66
66
  }
67
- /** True while a private-index scope is installed (diagnostics and tests). */
68
- export function hasReadOnlyGitIndexScope() {
69
- return activeScope !== undefined;
70
- }
71
67
  /**
72
68
  * Resolves a repository's git directory. Returns undefined for anything
73
- * that is not a readable git checkout — `engine/` is not always one
69
+ * that is not a readable git checkout. `engine/` is not always one
74
70
  * (`fireforge download` extracts a source tarball).
75
71
  */
76
72
  async function resolveGitDir(repoDir) {
@@ -119,20 +115,20 @@ export async function withPrivateGitIndex(repoDir, operation) {
119
115
  }
120
116
  /**
121
117
  * 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.
118
+ * needs to write the index without the write being visible to anyone else.
123
119
  *
124
120
  * The distinction from {@link withPrivateGitIndex} matters. That one exists
125
121
  * so a read-only command's incidental index refreshes do not touch the
126
122
  * primary checkout, and it is process-global, non-reentrant, and fail-open,
127
123
  * 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
124
+ * write is intentional and whose visibility is the defect: it is per-call, so
129
125
  * two concurrent callers cannot collide, and it never depends on an ambient
130
126
  * scope having been installed by whichever command happens to be running.
131
127
  *
132
128
  * The seed is a plain copy, which is safe against a concurrent writer: git
133
129
  * writes the index through `index.lock` and an atomic rename, so a reader
134
130
  * 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,
131
+ * required rather than merely tidy: an empty index makes a tracked,
136
132
  * unmodified file look like a fresh add.
137
133
  *
138
134
  * @param repoDir - Repository whose index should be shadowed
@@ -1,6 +1,13 @@
1
1
  import type { GitStatusEntry } from './git-base.js';
2
2
  /**
3
3
  * Parses NUL-delimited porcelain status output.
4
+ *
5
+ * A rename or copy occupies two NUL records (`XY new\0old\0`), and the `R`/`C`
6
+ * may sit in either column: git >= 2.18 detects renames in the worktree too
7
+ * (`status.renames`), emitting ` R new\0old\0` for an unstaged rename and
8
+ * `RM`/`R ` for a staged one. Only consuming the second record for an index
9
+ * `R`/`C` turned the worktree form's `old` field into a bogus extra entry
10
+ * whose status was whatever its first two path characters happened to be.
4
11
  * @param output - Raw git status output
5
12
  * @returns Parsed entries
6
13
  */
@@ -23,8 +30,8 @@ export declare function resolveMaxUntrackedFilesPerDir(): number;
23
30
  *
24
31
  * Expansion is capped per directory (FIREFORGE_MAX_UNTRACKED_FILES, default
25
32
  * 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.
33
+ * an interrupted download (unborn HEAD, the entire ~300k file tree
34
+ * untracked) enumerates and prints every file.
28
35
  *
29
36
  * @param repoDir - Repository directory
30
37
  * @param entries - Parsed status entries
@@ -1,8 +1,25 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  import { warn } from '../utils/logger.js';
3
- import { ensureGit, git } from './git-base.js';
3
+ import { git } from './git-base.js';
4
+ /**
5
+ * True when a porcelain status column carries a rename or copy, i.e. the
6
+ * record is followed by a second NUL-terminated field holding the original
7
+ * path.
8
+ * @param column - A single status column character
9
+ * @returns Whether the column is `R` or `C`
10
+ */
11
+ function isRenameOrCopyColumn(column) {
12
+ return column === 'R' || column === 'C';
13
+ }
4
14
  /**
5
15
  * Parses NUL-delimited porcelain status output.
16
+ *
17
+ * A rename or copy occupies two NUL records (`XY new\0old\0`), and the `R`/`C`
18
+ * may sit in either column: git >= 2.18 detects renames in the worktree too
19
+ * (`status.renames`), emitting ` R new\0old\0` for an unstaged rename and
20
+ * `RM`/`R ` for a staged one. Only consuming the second record for an index
21
+ * `R`/`C` turned the worktree form's `old` field into a bogus extra entry
22
+ * whose status was whatever its first two path characters happened to be.
6
23
  * @param output - Raw git status output
7
24
  * @returns Parsed entries
8
25
  */
@@ -18,7 +35,7 @@ export function parsePorcelainStatus(output) {
18
35
  const worktreeStatus = record[1] ?? ' ';
19
36
  const status = `${indexStatus}${worktreeStatus}`;
20
37
  const pathField = record.slice(3);
21
- const isRenameOrCopy = indexStatus === 'R' || indexStatus === 'C';
38
+ const isRenameOrCopy = isRenameOrCopyColumn(indexStatus) || isRenameOrCopyColumn(worktreeStatus);
22
39
  const originalPath = isRenameOrCopy ? records[i + 1] : undefined;
23
40
  if (isRenameOrCopy) {
24
41
  i++;
@@ -42,7 +59,6 @@ export function parsePorcelainStatus(output) {
42
59
  * @returns Parsed git status entries
43
60
  */
44
61
  export async function getWorkingTreeStatus(repoDir) {
45
- await ensureGit();
46
62
  return parsePorcelainStatus(await git(['status', '--porcelain=v1', '-z'], repoDir));
47
63
  }
48
64
  /** Default per-directory cap for untracked-directory expansion. */
@@ -57,7 +73,7 @@ export function resolveMaxUntrackedFilesPerDir() {
57
73
  return DEFAULT_MAX_UNTRACKED_FILES_PER_DIR;
58
74
  const parsed = Number.parseInt(raw, 10);
59
75
  if (!Number.isFinite(parsed) || parsed <= 0) {
60
- warn(`Ignoring FIREFORGE_MAX_UNTRACKED_FILES="${raw}" — expected a positive integer. Falling back to ${String(DEFAULT_MAX_UNTRACKED_FILES_PER_DIR)}.`);
76
+ warn(`Ignoring FIREFORGE_MAX_UNTRACKED_FILES="${raw}" — expected a positive integer. Falling back to ${DEFAULT_MAX_UNTRACKED_FILES_PER_DIR}.`);
61
77
  return DEFAULT_MAX_UNTRACKED_FILES_PER_DIR;
62
78
  }
63
79
  return parsed;
@@ -68,8 +84,8 @@ export function resolveMaxUntrackedFilesPerDir() {
68
84
  *
69
85
  * Expansion is capped per directory (FIREFORGE_MAX_UNTRACKED_FILES, default
70
86
  * 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.
87
+ * an interrupted download (unborn HEAD, the entire ~300k file tree
88
+ * untracked) enumerates and prints every file.
73
89
  *
74
90
  * @param repoDir - Repository directory
75
91
  * @param entries - Parsed status entries
@@ -86,7 +102,7 @@ export async function expandUntrackedDirectoryEntries(repoDir, entries) {
86
102
  }
87
103
  const individualFiles = await getUntrackedFilesInDir(repoDir, entry.file);
88
104
  if (individualFiles.length > maxPerDir) {
89
- warn(`Untracked directory ${entry.file} contains ${String(individualFiles.length)} files — only the first ${String(maxPerDir)} are listed. Add a .gitignore entry or clean the directory.`);
105
+ warn(`Untracked directory ${entry.file} contains ${individualFiles.length} files — only the first ${maxPerDir} are listed. Add a .gitignore entry or clean the directory.`);
90
106
  }
91
107
  for (const file of individualFiles.slice(0, maxPerDir)) {
92
108
  expanded.push({
@@ -108,7 +124,6 @@ export async function expandUntrackedDirectoryEntries(repoDir, entries) {
108
124
  * @returns List of untracked file paths
109
125
  */
110
126
  export async function getUntrackedFiles(repoDir) {
111
- await ensureGit();
112
127
  // Use git ls-files to get all untracked files, which properly expands directories
113
128
  const output = await git(['ls-files', '--others', '--exclude-standard'], repoDir);
114
129
  return output.split('\n').filter((line) => line.trim().length > 0);
@@ -121,7 +136,6 @@ export async function getUntrackedFiles(repoDir) {
121
136
  * @returns List of untracked file paths relative to repo root
122
137
  */
123
138
  export async function getUntrackedFilesInDir(repoDir, dir) {
124
- await ensureGit();
125
139
  const output = await git(['ls-files', '--others', '--exclude-standard', '--', dir], repoDir);
126
140
  return output.split('\n').filter((line) => line.trim().length > 0);
127
141
  }
@@ -133,7 +147,6 @@ export async function getUntrackedFilesInDir(repoDir, dir) {
133
147
  * @returns List of modified file paths relative to repo root
134
148
  */
135
149
  export async function getModifiedFilesInDir(repoDir, dir) {
136
- await ensureGit();
137
150
  const output = await git(['diff', '--name-only', 'HEAD', '--', dir], repoDir);
138
151
  return output.split('\n').filter((line) => line.trim().length > 0);
139
152
  }
@@ -146,7 +159,6 @@ export async function getModifiedFilesInDir(repoDir, dir) {
146
159
  export async function getDirtyFiles(repoDir, files) {
147
160
  if (files.length === 0)
148
161
  return [];
149
- await ensureGit();
150
162
  // Check both staged and unstaged changes for the given files
151
163
  const trackedOutput = await git(['diff', '--name-only', 'HEAD', '--', ...files], repoDir);
152
164
  const tracked = trackedOutput.split('\n').filter((line) => line.trim().length > 0);
@@ -17,7 +17,7 @@ export declare function isGitRepository(dir: string): Promise<boolean>;
17
17
  export declare function ensureOriginRemote(dir: string): Promise<void>;
18
18
  /**
19
19
  * Stages all files in the repository.
20
- * Tries a monolithic `git add -A` first; if that times out, falls back to
20
+ * Tries a monolithic `git add -A` first. If that times out, falls back to
21
21
  * directory-by-directory staged adds.
22
22
  */
23
23
  export declare function stageAllFiles(dir: string, options?: {
@@ -56,8 +56,8 @@ export declare function applyPatch(patchPath: string, repoDir: string, options?:
56
56
  * @param patchPath - Path to the patch file
57
57
  * @param repoDir - Repository directory
58
58
  * @param options.reject - Fall back to `git apply --reject`
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
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
61
  * touched by previously applied patches in the same run: two overlapping
62
62
  * patches (an `--allow-overlap` queue) share files, and a blanket
63
63
  * `checkout HEAD` would wipe the earlier patch's changes from the shared
@@ -103,12 +103,6 @@ export declare function getCurrentBranch(repoDir: string): Promise<string>;
103
103
  * @param repoDir - Repository directory
104
104
  */
105
105
  export declare function resetChanges(repoDir: string): Promise<void>;
106
- /**
107
- * Creates a commit with all current changes.
108
- * @param repoDir - Repository directory
109
- * @param message - Commit message
110
- */
111
- export declare function commit(repoDir: string, message: string): Promise<void>;
112
106
  /**
113
107
  * Gets the status of files with their status codes.
114
108
  * @param repoDir - Repository directory
@@ -41,8 +41,8 @@ export async function ensureOriginRemote(dir) {
41
41
  const GIT_ADD_ENV = { GIT_INDEX_THREADS: '0' };
42
42
  /**
43
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
44
+ * timeout (SIGTERM → exit code 143) or an AbortError raised by
45
+ * `AbortSignal.timeout`. Node's `child_process` layer rejects with an
46
46
  * AbortError when the signal fires, so both shapes have to be recognised.
47
47
  */
48
48
  function isTimeoutError(error) {
@@ -76,7 +76,7 @@ async function cleanupIndexLock(dir) {
76
76
  * other exclusion mechanism git considers, e.g. `.git/info/exclude`,
77
77
  * core.excludesFile). Used by the chunked staging fallback to skip entries
78
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
79
+ * following paths are ignored by one of your .gitignore files" error, a
80
80
  * state the monolithic `git add -A` path silently handles. A Firefox
81
81
  * checkout's top-level `.vscode/` is the common case: without this, the
82
82
  * chunked invocation aborts the whole fallback and turns a recoverable
@@ -93,7 +93,7 @@ async function isPathIgnored(dir, relativePath) {
93
93
  return true;
94
94
  if (result.exitCode === 1)
95
95
  return false;
96
- // Any other shape is "we don't know" — let the caller proceed and
96
+ // Any other shape is "we don't know", so let the caller proceed and
97
97
  // surface the real error if `git add` rejects the path.
98
98
  return false;
99
99
  }
@@ -104,7 +104,7 @@ async function isPathIgnored(dir, relativePath) {
104
104
  *
105
105
  * A chunked pass that hits its own timeout raises a typed
106
106
  * {@link GitIndexingTimeoutError} rather than an opaque `AbortError: The
107
- * operation was aborted`; the typed error carries the environment-variable
107
+ * operation was aborted`. The typed error carries the environment-variable
108
108
  * override so the operator can extend the budget and re-run.
109
109
  */
110
110
  async function stageAllFilesChunked(dir, scan, options = {}) {
@@ -134,7 +134,7 @@ async function stageAllFilesChunked(dir, scan, options = {}) {
134
134
  options.onProgress?.(`Staging directory ${stagedDirectories}/${directories.length}: ${dirName}/...`);
135
135
  await runChunk(['add', '--', dirName], dirName);
136
136
  }
137
- // Stage any top-level files (excluding gitignored ones — `git add`
137
+ // Stage any top-level files (excluding gitignored ones, because `git add`
138
138
  // on an explicit ignored path errors out, which would otherwise
139
139
  // abort the chunked fallback after the monolithic path has already
140
140
  // timed out).
@@ -154,7 +154,7 @@ async function stageAllFilesChunked(dir, scan, options = {}) {
154
154
  /**
155
155
  * Interval between heartbeat progress messages during the monolithic
156
156
  * `git add -A`. On a fresh ~600 MB Firefox tree the monolithic add runs
157
- * 60–120 seconds, during which git emits nothing to stdout/stderr. Without a
157
+ * 60 to 120 seconds, during which git emits nothing to stdout/stderr. Without a
158
158
  * heartbeat the CLI spinner stays pinned on "Indexing Firefox source …" for
159
159
  * the full window and looks hung, which invites a SIGINT mid-way.
160
160
  */
@@ -175,7 +175,7 @@ async function scanTopLevelSource(dir) {
175
175
  }
176
176
  /**
177
177
  * Stages all files in the repository.
178
- * Tries a monolithic `git add -A` first; if that times out, falls back to
178
+ * Tries a monolithic `git add -A` first. If that times out, falls back to
179
179
  * directory-by-directory staged adds.
180
180
  */
181
181
  export async function stageAllFiles(dir, options = {}) {
@@ -184,7 +184,7 @@ export async function stageAllFiles(dir, options = {}) {
184
184
  reportProgress?.('Scanning Firefox source tree before indexing...');
185
185
  const scan = await scanTopLevelSource(dir);
186
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'}`);
187
- // The heartbeat tracks a PER-PHASE start timestamp and labels each tick
187
+ // The heartbeat tracks a per-phase start timestamp and labels each tick
188
188
  // with the phase. A single start time set at function entry reports
189
189
  // cumulative elapsed for the whole `stageAllFiles` invocation, so after a
190
190
  // monolithic timeout the chunked-phase ticks name numbers that already
@@ -225,15 +225,8 @@ export async function stageAllFiles(dir, options = {}) {
225
225
  // monolithic budget forward.
226
226
  phase = 'chunked';
227
227
  phaseStartedAt = Date.now();
228
- try {
229
- await stageAllFilesChunked(dir, scan, options);
230
- reportProgress?.('Git phase complete: chunked source indexing finished.');
231
- }
232
- catch (error) {
233
- if (error instanceof GitIndexingTimeoutError)
234
- throw error;
235
- throw error;
236
- }
228
+ await stageAllFilesChunked(dir, scan, options);
229
+ reportProgress?.('Git phase complete: chunked source indexing finished.');
237
230
  }
238
231
  finally {
239
232
  if (heartbeatTimer)
@@ -285,10 +278,20 @@ export async function initRepository(dir, branchName = 'main', options = {}) {
285
278
  reportProgress('Configuring origin remote for build compatibility...');
286
279
  await git(['remote', 'add', 'origin', 'https://github.com/mozilla-firefox/firefox'], dir);
287
280
  reportProgress('Git phase complete: source git repository metadata initialized.');
281
+ await stageAndCommitSource(dir, reportProgress, 'Indexing Firefox source with git add -A (this can take several minutes on large trees)...');
282
+ }
283
+ /**
284
+ * The tail shared by {@link initRepository} and {@link resumeRepository}:
285
+ * normalizes the Firefox ignore files, stages the whole tree, and creates
286
+ * the initial source commit. Index-lock failures on either git step are
287
+ * wrapped into the typed lock error so both entry points report them the
288
+ * same way.
289
+ */
290
+ async function stageAndCommitSource(dir, reportProgress, stagingMessage) {
288
291
  reportProgress('Normalizing Firefox ignore files for Git-backed mach lint compatibility...');
289
292
  await ensureFirefoxIgnorefileCompatibility(dir);
290
293
  // Add all files
291
- reportProgress('Indexing Firefox source with git add -A (this can take several minutes on large trees)...');
294
+ reportProgress(stagingMessage);
292
295
  await assertNoGitIndexLock(dir);
293
296
  try {
294
297
  await stageAllFiles(dir, { onProgress: reportProgress });
@@ -310,7 +313,6 @@ export async function initRepository(dir, branchName = 'main', options = {}) {
310
313
  * cleans up stale locks, stages all files, and creates the initial commit.
311
314
  */
312
315
  export async function resumeRepository(dir, options = {}) {
313
- await ensureGit();
314
316
  const reportProgress = options.onProgress ?? (() => { });
315
317
  if (!(await isGitRepository(dir))) {
316
318
  throw new GitError('Not a git repository', 'resume');
@@ -324,24 +326,7 @@ export async function resumeRepository(dir, options = {}) {
324
326
  await cleanupIndexLock(dir);
325
327
  // Ensure origin remote exists (may have been added before the interrupt)
326
328
  await ensureOriginRemote(dir);
327
- reportProgress('Normalizing Firefox ignore files for Git-backed mach lint compatibility...');
328
- await ensureFirefoxIgnorefileCompatibility(dir);
329
- // Stage all files
330
- reportProgress('Indexing Firefox source (resuming)...');
331
- await assertNoGitIndexLock(dir);
332
- try {
333
- await stageAllFiles(dir, { onProgress: reportProgress });
334
- }
335
- catch (error) {
336
- throw await maybeWrapIndexLockError(dir, error);
337
- }
338
- // Create initial commit
339
- try {
340
- await createInitialSourceCommit(dir, reportProgress);
341
- }
342
- catch (error) {
343
- throw await maybeWrapIndexLockError(dir, error);
344
- }
329
+ await stageAndCommitSource(dir, reportProgress, 'Indexing Firefox source (resuming)...');
345
330
  }
346
331
  async function assertNoGitIndexLock(dir) {
347
332
  const lockPath = join(dir, '.git', 'index.lock');
@@ -407,8 +392,8 @@ export async function applyPatch(patchPath, repoDir, options = {}) {
407
392
  * @param patchPath - Path to the patch file
408
393
  * @param repoDir - Repository directory
409
394
  * @param options.reject - Fall back to `git apply --reject`
410
- * @param options.protectedFiles - Files that must NOT be reset to HEAD by the
411
- * recovery step. Callers applying a patch QUEUE pass the files already
395
+ * @param options.protectedFiles - Files that must not be reset to HEAD by the
396
+ * recovery step. Callers applying a patch queue pass the files already
412
397
  * touched by previously applied patches in the same run: two overlapping
413
398
  * patches (an `--allow-overlap` queue) share files, and a blanket
414
399
  * `checkout HEAD` would wipe the earlier patch's changes from the shared
@@ -439,14 +424,14 @@ export async function applyPatchIdempotent(patchPath, repoDir, options = {}) {
439
424
  await applyPatch(patchPath, repoDir, options);
440
425
  }
441
426
  /**
442
- * Restores `files` to their HEAD state, deleting files the patch would CREATE
443
- * (present on disk from a partial apply but absent in HEAD — for those,
427
+ * Restores `files` to their HEAD state, deleting files the patch would create
428
+ * (present on disk from a partial apply but absent in HEAD, where
444
429
  * `git checkout HEAD --` fails, and ignoring that failure leaves stray files
445
430
  * that make the subsequent forward apply die with "already exists" and no
446
431
  * hint why).
447
432
  *
448
433
  * Every git invocation is chunked via {@link chunkPathspecs} so a very large
449
- * patch cannot hit `E2BIG`, and every exit code is checked — a silent failed
434
+ * patch cannot hit `E2BIG`, and every exit code is checked. A silent failed
450
435
  * restore is the confusing state this recovery step exists to prevent.
451
436
  */
452
437
  async function restoreFilesToHead(repoDir, patchPath, files) {
@@ -499,7 +484,6 @@ export async function reversePatch(patchPath, repoDir) {
499
484
  * @returns True if there are uncommitted changes
500
485
  */
501
486
  export async function hasChanges(repoDir) {
502
- await ensureGit();
503
487
  const entries = await getWorkingTreeStatus(repoDir);
504
488
  return entries.length > 0;
505
489
  }
@@ -518,7 +502,6 @@ export function isMissingHeadError(error) {
518
502
  * @returns Commit hash
519
503
  */
520
504
  export async function getHead(repoDir) {
521
- await ensureGit();
522
505
  const output = await git(['rev-parse', 'HEAD'], repoDir);
523
506
  return output.trim();
524
507
  }
@@ -528,7 +511,6 @@ export async function getHead(repoDir) {
528
511
  * @returns Branch name
529
512
  */
530
513
  export async function getCurrentBranch(repoDir) {
531
- await ensureGit();
532
514
  const output = await git(['rev-parse', '--abbrev-ref', 'HEAD'], repoDir);
533
515
  return output.trim();
534
516
  }
@@ -537,7 +519,6 @@ export async function getCurrentBranch(repoDir) {
537
519
  * @param repoDir - Repository directory
538
520
  */
539
521
  export async function resetChanges(repoDir) {
540
- await ensureGit();
541
522
  try {
542
523
  await git(['reset', '--hard', 'HEAD'], repoDir);
543
524
  }
@@ -546,16 +527,6 @@ export async function resetChanges(repoDir) {
546
527
  }
547
528
  await git(['clean', '-fd'], repoDir);
548
529
  }
549
- /**
550
- * Creates a commit with all current changes.
551
- * @param repoDir - Repository directory
552
- * @param message - Commit message
553
- */
554
- export async function commit(repoDir, message) {
555
- await ensureGit();
556
- await stageAllFiles(repoDir);
557
- await git(['commit', '-m', message], repoDir);
558
- }
559
530
  /**
560
531
  * Gets the status of files with their status codes.
561
532
  * @param repoDir - Repository directory