@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
@@ -3,6 +3,7 @@ import { join } from 'node:path';
3
3
  import { InconclusiveVerdictError } from '../errors/base.js';
4
4
  import { toError } from '../utils/errors.js';
5
5
  import { info, warn } from '../utils/logger.js';
6
+ import { sleep } from '../utils/sleep.js';
6
7
  import { readLockStatus, withFileLock } from './file-lock.js';
7
8
  import { git } from './git-base.js';
8
9
  const ENGINE_SESSION_LOCK_PATH = join('.fireforge', 'engine-session.lock');
@@ -17,38 +18,38 @@ const MAX_WAIT_LOCK_MS = 3600 * 1000;
17
18
  /**
18
19
  * Formats the periodic operator-facing waiting line printed while `--wait-lock`
19
20
  * polls a contended engine session lock. The holder identification comes from
20
- * the lock's owner-metadata lines (`command=…`, `started=…`); an unreadable
21
+ * the lock's owner-metadata lines (`command=…`, `started=…`). An unreadable
21
22
  * owner file degrades to the anonymous form.
22
23
  */
23
24
  function formatWaitProgressLine(waitedMs, timeoutMs, holder, queue) {
24
- const progress = `${String(Math.round(waitedMs / 1000))}s of up to ${String(Math.round(timeoutMs / 1000))}s`;
25
+ const progress = `${Math.round(waitedMs / 1000)}s of up to ${Math.round(timeoutMs / 1000)}s`;
25
26
  // Queue position: under several concurrent sessions the wait
26
27
  // line alone left operators inferring their place from `ps`.
27
28
  const position = queue === undefined || queue.depth === 0
28
29
  ? ''
29
30
  : queue.ahead === 0
30
- ? ` You are next in a queue of ${String(queue.depth)}.`
31
- : ` ${String(queue.ahead)} ahead of you (queue of ${String(queue.depth)}).`;
31
+ ? ` You are next in a queue of ${queue.depth}.`
32
+ : ` ${queue.ahead} ahead of you (queue of ${queue.depth}).`;
32
33
  if (holder === undefined) {
33
34
  return `Waiting for the FireForge engine lock — ${progress}.${position}`;
34
35
  }
35
36
  const details = holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '';
36
- return `Waiting for the FireForge engine lock held by PID ${String(holder.pid)}${details} — ${progress}.${position}`;
37
+ return `Waiting for the FireForge engine lock held by PID ${holder.pid}${details} — ${progress}.${position}`;
37
38
  }
38
39
  /**
39
- * Formats the notice printed when the wait budget is EXTENDED because the
40
+ * Formats the notice printed when the wait budget is extended because the
40
41
  * queue advanced.
41
42
  *
42
- * Exported for direct unit testing. It names both figures — the requested
43
- * budget and the one now in force — because the whole point is that the two
44
- * have diverged, and an operator comparing the elapsed time against the
45
- * number they typed would otherwise conclude the timeout is broken.
43
+ * Exported for direct unit testing. It names both figures, the requested
44
+ * budget and the one now in force, because they have diverged and an
45
+ * operator comparing the elapsed time against the number they typed would
46
+ * otherwise conclude the timeout is broken.
46
47
  */
47
48
  export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
48
- const position = ahead === 0 ? 'you are now next' : `${String(ahead)} still ahead of you`;
49
+ const position = ahead === 0 ? 'you are now next' : `${ahead} still ahead of you`;
49
50
  return (`The queue advanced (${position}), so the engine-lock wait was extended to ` +
50
- `${String(Math.round(budgetMs / 1000))}s total (you asked for ` +
51
- `${String(Math.round(requestedMs / 1000))}s). A queue that stops moving still ` +
51
+ `${Math.round(budgetMs / 1000)}s total (you asked for ` +
52
+ `${Math.round(requestedMs / 1000)}s). A queue that stops moving still ` +
52
53
  `gives up on the budget you asked for.`);
53
54
  }
54
55
  /**
@@ -56,11 +57,11 @@ export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
56
57
  * one engine-mutating FireForge command touches `engine/` at a time.
57
58
  */
58
59
  export async function withEngineSessionLock(projectRoot, command, operation, options = {}) {
59
- // The lock is bypassed under test by default, and that is deliberate: the
60
+ // The lock is bypassed under test by default, on purpose: the
60
61
  // suite runs many engine-mutating commands in-process, which would either
61
62
  // serialise on this lock or deadlock outright.
62
63
  // `FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST=1` lets the lock's own
63
- // tests opt back in. Do not delete this branch — it is the reason the
64
+ // tests opt back in. Do not delete this branch. It is the reason the
64
65
  // suite completes.
65
66
  if (process.env['FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST'] !== '1' &&
66
67
  (process.env['NODE_ENV'] === 'test' || process.env['VITEST'] !== undefined)) {
@@ -77,30 +78,30 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
77
78
  onWaitProgress: ({ waitedMs, timeoutMs, holder, queue }) => {
78
79
  info(formatWaitProgressLine(waitedMs, timeoutMs, holder, queue));
79
80
  },
80
- // Say it out loud. An extension is the moment the budget the
81
+ // Announce it. An extension is the moment the budget the
81
82
  // operator asked for stops being the budget in force, and a wait
82
83
  // that silently outlives its own stated timeout is
83
- // indistinguishable from a broken one — which is how a downstream
84
+ // indistinguishable from a broken one, which is how a downstream
84
85
  // fork read it.
85
86
  onWaitExtended: ({ ahead, budgetMs }) => {
86
87
  info(formatWaitExtendedLine(ahead, budgetMs, waitLockSeconds * 1000));
87
88
  },
88
89
  // A budget that expires one position from the head pays the whole
89
- // wait for nothing. While the queue is still MOVING the wait is
90
- // working, so each advance renews the budget — up to a hard
91
- // ceiling, so a pathological queue cannot wait forever. The
92
- // no-flag fail-fast path deliberately gets none of this.
90
+ // wait for nothing. While the queue is still moving the wait is
91
+ // working, so each advance renews the budget, up to a hard
92
+ // ceiling so a pathological queue cannot wait forever. The
93
+ // no-flag fail-fast path gets none of this.
93
94
  extendWhileAdvancing: {
94
95
  maxWaitMs: Math.min(waitLockSeconds * 1000 * WAIT_EXTENSION_FACTOR, MAX_WAIT_LOCK_MS),
95
96
  },
96
97
  }
97
98
  : {}),
98
99
  ownerMetadata: [`command=${command}`, `started=${new Date().toISOString()}`],
99
- // Reason first, remedy second — the no-flag default waits
100
+ // Reason first, remedy second: the no-flag default waits
100
101
  // only ~1 s, so contention is the common case and `--wait-lock` is the
101
102
  // genuine remedy. withFileLock appends the holder identification from
102
103
  // the lock's owner metadata. The leading sentence is a message contract
103
- // (pinned by engine-session-lock tests); extend, don't reword.
104
+ // (pinned by engine-session-lock tests). Extend, don't reword.
104
105
  onTimeoutMessage: `Another FireForge engine-mutating command is already running. ` +
105
106
  `Wait for it to finish, then retry \`${command}\` — or pass --wait-lock [seconds] ` +
106
107
  `to wait for the lock (bare --wait-lock waits up to 60 seconds). ` +
@@ -109,8 +110,8 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
109
110
  });
110
111
  }
111
112
  /**
112
- * Inspects the project's engine-session lock without acquiring it —
113
- * backing `fireforge status --lock`.
113
+ * Inspects the project's engine-session lock without acquiring it, backing
114
+ * `fireforge status --lock`.
114
115
  *
115
116
  * @param projectRoot - Project root containing `.fireforge/`
116
117
  * @returns Holder identity, hold duration, and queue depth
@@ -128,21 +129,21 @@ export function formatEngineSessionLockStatus(snapshot, holderCpuSeconds) {
128
129
  }
129
130
  const elapsed = snapshot.heldForMs === undefined
130
131
  ? 'unknown duration'
131
- : `${String(Math.round(snapshot.heldForMs / 1000))}s`;
132
+ : `${Math.round(snapshot.heldForMs / 1000)}s`;
132
133
  const holder = snapshot.holder;
133
134
  const identity = holder === undefined
134
135
  ? 'held by an unidentified process (no readable owner record)'
135
- : `held by PID ${String(holder.pid)}${holder.alive ? '' : ' (NOT RUNNING — stale lock)'}` +
136
+ : `held by PID ${holder.pid}${holder.alive ? '' : ' (NOT RUNNING — stale lock)'}` +
136
137
  (holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '');
137
138
  const lines = [
138
139
  `Engine session lock: ${identity}, for ${elapsed}.`,
139
- `Queue depth: ${String(snapshot.queueDepth)} waiter(s).`,
140
+ `Queue depth: ${snapshot.queueDepth} waiter(s).`,
140
141
  ];
141
- // Liveness answers "does the process exist"; it does not answer "is it
142
+ // Liveness answers "does the process exist". It does not answer "is it
142
143
  // getting anywhere". A holder alive for minutes having used a fraction of
143
144
  // a second of CPU is the shape of a wedged command, and every waiter
144
145
  // behind it inherits the stall. Stated as an observation with its own
145
- // caveat — a holder blocked on I/O is also idle, and this must not be read
146
+ // caveat: a holder blocked on I/O is also idle, and this must not be read
146
147
  // as licence to kill anything.
147
148
  if (holder?.alive === true && holderCpuSeconds !== undefined) {
148
149
  const cpu = `${holderCpuSeconds.toFixed(1)}s`;
@@ -174,15 +175,15 @@ export async function snapshotEngineGeneration(engineDir) {
174
175
  }
175
176
  catch (error) {
176
177
  lastError = error;
177
- // A contended `.git/index.lock` is TRANSIENT, not a state: some other
178
+ // A contended `.git/index.lock` is transient, not a state: some other
178
179
  // writer held the index for the instant we looked. Treating it as
179
180
  // "unmeasurable" turns a perfectly good suite into
180
181
  // `FAIL reason=inconclusive` on a one-sided probe failure. Anything
181
- // else — an unreadable `.git`, a non-git `engine/` — is a real state
182
+ // else (an unreadable `.git`, a non-git `engine/`) is a real state
182
183
  // and is reported immediately.
183
184
  if (!isIndexLockError(error) || attempt === GENERATION_PROBE_ATTEMPTS - 1)
184
185
  break;
185
- await delay(GENERATION_PROBE_RETRY_MS);
186
+ await sleep(GENERATION_PROBE_RETRY_MS);
186
187
  }
187
188
  }
188
189
  return `${UNAVAILABLE_PREFIX}${toError(lastError).message}`;
@@ -191,11 +192,6 @@ export async function snapshotEngineGeneration(engineDir) {
191
192
  const GENERATION_PROBE_ATTEMPTS = 3;
192
193
  /** Pause between generation-probe attempts. */
193
194
  const GENERATION_PROBE_RETRY_MS = 250;
194
- function delay(ms) {
195
- return new Promise((resolveDelay) => {
196
- setTimeout(resolveDelay, ms);
197
- });
198
- }
199
195
  /**
200
196
  * True when a git failure is the transient index-lock contention shape
201
197
  * (`Unable to create '…/.git/index.lock': File exists`) rather than a
@@ -206,7 +202,7 @@ export function isIndexLockError(error) {
206
202
  return /index\.lock/i.test(message);
207
203
  }
208
204
  /**
209
- * True when a generation token records a failed probe — i.e. nothing was
205
+ * True when a generation token records a failed probe, i.e. nothing was
210
206
  * measured, so the token must never be compared (or hashed) as if it
211
207
  * described the engine's state.
212
208
  */
@@ -232,9 +228,9 @@ function splitGenerationToken(token) {
232
228
  /**
233
229
  * Parses `git status --porcelain=v1 -z` into `XY path` records.
234
230
  *
235
- * The rename/copy shape is the trap: `R`/`C` entries are followed by a
236
- * SECOND NUL-separated field carrying the original path, and consuming only
237
- * one desynchronises every record after it — turning a one-file rename into
231
+ * The rename/copy shape needs care: `R`/`C` entries are followed by a
232
+ * second NUL-separated field carrying the original path, and consuming only
233
+ * one desynchronises every record after it, turning a one-file rename into
238
234
  * a report that the whole tree moved. Both fields are consumed and the
239
235
  * record renders as `orig -> new`.
240
236
  */
@@ -243,7 +239,7 @@ function parsePorcelainRecords(body) {
243
239
  const records = [];
244
240
  for (let i = 0; i < fields.length; i++) {
245
241
  const field = fields[i] ?? '';
246
- // `XY ` — two status characters and a space — then the path.
242
+ // `XY `, two status characters and a space, then the path.
247
243
  if (field.length < 4)
248
244
  continue;
249
245
  const status = field.slice(0, 2);
@@ -261,8 +257,8 @@ function parsePorcelainRecords(body) {
261
257
  /**
262
258
  * Describes what moved between two generation tokens, in operator terms.
263
259
  *
264
- * The refusal used to say only THAT the engine changed, which left the
265
- * operator to reconstruct the writer by hand — `find -newermt` against the
260
+ * The refusal used to say only that the engine changed, which left the
261
+ * operator to reconstruct the writer by hand: `find -newermt` against the
266
262
  * run window, minus the objdir, minus git's own bookkeeping. Everything
267
263
  * needed to answer it is already in the two tokens, so the refusal answers
268
264
  * it. Pure and total: an unparseable token yields an empty list rather than
@@ -271,7 +267,7 @@ function parsePorcelainRecords(body) {
271
267
  *
272
268
  * @param before - Token captured before the run
273
269
  * @param after - Token captured after the run
274
- * @returns Human-readable lines describing the delta; empty when nothing
270
+ * @returns Human-readable lines describing the delta. Empty when nothing
275
271
  * could be attributed
276
272
  */
277
273
  export function describeEngineGenerationDelta(before, after) {
@@ -290,7 +286,7 @@ export function describeEngineGenerationDelta(before, after) {
290
286
  return;
291
287
  const head = records.slice(0, DELTA_ENTRY_LIMIT);
292
288
  const truncated = records.length - head.length;
293
- lines.push(`${label}: ${head.join(', ')}${truncated > 0 ? `, … (+${String(truncated)} more)` : ''}`);
289
+ lines.push(`${label}: ${head.join(', ')}${truncated > 0 ? `, … (+${truncated} more)` : ''}`);
294
290
  };
295
291
  render('Working-tree entries that appeared', appeared);
296
292
  render('Working-tree entries that went away', disappeared);
@@ -300,25 +296,25 @@ export function describeEngineGenerationDelta(before, after) {
300
296
  * Throws when the engine's generation token differs from `before`, i.e. the
301
297
  * engine was mutated by another writer while a test run was in flight.
302
298
  *
303
- * **An unmeasurable engine warns rather than throws.** `engine/` is not
304
- * always a git checkout — `fireforge download` extracts a source tarball —
299
+ * An unmeasurable engine warns rather than throws. `engine/` is not
300
+ * always a git checkout (`fireforge download` extracts a source tarball),
305
301
  * so a failed probe is a legitimate state and must not fail the run.
306
302
  *
307
- * What it must also not do is pass *silently*. A failure token compared for
303
+ * It must also not pass silently. A failure token compared for
308
304
  * equality like any other would let a git failure that reproduces across
309
305
  * both probes (unreadable `.git`, a permissions problem, a corrupt index)
310
306
  * take the `after === before` early return and bless a verdict the guard
311
- * never verified. Two *differing* failure messages are worse still: they
307
+ * never verified. Two differing failure messages are worse still: they
312
308
  * fall through to the mutation branch and report a spurious
313
309
  * "engine/ changed". Hence the prefix comparison rather than a token
314
- * comparison — the token embeds the error message, and two genuine failures
310
+ * comparison: the token embeds the error message, and two genuine failures
315
311
  * rarely phrase it identically.
316
312
  *
317
- * The tolerance is deliberately limited to a probe that failed *both* times:
313
+ * The tolerance is limited to a probe that failed both times:
318
314
  * that is the steady state of a non-git `engine/`, and it warns. A one-sided
319
315
  * transition is not that state. An `engine/` that was measurable and then
320
316
  * was not means the second probe measured nothing about a checkout that
321
- * demonstrably had something to measure; the reverse means there was never a
317
+ * demonstrably had something to measure. The reverse means there was never a
322
318
  * baseline to compare against. Neither verdict can be trusted, so both throw.
323
319
  */
324
320
  export async function assertEngineGenerationUnchanged(engineDir, before) {
@@ -2,23 +2,23 @@
2
2
  * Detects the new-file-plus-moved-code slice shape and names the working
3
3
  * sequence through it.
4
4
  *
5
- * A slice that ADDS new files and MOVES lines into them from an existing
5
+ * A slice that adds new files and moves lines into them from an existing
6
6
  * patch has no path through the two refusal flags:
7
7
  *
8
8
  * - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
9
- * still unmanaged; and
9
+ * still unmanaged, and
10
10
  * - exporting the new files as their own patch fails cross-patch lint,
11
- * because at the projected placement the OLD patch still contains the
11
+ * because at the projected placement the old patch still contains the
12
12
  * moved code.
13
13
  *
14
14
  * Each guard is individually correct. Together they dead-end, and the way out
15
- * is non-obvious: adopt the new files into the OLD patch first
15
+ * is non-obvious: adopt the new files into the old patch first
16
16
  * (`re-export --scan --scan-file`), then split them out into a patch of their
17
17
  * own (`patch move-files --create --order N`).
18
18
  *
19
- * This module recognises the shape from evidence FireForge already has — the
19
+ * This module recognises the shape from evidence FireForge already has (the
20
20
  * pending diff's new-file content versus the added lines the existing patches
21
- * carry — so the refusal can name the sequence instead of leaving the
21
+ * carry), so the refusal can name the sequence instead of leaving the
22
22
  * operator to derive it.
23
23
  */
24
24
  /** One existing patch that already carries lines the new files would add. */
@@ -37,7 +37,7 @@ export interface MovedCodeQueueEntry {
37
37
  }
38
38
  /**
39
39
  * Finds existing patches that still carry substantive lines the pending
40
- * diff's NEW files would add — the fingerprint of code moved out of an
40
+ * diff's new files would add, the fingerprint of code moved out of an
41
41
  * existing patch into a new file.
42
42
  *
43
43
  * Pure. Overlaps are returned strongest-first so the message names the
@@ -3,23 +3,23 @@
3
3
  * Detects the new-file-plus-moved-code slice shape and names the working
4
4
  * sequence through it.
5
5
  *
6
- * A slice that ADDS new files and MOVES lines into them from an existing
6
+ * A slice that adds new files and moves lines into them from an existing
7
7
  * patch has no path through the two refusal flags:
8
8
  *
9
9
  * - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
10
- * still unmanaged; and
10
+ * still unmanaged, and
11
11
  * - exporting the new files as their own patch fails cross-patch lint,
12
- * because at the projected placement the OLD patch still contains the
12
+ * because at the projected placement the old patch still contains the
13
13
  * moved code.
14
14
  *
15
15
  * Each guard is individually correct. Together they dead-end, and the way out
16
- * is non-obvious: adopt the new files into the OLD patch first
16
+ * is non-obvious: adopt the new files into the old patch first
17
17
  * (`re-export --scan --scan-file`), then split them out into a patch of their
18
18
  * own (`patch move-files --create --order N`).
19
19
  *
20
- * This module recognises the shape from evidence FireForge already has — the
20
+ * This module recognises the shape from evidence FireForge already has (the
21
21
  * pending diff's new-file content versus the added lines the existing patches
22
- * carry — so the refusal can name the sequence instead of leaving the
22
+ * carry), so the refusal can name the sequence instead of leaving the
23
23
  * operator to derive it.
24
24
  */
25
25
  import { extractAddedLinesPerFile } from './patch-lint-diff.js';
@@ -42,7 +42,7 @@ function isSubstantiveLine(line) {
42
42
  const MOVED_CODE_LINE_THRESHOLD = 3;
43
43
  /**
44
44
  * Finds existing patches that still carry substantive lines the pending
45
- * diff's NEW files would add — the fingerprint of code moved out of an
45
+ * diff's new files would add, the fingerprint of code moved out of an
46
46
  * existing patch into a new file.
47
47
  *
48
48
  * Pure. Overlaps are returned strongest-first so the message names the
@@ -108,20 +108,20 @@ export function formatAdoptThenSplitRemedy(overlaps, newPatchName, insertionOrde
108
108
  return [];
109
109
  const fileArgs = strongest.files.map((file) => `--scan-file ${file}`).join(' ');
110
110
  const moveArgs = strongest.files.map((file) => `--file ${file}`).join(' ');
111
- // `patch move-files --create` takes the new patch's NAME, not a
111
+ // `patch move-files --create` takes the new patch's name, not a
112
112
  // filename: strip the order prefix and the `.patch` suffix so the
113
113
  // suggested command is copy-pasteable.
114
114
  const suggestedName = newPatchName.replace(/^\d+-/, '').replace(/\.patch$/, '');
115
115
  return [
116
116
  '',
117
- `This looks like a new-file + moved-code slice: ${String(strongest.sharedLines)} substantive ` +
117
+ `This looks like a new-file + moved-code slice: ${strongest.sharedLines} substantive ` +
118
118
  `line(s) the new file(s) would add are still carried by ${strongest.sourcePatch}. ` +
119
119
  'Exporting them as their own patch cannot pass cross-patch lint while the source patch ' +
120
120
  'still owns the same code, and re-exporting cannot adopt them while they are unmanaged — ' +
121
121
  'each guard is right, and together they dead-end.',
122
122
  'Working sequence (adopt, then split):',
123
123
  ` 1. fireforge re-export ${strongest.sourcePatch} --scan ${fileArgs}`,
124
- ` 2. fireforge patch move-files ${strongest.sourcePatch} ${suggestedName} --create --order ${String(insertionOrder)} ${moveArgs}`,
124
+ ` 2. fireforge patch move-files ${strongest.sourcePatch} ${suggestedName} --create --order ${insertionOrder} ${moveArgs}`,
125
125
  'Step 1 adopts the new files into the patch that already owns the moved lines; step 2 ' +
126
126
  'splits them back out as one transaction, so the queue is never in a state where two ' +
127
127
  'patches own the same code.',
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Filename of a lock directory's owner record, relative to the lock dir.
3
+ *
4
+ * Re-exported by `file-lock.ts` so external readers (`tree-store.ts`) share
5
+ * the constant instead of re-spelling `'pid'`. The file format is
6
+ * documented on {@link readLockOwner}.
7
+ */
8
+ export declare const LOCK_PID_FILE = "pid";
9
+ /**
10
+ * Owner record read back from a lock directory's PID file.
11
+ *
12
+ * `token` is the per-acquisition UUID written on line 2 of the PID file,
13
+ * `acquiredAtMs` the wall-clock time the record was written (diagnostic),
14
+ * and `startTick` the writer's boot-relative start tick (liveness). Records
15
+ * from releases before a field was introduced parse with it `undefined`.
16
+ * Readers must treat that as "unknown", never as a mismatch.
17
+ */
18
+ export type LockOwner = {
19
+ present: false;
20
+ } | {
21
+ present: true;
22
+ pid: number;
23
+ token?: string;
24
+ acquiredAtMs?: number;
25
+ startTick?: number;
26
+ metadata: string[];
27
+ };
28
+ /**
29
+ * Reads the owner PID (line 1), acquisition token (line 2), the mechanical
30
+ * `acquired-at-ms=` / `start-tick=` lines (when present), and diagnostic
31
+ * metadata (the remaining lines 3+) from a lock directory's PID file.
32
+ * Returns `{ present: false }` when the PID file is missing, unreadable, or
33
+ * the PID does not parse as a finite integer (caller falls back to the
34
+ * age-only staleness heuristic).
35
+ *
36
+ * File format note: external readers do `parseInt(content.trim(), 10)`,
37
+ * which parses the leading digits of a multi-line file, so the token and
38
+ * mechanical lines stay compatible.
39
+ *
40
+ * @param lockPath - Lock directory whose owner record to read
41
+ * @returns The parsed owner record, or `{ present: false }`
42
+ */
43
+ export declare function readLockOwner(lockPath: string): Promise<LockOwner>;
44
+ /**
45
+ * Stamps this process's ownership (PID, per-acquisition token, acquisition
46
+ * time, own start tick, diagnostic metadata) into a lock directory it has
47
+ * just created, and reads the record back to prove it landed.
48
+ *
49
+ * The write is fatal. It used to be best-effort, on the theory that stale
50
+ * recovery would fall back to the age heuristic, but that heuristic reaps
51
+ * any owner-less lock after five minutes, and the build lock legitimately
52
+ * holds for hours. A holder whose record failed to write was therefore
53
+ * reaped mid-build and a second process entered the critical section. On
54
+ * failure the just-created lock directory is removed (nothing else can own
55
+ * it yet) and a {@link GeneralError} names the cause.
56
+ *
57
+ * @param lockPath - Lock directory this process has just `mkdir`'d
58
+ * @param token - Per-acquisition UUID, later checked by release
59
+ * @param ownerMetadata - Extra human-diagnostic lines (see `FileLockOptions.ownerMetadata`)
60
+ * @throws {GeneralError} When the record cannot be written or does not read back as written
61
+ */
62
+ export declare function writeLockOwner(lockPath: string, token: string, ownerMetadata: readonly string[] | undefined): Promise<void>;
63
+ /**
64
+ * Boot-relative start tick of a process, where the platform exposes it
65
+ * cheaply.
66
+ *
67
+ * Linux only: field 22 of `/proc/<pid>/stat`, in USER_HZ since boot.
68
+ * Elsewhere (macOS, Windows) obtaining a start time means spawning
69
+ * `ps`/`wmic` per probe, which is not worth paying on every poll of a
70
+ * contended lock. Those platforms return `undefined` and liveness stays
71
+ * PID-only.
72
+ *
73
+ * Not converted to wall-clock time via `/proc/stat` `btime`, on purpose:
74
+ * on current kernels `btime` is derived from the realtime clock and moves
75
+ * with every clock step, so a wall-clock comparison against a recorded
76
+ * acquisition time misjudges a live holder as a reused PID after NTP steps
77
+ * the clock forward, and reaps a lock that is in use.
78
+ *
79
+ * @param pid - Process to look up
80
+ * @param procRoot - procfs mount, overridable for tests
81
+ * @returns Start tick, or `undefined` when unobtainable
82
+ */
83
+ export declare function readProcessStartTick(pid: number, procRoot?: string): number | undefined;
84
+ /**
85
+ * Whether the process named by a lock's owner record is the same process
86
+ * that acquired the lock, not merely a live process wearing its PID.
87
+ *
88
+ * `isProcessAlive` answers "does this PID exist". After a holder crashes,
89
+ * the kernel may hand its PID to a long-lived daemon, and a PID-only check
90
+ * then honours the dead lock until the waiter's timeout. Where the record
91
+ * carries the writer's start tick and the candidate's own tick is cheaply
92
+ * obtainable (see {@link readProcessStartTick}), the two must be equal: a
93
+ * different tick is a different process. Records without a start tick, and
94
+ * platforms without one, keep the PID-only answer.
95
+ *
96
+ * @param owner - Owner record fields that identify the holder
97
+ * @param procRoot - procfs mount, overridable for tests
98
+ * @returns True when the original holder is still running (or cannot be proven gone)
99
+ */
100
+ export declare function isLockOwnerAlive(owner: {
101
+ pid: number;
102
+ startTick?: number | undefined;
103
+ }, procRoot?: string): boolean;