@hominis/fireforge 0.49.2 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/README.md +1 -1
  3. package/dist/bin/fireforge.js +6 -0
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/commands/build-prelock.d.ts +20 -0
  6. package/dist/src/commands/build-prelock.js +50 -0
  7. package/dist/src/commands/build.d.ts +3 -1
  8. package/dist/src/commands/build.js +13 -6
  9. package/dist/src/commands/check-report.d.ts +41 -0
  10. package/dist/src/commands/check-report.js +91 -0
  11. package/dist/src/commands/check-run.d.ts +33 -0
  12. package/dist/src/commands/check-run.js +112 -0
  13. package/dist/src/commands/check-steps.d.ts +75 -0
  14. package/dist/src/commands/check-steps.js +200 -0
  15. package/dist/src/commands/check.d.ts +32 -0
  16. package/dist/src/commands/check.js +160 -0
  17. package/dist/src/commands/config.js +5 -6
  18. package/dist/src/commands/declarations-report.d.ts +43 -0
  19. package/dist/src/commands/declarations-report.js +76 -0
  20. package/dist/src/commands/doctor-engine-eslint.js +6 -1
  21. package/dist/src/commands/doctor-source-pin.js +4 -1
  22. package/dist/src/commands/export-adopt-check.d.ts +38 -0
  23. package/dist/src/commands/export-adopt-check.js +98 -0
  24. package/dist/src/commands/export-flow.js +29 -14
  25. package/dist/src/commands/export-placement-gate.d.ts +6 -2
  26. package/dist/src/commands/export-placement-gate.js +8 -0
  27. package/dist/src/commands/export-shared.d.ts +2 -1
  28. package/dist/src/commands/export-staged-registration.d.ts +46 -0
  29. package/dist/src/commands/export-staged-registration.js +91 -0
  30. package/dist/src/commands/forward-import-remedy.d.ts +32 -0
  31. package/dist/src/commands/forward-import-remedy.js +63 -0
  32. package/dist/src/commands/furnace/apply.js +3 -3
  33. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
  34. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  35. package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
  36. package/dist/src/commands/furnace/chrome-doc.js +2 -2
  37. package/dist/src/commands/furnace/create.js +2 -2
  38. package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
  39. package/dist/src/commands/furnace/deploy-named.js +107 -0
  40. package/dist/src/commands/furnace/deploy.d.ts +3 -2
  41. package/dist/src/commands/furnace/deploy.js +50 -86
  42. package/dist/src/commands/furnace/diff.js +26 -3
  43. package/dist/src/commands/furnace/index.js +66 -41
  44. package/dist/src/commands/furnace/init.js +13 -6
  45. package/dist/src/commands/furnace/override.js +4 -2
  46. package/dist/src/commands/furnace/preview.js +4 -3
  47. package/dist/src/commands/furnace/refresh.js +2 -2
  48. package/dist/src/commands/furnace/remove.js +4 -3
  49. package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
  50. package/dist/src/commands/furnace/rename-dry-run.js +127 -0
  51. package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
  52. package/dist/src/commands/furnace/rename-helpers.js +15 -1
  53. package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
  54. package/dist/src/commands/furnace/rename-registrations.js +98 -0
  55. package/dist/src/commands/furnace/rename.d.ts +2 -1
  56. package/dist/src/commands/furnace/rename.js +28 -66
  57. package/dist/src/commands/furnace/scan.d.ts +9 -4
  58. package/dist/src/commands/furnace/scan.js +11 -9
  59. package/dist/src/commands/furnace/sync.js +3 -2
  60. package/dist/src/commands/furnace/validate-report.d.ts +45 -0
  61. package/dist/src/commands/furnace/validate-report.js +91 -0
  62. package/dist/src/commands/furnace/validate.d.ts +1 -1
  63. package/dist/src/commands/furnace/validate.js +151 -113
  64. package/dist/src/commands/furnace/validation-output.js +14 -3
  65. package/dist/src/commands/lint-per-patch.js +36 -61
  66. package/dist/src/commands/lint-per-run-checkjs.js +2 -2
  67. package/dist/src/commands/lint-report.d.ts +8 -4
  68. package/dist/src/commands/lint-report.js +20 -5
  69. package/dist/src/commands/lint.js +15 -34
  70. package/dist/src/commands/manifest.js +4 -0
  71. package/dist/src/commands/park.d.ts +22 -0
  72. package/dist/src/commands/park.js +232 -0
  73. package/dist/src/commands/patch/delete-gap-notice.js +3 -1
  74. package/dist/src/commands/patch/delete.d.ts +1 -1
  75. package/dist/src/commands/patch/delete.js +24 -104
  76. package/dist/src/commands/patch/index.d.ts +3 -3
  77. package/dist/src/commands/patch/index.js +10 -4
  78. package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
  79. package/dist/src/commands/patch/lint-ignore-from.js +142 -0
  80. package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
  81. package/dist/src/commands/patch/lint-ignore.js +78 -31
  82. package/dist/src/commands/patch/move-files-create.js +34 -18
  83. package/dist/src/commands/patch/move-files-into.js +15 -7
  84. package/dist/src/commands/patch/move-files.js +6 -2
  85. package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
  86. package/dist/src/commands/patch/removal-created-files.js +83 -0
  87. package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
  88. package/dist/src/commands/patch/removal-dependents.js +133 -0
  89. package/dist/src/commands/patch/rename.js +20 -1
  90. package/dist/src/commands/patch/reserve.d.ts +33 -0
  91. package/dist/src/commands/patch/reserve.js +152 -0
  92. package/dist/src/commands/patch/retire.d.ts +34 -0
  93. package/dist/src/commands/patch/retire.js +133 -0
  94. package/dist/src/commands/patch/split-plan.d.ts +17 -8
  95. package/dist/src/commands/patch/split-plan.js +60 -28
  96. package/dist/src/commands/patch/split-staged.d.ts +108 -0
  97. package/dist/src/commands/patch/split-staged.js +202 -0
  98. package/dist/src/commands/patch/split.d.ts +5 -0
  99. package/dist/src/commands/patch/split.js +62 -17
  100. package/dist/src/commands/patch/stage.d.ts +34 -0
  101. package/dist/src/commands/patch/stage.js +153 -0
  102. package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
  103. package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
  104. package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
  105. package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
  106. package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
  107. package/dist/src/commands/patch/staged-dependency-from.js +108 -0
  108. package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
  109. package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
  110. package/dist/src/commands/patch/staged-dependency.js +54 -139
  111. package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
  112. package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
  113. package/dist/src/commands/re-export-adjacent.d.ts +50 -2
  114. package/dist/src/commands/re-export-adjacent.js +160 -40
  115. package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
  116. package/dist/src/commands/re-export-bulk-scan.js +22 -7
  117. package/dist/src/commands/re-export-drift.d.ts +36 -8
  118. package/dist/src/commands/re-export-drift.js +73 -49
  119. package/dist/src/commands/re-export-files.js +11 -8
  120. package/dist/src/commands/re-export-hunks.d.ts +35 -0
  121. package/dist/src/commands/re-export-hunks.js +220 -0
  122. package/dist/src/commands/re-export-lint.d.ts +2 -1
  123. package/dist/src/commands/re-export-lint.js +23 -10
  124. package/dist/src/commands/re-export-options.js +74 -6
  125. package/dist/src/commands/re-export-preflight.d.ts +23 -0
  126. package/dist/src/commands/re-export-preflight.js +160 -0
  127. package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
  128. package/dist/src/commands/re-export-purity-scope.js +131 -0
  129. package/dist/src/commands/re-export-register.js +56 -17
  130. package/dist/src/commands/re-export-removed.d.ts +13 -2
  131. package/dist/src/commands/re-export-removed.js +57 -12
  132. package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
  133. package/dist/src/commands/re-export-scan-owner.js +116 -0
  134. package/dist/src/commands/re-export-scan.d.ts +19 -9
  135. package/dist/src/commands/re-export-scan.js +60 -24
  136. package/dist/src/commands/re-export-single.js +122 -46
  137. package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
  138. package/dist/src/commands/re-export-stale-registrations.js +62 -0
  139. package/dist/src/commands/re-export-summary.d.ts +28 -0
  140. package/dist/src/commands/re-export-summary.js +36 -0
  141. package/dist/src/commands/re-export.js +71 -57
  142. package/dist/src/commands/rebase/index.js +17 -17
  143. package/dist/src/commands/run.js +16 -2
  144. package/dist/src/commands/status-check.d.ts +55 -16
  145. package/dist/src/commands/status-check.js +92 -37
  146. package/dist/src/commands/status-json.d.ts +22 -9
  147. package/dist/src/commands/status-json.js +47 -32
  148. package/dist/src/commands/status-output.js +3 -1
  149. package/dist/src/commands/status-scope.d.ts +37 -0
  150. package/dist/src/commands/status-scope.js +54 -0
  151. package/dist/src/commands/status.js +66 -23
  152. package/dist/src/commands/test-browser-preflight.js +19 -3
  153. package/dist/src/commands/test-build-furnace.d.ts +22 -0
  154. package/dist/src/commands/test-build-furnace.js +54 -0
  155. package/dist/src/commands/test-build-phase.js +64 -41
  156. package/dist/src/commands/test-checkjs.js +10 -2
  157. package/dist/src/commands/test-diagnose.js +7 -0
  158. package/dist/src/commands/test-dispatch.d.ts +39 -0
  159. package/dist/src/commands/test-dispatch.js +211 -0
  160. package/dist/src/commands/test-furnace-reach.d.ts +37 -0
  161. package/dist/src/commands/test-furnace-reach.js +132 -0
  162. package/dist/src/commands/test-modes.d.ts +16 -1
  163. package/dist/src/commands/test-modes.js +24 -1
  164. package/dist/src/commands/test-multi-verdict.d.ts +61 -0
  165. package/dist/src/commands/test-multi-verdict.js +111 -0
  166. package/dist/src/commands/test-orchestrate.d.ts +52 -0
  167. package/dist/src/commands/test-orchestrate.js +240 -0
  168. package/dist/src/commands/test-perf-scope.d.ts +50 -0
  169. package/dist/src/commands/test-perf-scope.js +138 -0
  170. package/dist/src/commands/test-prelock.d.ts +51 -0
  171. package/dist/src/commands/test-prelock.js +273 -0
  172. package/dist/src/commands/test-register.js +69 -10
  173. package/dist/src/commands/test-results.d.ts +62 -0
  174. package/dist/src/commands/test-results.js +62 -0
  175. package/dist/src/commands/test-run.d.ts +13 -55
  176. package/dist/src/commands/test-run.js +74 -99
  177. package/dist/src/commands/test-shards.d.ts +110 -0
  178. package/dist/src/commands/test-shards.js +255 -0
  179. package/dist/src/commands/test-stale-gate.d.ts +5 -1
  180. package/dist/src/commands/test-stale-gate.js +60 -28
  181. package/dist/src/commands/test-verdict.d.ts +11 -1
  182. package/dist/src/commands/test-verdict.js +28 -1
  183. package/dist/src/commands/test.d.ts +6 -1
  184. package/dist/src/commands/test.js +120 -124
  185. package/dist/src/commands/token-lint.d.ts +14 -0
  186. package/dist/src/commands/token-lint.js +151 -0
  187. package/dist/src/commands/token.js +10 -0
  188. package/dist/src/commands/verify-scope.d.ts +28 -0
  189. package/dist/src/commands/verify-scope.js +67 -0
  190. package/dist/src/commands/verify.d.ts +10 -2
  191. package/dist/src/commands/verify.js +67 -36
  192. package/dist/src/core/build-baseline-types.d.ts +46 -0
  193. package/dist/src/core/build-baseline-validate.js +19 -0
  194. package/dist/src/core/build-baseline.d.ts +5 -1
  195. package/dist/src/core/build-baseline.js +3 -1
  196. package/dist/src/core/build-overwrite-guard.d.ts +50 -0
  197. package/dist/src/core/build-overwrite-guard.js +84 -4
  198. package/dist/src/core/build-prepare.d.ts +13 -0
  199. package/dist/src/core/build-prepare.js +42 -10
  200. package/dist/src/core/build-run-record.d.ts +74 -0
  201. package/dist/src/core/build-run-record.js +136 -0
  202. package/dist/src/core/checkjs-support-heads.d.ts +41 -0
  203. package/dist/src/core/checkjs-support-heads.js +104 -0
  204. package/dist/src/core/config-paths.d.ts +2 -2
  205. package/dist/src/core/config-paths.js +10 -0
  206. package/dist/src/core/config-validate-check.d.ts +8 -0
  207. package/dist/src/core/config-validate-check.js +219 -0
  208. package/dist/src/core/config-validate-file-size.d.ts +9 -6
  209. package/dist/src/core/config-validate-file-size.js +91 -2
  210. package/dist/src/core/config-validate-history.d.ts +11 -0
  211. package/dist/src/core/config-validate-history.js +38 -0
  212. package/dist/src/core/config-validate-patch-policy.js +100 -0
  213. package/dist/src/core/config-validate-test-toolchains.js +21 -0
  214. package/dist/src/core/config-validate-token-scales.d.ts +9 -0
  215. package/dist/src/core/config-validate-token-scales.js +92 -0
  216. package/dist/src/core/config-validate.js +20 -5
  217. package/dist/src/core/config.d.ts +5 -0
  218. package/dist/src/core/config.js +16 -0
  219. package/dist/src/core/coverage-dispatch.d.ts +24 -0
  220. package/dist/src/core/coverage-dispatch.js +44 -0
  221. package/dist/src/core/coverage-extend.d.ts +70 -45
  222. package/dist/src/core/coverage-extend.js +199 -144
  223. package/dist/src/core/coverage-records.d.ts +108 -0
  224. package/dist/src/core/coverage-records.js +384 -0
  225. package/dist/src/core/destructive.d.ts +7 -4
  226. package/dist/src/core/destructive.js +10 -10
  227. package/dist/src/core/engine-session-lock.d.ts +16 -1
  228. package/dist/src/core/engine-session-lock.js +38 -10
  229. package/dist/src/core/export-moved-code-shape.d.ts +49 -11
  230. package/dist/src/core/export-moved-code-shape.js +135 -44
  231. package/dist/src/core/file-lock-queue.d.ts +67 -0
  232. package/dist/src/core/file-lock-queue.js +221 -0
  233. package/dist/src/core/file-lock-shared.d.ts +57 -0
  234. package/dist/src/core/file-lock-shared.js +117 -0
  235. package/dist/src/core/file-lock.d.ts +13 -25
  236. package/dist/src/core/file-lock.js +163 -140
  237. package/dist/src/core/furnace-apply-output.d.ts +10 -0
  238. package/dist/src/core/furnace-apply-output.js +31 -1
  239. package/dist/src/core/furnace-apply.js +22 -12
  240. package/dist/src/core/furnace-composed-source.d.ts +76 -0
  241. package/dist/src/core/furnace-composed-source.js +167 -0
  242. package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
  243. package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
  244. package/dist/src/core/furnace-config-validate.js +14 -0
  245. package/dist/src/core/furnace-css-fragments.d.ts +10 -0
  246. package/dist/src/core/furnace-css-fragments.js +26 -0
  247. package/dist/src/core/furnace-operation.d.ts +3 -3
  248. package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
  249. package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
  250. package/dist/src/core/furnace-registration-remove.d.ts +22 -1
  251. package/dist/src/core/furnace-registration-remove.js +53 -17
  252. package/dist/src/core/furnace-registration-rename.d.ts +26 -0
  253. package/dist/src/core/furnace-registration-rename.js +77 -0
  254. package/dist/src/core/furnace-registration.d.ts +14 -4
  255. package/dist/src/core/furnace-registration.js +44 -10
  256. package/dist/src/core/furnace-staleness.d.ts +7 -0
  257. package/dist/src/core/furnace-staleness.js +34 -24
  258. package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
  259. package/dist/src/core/furnace-validate-accessibility.js +71 -28
  260. package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
  261. package/dist/src/core/furnace-validate-exceptions.js +80 -0
  262. package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
  263. package/dist/src/core/furnace-validate-icon-button.js +78 -0
  264. package/dist/src/core/furnace-validate.js +1 -1
  265. package/dist/src/core/harness-port-fallback.d.ts +60 -0
  266. package/dist/src/core/harness-port-fallback.js +96 -0
  267. package/dist/src/core/history-log-file.d.ts +61 -0
  268. package/dist/src/core/history-log-file.js +164 -0
  269. package/dist/src/core/history-log.d.ts +2 -1
  270. package/dist/src/core/history-log.js +2 -1
  271. package/dist/src/core/json-preserving-edit.d.ts +22 -0
  272. package/dist/src/core/json-preserving-edit.js +199 -0
  273. package/dist/src/core/line-prefixer.d.ts +18 -0
  274. package/dist/src/core/line-prefixer.js +34 -0
  275. package/dist/src/core/mach.d.ts +7 -0
  276. package/dist/src/core/mach.js +32 -10
  277. package/dist/src/core/module-resolution-preflight.d.ts +19 -3
  278. package/dist/src/core/module-resolution-preflight.js +24 -6
  279. package/dist/src/core/negative-control-compiled.d.ts +27 -0
  280. package/dist/src/core/negative-control-compiled.js +73 -0
  281. package/dist/src/core/negative-control-diff.d.ts +51 -0
  282. package/dist/src/core/negative-control-diff.js +179 -0
  283. package/dist/src/core/negative-control.d.ts +150 -0
  284. package/dist/src/core/negative-control.js +399 -0
  285. package/dist/src/core/objdir-install-manifests.d.ts +73 -0
  286. package/dist/src/core/objdir-install-manifests.js +226 -0
  287. package/dist/src/core/park-store.d.ts +63 -0
  288. package/dist/src/core/park-store.js +216 -0
  289. package/dist/src/core/patch-export-update.d.ts +6 -0
  290. package/dist/src/core/patch-export-update.js +13 -3
  291. package/dist/src/core/patch-export.d.ts +3 -2
  292. package/dist/src/core/patch-export.js +22 -16
  293. package/dist/src/core/patch-files.js +26 -8
  294. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
  295. package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
  296. package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
  297. package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
  298. package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
  299. package/dist/src/core/patch-lint-checkjs.js +20 -13
  300. package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
  301. package/dist/src/core/patch-lint-code-lines.js +105 -0
  302. package/dist/src/core/patch-lint-cross.d.ts +3 -1
  303. package/dist/src/core/patch-lint-cross.js +17 -4
  304. package/dist/src/core/patch-lint-css.d.ts +8 -2
  305. package/dist/src/core/patch-lint-css.js +24 -14
  306. package/dist/src/core/patch-lint-file-size.d.ts +12 -5
  307. package/dist/src/core/patch-lint-file-size.js +22 -11
  308. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
  309. package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
  310. package/dist/src/core/patch-lint-forward-registration.js +10 -0
  311. package/dist/src/core/patch-lint-ignore.d.ts +196 -0
  312. package/dist/src/core/patch-lint-ignore.js +429 -0
  313. package/dist/src/core/patch-lint-ownership.d.ts +10 -0
  314. package/dist/src/core/patch-lint-ownership.js +26 -0
  315. package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
  316. package/dist/src/core/patch-lint-size-thresholds.js +110 -0
  317. package/dist/src/core/patch-lint-size.d.ts +117 -0
  318. package/dist/src/core/patch-lint-size.js +331 -0
  319. package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
  320. package/dist/src/core/patch-lint-staged-registration.js +20 -0
  321. package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
  322. package/dist/src/core/patch-lint-token-scale.js +286 -0
  323. package/dist/src/core/patch-lint.d.ts +11 -83
  324. package/dist/src/core/patch-lint.js +66 -288
  325. package/dist/src/core/patch-lock.js +7 -6
  326. package/dist/src/core/patch-manifest-consistency.js +7 -6
  327. package/dist/src/core/patch-manifest-io.d.ts +6 -3
  328. package/dist/src/core/patch-manifest-io.js +27 -9
  329. package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
  330. package/dist/src/core/patch-manifest-key-order.js +61 -0
  331. package/dist/src/core/patch-manifest-stage.d.ts +46 -0
  332. package/dist/src/core/patch-manifest-stage.js +96 -0
  333. package/dist/src/core/patch-manifest-validate.js +61 -3
  334. package/dist/src/core/patch-order-legal.d.ts +26 -0
  335. package/dist/src/core/patch-order-legal.js +88 -0
  336. package/dist/src/core/patch-policy-content.d.ts +40 -0
  337. package/dist/src/core/patch-policy-content.js +216 -0
  338. package/dist/src/core/patch-policy.d.ts +22 -5
  339. package/dist/src/core/patch-policy.js +26 -12
  340. package/dist/src/core/patch-retired.d.ts +57 -0
  341. package/dist/src/core/patch-retired.js +92 -0
  342. package/dist/src/core/patch-subset.d.ts +16 -0
  343. package/dist/src/core/patch-subset.js +66 -0
  344. package/dist/src/core/preflight-wait.d.ts +20 -0
  345. package/dist/src/core/preflight-wait.js +38 -0
  346. package/dist/src/core/rebase-from-version.d.ts +46 -0
  347. package/dist/src/core/rebase-from-version.js +71 -0
  348. package/dist/src/core/run-log.d.ts +26 -0
  349. package/dist/src/core/run-log.js +106 -4
  350. package/dist/src/core/run-profile.d.ts +7 -0
  351. package/dist/src/core/run-profile.js +7 -1
  352. package/dist/src/core/smoke-patterns.d.ts +5 -0
  353. package/dist/src/core/smoke-patterns.js +13 -0
  354. package/dist/src/core/test-harness-crash.d.ts +19 -1
  355. package/dist/src/core/test-harness-crash.js +8 -9
  356. package/dist/src/core/test-harness-signature.d.ts +33 -0
  357. package/dist/src/core/test-harness-signature.js +23 -1
  358. package/dist/src/core/test-raw-log.d.ts +66 -0
  359. package/dist/src/core/test-raw-log.js +122 -0
  360. package/dist/src/core/test-run-completeness.d.ts +90 -0
  361. package/dist/src/core/test-run-completeness.js +184 -0
  362. package/dist/src/core/test-stale-check.d.ts +27 -1
  363. package/dist/src/core/test-stale-check.js +39 -49
  364. package/dist/src/core/test-stale-exempt.d.ts +40 -0
  365. package/dist/src/core/test-stale-exempt.js +70 -0
  366. package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
  367. package/dist/src/core/test-xpcshell-retry.js +2 -1
  368. package/dist/src/core/token-lint.d.ts +53 -0
  369. package/dist/src/core/token-lint.js +131 -0
  370. package/dist/src/core/token-sibling-sheets.d.ts +46 -0
  371. package/dist/src/core/token-sibling-sheets.js +119 -0
  372. package/dist/src/core/tree-guard.js +5 -0
  373. package/dist/src/core/typecheck-shim.d.ts +6 -2
  374. package/dist/src/core/typecheck-shim.js +205 -4
  375. package/dist/src/core/typecheck.js +3 -1
  376. package/dist/src/index.d.ts +14 -3
  377. package/dist/src/index.js +6 -1
  378. package/dist/src/types/commands/index.d.ts +2 -2
  379. package/dist/src/types/commands/options.d.ts +212 -24
  380. package/dist/src/types/commands/patches.d.ts +118 -1
  381. package/dist/src/types/config.d.ts +264 -0
  382. package/dist/src/types/config.js +9 -0
  383. package/dist/src/types/furnace.d.ts +63 -1
  384. package/dist/src/types/furnace.js +7 -0
  385. package/dist/src/types/index.d.ts +1 -1
  386. package/dist/src/utils/options.d.ts +36 -7
  387. package/dist/src/utils/options.js +94 -8
  388. package/dist/src/utils/path-glob.d.ts +15 -0
  389. package/dist/src/utils/path-glob.js +47 -0
  390. package/dist/src/utils/regex.d.ts +15 -3
  391. package/dist/src/utils/regex.js +37 -16
  392. package/docs/configuration.md +369 -11
  393. package/docs/exit-codes.md +18 -1
  394. package/docs/furnace.md +139 -3
  395. package/docs/lifecycle-invariants.md +65 -30
  396. package/docs/machine-output.md +120 -12
  397. package/docs/patch-workflow.md +458 -22
  398. package/docs/run-logs.md +20 -1
  399. package/docs/testing.md +346 -21
  400. package/package.json +3 -3
@@ -19,12 +19,19 @@
19
19
  * no owned file is an upstream Firefox module, which FireForge does not
20
20
  * police and cannot cheaply enumerate. Policing only what the fork owns is
21
21
  * both the actionable set and the one that produces real incidents.
22
+ *
23
+ * An unscoped `verify` widens that set with the engine worktree: changed
24
+ * files import, and untracked files are targets. A chrome script's lazy
25
+ * getter for a new, not yet exported `.sys.mjs` with no moz.build line
26
+ * SIGSEGVed every start of a shared objdir, and neither file was in the
27
+ * queue yet, so the queue-only scan could not see it.
22
28
  */
23
29
  import { dirname, join } from 'node:path';
24
30
  import { toError } from '../utils/errors.js';
25
31
  import { pathExists, readText } from '../utils/fs.js';
26
32
  import { verbose } from '../utils/logger.js';
27
33
  import { escapeRegex } from '../utils/regex.js';
34
+ import { expandUntrackedDirectoryEntries, getWorkingTreeStatus } from './git-status.js';
28
35
  import { extractResourceModuleSpecifiers, moduleSourceSuffix, } from './patch-lint-module-registration.js';
29
36
  /** Extensions whose contents are scanned for resource-module imports. */
30
37
  const IMPORTABLE_EXTENSIONS = ['.mjs', '.sys.mjs', '.js', '.jsm'];
@@ -79,20 +86,31 @@ async function isRegisteredInAncestorMozBuild(engineDir, moduleRelPath, mozBuild
79
86
  dir = parent;
80
87
  }
81
88
  }
89
+ /** Lists the engine's changed and untracked files for the worktree scan. */
90
+ export async function collectWorktreeModuleFiles(engineDir) {
91
+ const entries = await expandUntrackedDirectoryEntries(engineDir, await getWorkingTreeStatus(engineDir));
92
+ const present = entries.filter((entry) => entry.worktreeStatus !== 'D');
93
+ return {
94
+ changed: present.map((entry) => entry.file),
95
+ untracked: present.filter((entry) => entry.status === '??').map((entry) => entry.file),
96
+ };
97
+ }
82
98
  /**
83
99
  * Resolves every `resource://` system-module import made by the
84
- * queue-owned files and reports the ones a packaged browser could not
85
- * load.
100
+ * queue-owned files (and, given `worktree`, by changed engine files) and
101
+ * reports the ones a packaged browser could not load.
86
102
  *
87
103
  * @param engineDir - Path to the engine checkout
88
104
  * @param ownedFiles - Engine-relative paths the patch queue owns
105
+ * @param worktree - Changed and untracked engine files to judge as well
89
106
  * @returns Findings sorted by module path. Empty when everything resolves
90
107
  */
91
- export async function findUnresolvedSystemModuleImports(engineDir, ownedFiles) {
92
- const owned = [...new Set(ownedFiles)];
93
- /** specifier → importing owned files. */
108
+ export async function findUnresolvedSystemModuleImports(engineDir, ownedFiles, worktree) {
109
+ const owned = [...new Set([...ownedFiles, ...(worktree?.untracked ?? [])])];
110
+ const importing = [...new Set([...owned, ...(worktree?.changed ?? [])])];
111
+ /** specifier → importing files. */
94
112
  const importersBySpecifier = new Map();
95
- for (const file of owned) {
113
+ for (const file of importing) {
96
114
  if (!IMPORTABLE_EXTENSIONS.some((extension) => file.endsWith(extension)))
97
115
  continue;
98
116
  const content = await readIfPresent(join(engineDir, file));
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Which negative-control targets only a build can deliver.
3
+ *
4
+ * A control is applied after the pre-test build and right before dispatch,
5
+ * which is right for a file the runtime reads from the source tree or the
6
+ * objdir links to. A C++ (or Rust, IDL, …) source edited at that point is
7
+ * never compiled: the run tests the unmutated binary and reports
8
+ * `control=missed`, which reads as a test that cannot fail. Such a target
9
+ * is now refused without `--build`, and with `--build` the control is
10
+ * applied before the build so the binary under test carries it.
11
+ */
12
+ /**
13
+ * The engine-relative targets that reach the runtime only through a
14
+ * compile: a compiled-source extension and no install-manifest entry that
15
+ * ships the file itself.
16
+ *
17
+ * @param engineDir - Absolute engine directory
18
+ * @param enginePaths - The control's engine-relative targets
19
+ */
20
+ export declare function findCompiledControlTargets(engineDir: string, enginePaths: readonly string[]): Promise<string[]>;
21
+ /**
22
+ * The refusal for a compiled control without `--build`, naming the manual
23
+ * procedure for a run that wants to keep its build out of FireForge.
24
+ *
25
+ * @param compiled - Engine-relative compiled targets
26
+ */
27
+ export declare function formatCompiledControlRefusal(compiled: readonly string[]): string;
@@ -0,0 +1,73 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Which negative-control targets only a build can deliver.
4
+ *
5
+ * A control is applied after the pre-test build and right before dispatch,
6
+ * which is right for a file the runtime reads from the source tree or the
7
+ * objdir links to. A C++ (or Rust, IDL, …) source edited at that point is
8
+ * never compiled: the run tests the unmutated binary and reports
9
+ * `control=missed`, which reads as a test that cannot fail. Such a target
10
+ * is now refused without `--build`, and with `--build` the control is
11
+ * applied before the build so the binary under test carries it.
12
+ */
13
+ import { extname } from 'node:path';
14
+ import { classifyRuntimeDelivery } from './objdir-install-manifests.js';
15
+ import { loadEngineInstallIndex } from './test-stale-exempt.js';
16
+ /** Extensions of sources the build compiles or code-generates into the binary. */
17
+ const COMPILED_EXTENSIONS = new Set([
18
+ '.c',
19
+ '.cc',
20
+ '.cpp',
21
+ '.cxx',
22
+ '.h',
23
+ '.hh',
24
+ '.hpp',
25
+ '.m',
26
+ '.mm',
27
+ '.rs',
28
+ '.idl',
29
+ '.webidl',
30
+ '.ipdl',
31
+ '.ipdlh',
32
+ '.yaml',
33
+ '.yml',
34
+ ]);
35
+ /**
36
+ * The engine-relative targets that reach the runtime only through a
37
+ * compile: a compiled-source extension and no install-manifest entry that
38
+ * ships the file itself.
39
+ *
40
+ * @param engineDir - Absolute engine directory
41
+ * @param enginePaths - The control's engine-relative targets
42
+ */
43
+ export async function findCompiledControlTargets(engineDir, enginePaths) {
44
+ const candidates = enginePaths.filter((path) => COMPILED_EXTENSIONS.has(extname(path)));
45
+ if (candidates.length === 0)
46
+ return [];
47
+ const index = await loadEngineInstallIndex(engineDir);
48
+ if (index === undefined)
49
+ return candidates;
50
+ const compiled = [];
51
+ for (const path of candidates) {
52
+ if ((await classifyRuntimeDelivery(index, engineDir, path)) === 'unlisted') {
53
+ compiled.push(path);
54
+ }
55
+ }
56
+ return compiled;
57
+ }
58
+ /**
59
+ * The refusal for a compiled control without `--build`, naming the manual
60
+ * procedure for a run that wants to keep its build out of FireForge.
61
+ *
62
+ * @param compiled - Engine-relative compiled targets
63
+ */
64
+ export function formatCompiledControlRefusal(compiled) {
65
+ const files = compiled.map((path) => `engine/${path}`).join(', ');
66
+ return (`This negative control edits compiled source (${files}). Applied right before dispatch, ` +
67
+ 'it would never be compiled: the run would test the unmutated binary and report ' +
68
+ 'control=missed. Add --build: the control is then applied before the pre-test build, so ' +
69
+ 'the binary under test carries it, and restored afterwards with a fresh mtime so the next ' +
70
+ 'build recompiles the original. To run it by hand instead: copy the mutated file in, ' +
71
+ '`touch` it, `fireforge build`, `fireforge test`, restore the file byte-exact, `touch` it ' +
72
+ 'again and rebuild.');
73
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Parsing and strict application of a `fireforge test --negative-control`
3
+ * diff.
4
+ *
5
+ * A control is a reviewed mutation, so the applier is deliberately strict:
6
+ * every context and removed line must match exactly, the only tolerance is
7
+ * a line offset (the same one `git apply` allows, never fuzz), and a hunk
8
+ * that does not apply refuses the whole control before any file is
9
+ * written. Only plain text modifications of existing files are accepted: a
10
+ * created, deleted, renamed or binary file has no byte-exact restore story
11
+ * that is worth its risk for a neuter.
12
+ */
13
+ import { type ParsedHunk } from './patch-parse.js';
14
+ /** One file of a control diff. */
15
+ export interface ControlDiffFile {
16
+ /** The path the diff names, without git's `a/`/`b/` prefix. */
17
+ path: string;
18
+ /** The hunks to apply, in file order. */
19
+ hunks: ParsedHunk[];
20
+ }
21
+ /** Options for {@link parseControlDiff}. */
22
+ export interface ParseControlDiffOptions {
23
+ /**
24
+ * Called for a section whose old and new paths differ. Returns the path
25
+ * the control targets (a `git diff --no-index <file> <edited copy>` names
26
+ * the copy on its new side), or undefined for a real rename, which is
27
+ * refused.
28
+ */
29
+ resolveRename?: (sourcePath: string, targetPath: string) => string | undefined;
30
+ }
31
+ /**
32
+ * Parses a control diff. Accepts `git diff` output (a `diff --git` header
33
+ * per file), which is what `git -C engine diff -- <file>` or a project-root
34
+ * `git diff` writes, a plain unified diff (`diff -u`), and, through
35
+ * `resolveRename`, a `git diff --no-index` against an edited copy.
36
+ *
37
+ * @param content - The diff file's text
38
+ * @param options - See {@link ParseControlDiffOptions}
39
+ * @returns One entry per file, in diff order
40
+ */
41
+ export declare function parseControlDiff(content: string, options?: ParseControlDiffOptions): ControlDiffFile[];
42
+ /**
43
+ * Applies `hunks` to `original`, strictly.
44
+ *
45
+ * @param original - The file's current text
46
+ * @param hunks - Hunks parsed from the control diff
47
+ * @param label - File label for refusal messages
48
+ * @returns The mutated text
49
+ * @throws GeneralError when any hunk does not apply
50
+ */
51
+ export declare function applyControlHunks(original: string, hunks: readonly ParsedHunk[], label: string): string;
@@ -0,0 +1,179 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Parsing and strict application of a `fireforge test --negative-control`
4
+ * diff.
5
+ *
6
+ * A control is a reviewed mutation, so the applier is deliberately strict:
7
+ * every context and removed line must match exactly, the only tolerance is
8
+ * a line offset (the same one `git apply` allows, never fuzz), and a hunk
9
+ * that does not apply refuses the whole control before any file is
10
+ * written. Only plain text modifications of existing files are accepted: a
11
+ * created, deleted, renamed or binary file has no byte-exact restore story
12
+ * that is worth its risk for a neuter.
13
+ */
14
+ import { GeneralError } from '../errors/base.js';
15
+ import { isContainedRelativePath, normalizePathSlashes } from '../utils/paths.js';
16
+ import { parseDiffSections } from './patch-parse.js';
17
+ function refuse(message) {
18
+ throw new GeneralError(`Negative control diff refused: ${message}`);
19
+ }
20
+ /** A `---`/`+++` file name, without a trailing timestamp or git's `a/`/`b/`. */
21
+ function plainDiffPath(raw) {
22
+ const name = raw.split('\t')[0]?.trim() ?? '';
23
+ return name.startsWith('a/') || name.startsWith('b/') ? name.slice(2) : name;
24
+ }
25
+ /**
26
+ * Gives a plain unified diff (`diff -u`, no `diff --git` lines) the git
27
+ * header the section parser keys on, one per `---`/`+++` pair. A diff that
28
+ * already carries `diff --git` headers is returned unchanged.
29
+ *
30
+ * @param content - The diff file's text
31
+ */
32
+ function withGitHeaders(content) {
33
+ const lines = content.split('\n');
34
+ if (lines.some((line) => line.startsWith('diff --git ')))
35
+ return content;
36
+ const out = [];
37
+ for (let index = 0; index < lines.length; index += 1) {
38
+ const line = lines[index] ?? '';
39
+ const next = lines[index + 1] ?? '';
40
+ if (line.startsWith('--- ') && next.startsWith('+++ ')) {
41
+ const oldPath = plainDiffPath(line.slice(4));
42
+ const newPath = plainDiffPath(next.slice(4));
43
+ index += 1;
44
+ if (oldPath === '/dev/null' || newPath === '/dev/null') {
45
+ // Kept as a create/delete, which the parser below refuses by name.
46
+ const path = oldPath === '/dev/null' ? newPath : oldPath;
47
+ out.push(`diff --git a/${path} b/${path}`, oldPath === '/dev/null' ? 'new file mode 100644' : 'deleted file mode 100644', oldPath === '/dev/null' ? '--- /dev/null' : `--- a/${path}`, newPath === '/dev/null' ? '+++ /dev/null' : `+++ b/${path}`);
48
+ continue;
49
+ }
50
+ out.push(`diff --git a/${oldPath} b/${newPath}`, `--- a/${oldPath}`, `+++ b/${newPath}`);
51
+ continue;
52
+ }
53
+ out.push(line);
54
+ }
55
+ return out.join('\n');
56
+ }
57
+ /**
58
+ * Parses a control diff. Accepts `git diff` output (a `diff --git` header
59
+ * per file), which is what `git -C engine diff -- <file>` or a project-root
60
+ * `git diff` writes, a plain unified diff (`diff -u`), and, through
61
+ * `resolveRename`, a `git diff --no-index` against an edited copy.
62
+ *
63
+ * @param content - The diff file's text
64
+ * @param options - See {@link ParseControlDiffOptions}
65
+ * @returns One entry per file, in diff order
66
+ */
67
+ export function parseControlDiff(content, options = {}) {
68
+ const sections = parseDiffSections(withGitHeaders(content));
69
+ if (sections.length === 0) {
70
+ refuse('no diff sections found. Write the control with git, e.g. ' +
71
+ '`git -C engine diff -- <file> > control.diff` after making the edit, then revert the edit.');
72
+ }
73
+ const seen = new Set();
74
+ return sections.map((section) => {
75
+ let path = normalizePathSlashes(section.targetPath);
76
+ if (section.isBinary)
77
+ refuse(`${path} is a binary section.`);
78
+ if (section.isNewFile || section.isDeletedFile) {
79
+ refuse(`${path} creates or deletes a file; a control may only modify existing text files.`);
80
+ }
81
+ if (section.sourcePath !== section.targetPath) {
82
+ const resolved = options.resolveRename?.(section.sourcePath, section.targetPath);
83
+ if (resolved === undefined) {
84
+ refuse(`${section.sourcePath} -> ${path} is a rename; a control may only modify files.`);
85
+ }
86
+ path = normalizePathSlashes(resolved);
87
+ }
88
+ if (!isContainedRelativePath(path)) {
89
+ refuse(`${path} is not a contained relative path.`);
90
+ }
91
+ if (section.hunks.length === 0)
92
+ refuse(`${path} has no hunks.`);
93
+ if (seen.has(path))
94
+ refuse(`${path} appears in more than one section.`);
95
+ seen.add(path);
96
+ return { path, hunks: section.hunks };
97
+ });
98
+ }
99
+ function hunkSides(hunk, label, index) {
100
+ const oldLines = [];
101
+ const newLines = [];
102
+ for (const line of hunk.lines) {
103
+ const body = line.slice(1);
104
+ if (line.startsWith(' ') || line.startsWith('-'))
105
+ oldLines.push(body);
106
+ if (line.startsWith(' ') || line.startsWith('+'))
107
+ newLines.push(body);
108
+ }
109
+ if (oldLines.length !== hunk.oldCount || newLines.length !== hunk.newCount) {
110
+ refuse(`hunk ${index + 1} of ${label} is malformed: its header counts ` +
111
+ `(-${hunk.oldCount} +${hunk.newCount}) do not match its body ` +
112
+ `(-${oldLines.length} +${newLines.length}).`);
113
+ }
114
+ return { oldLines, newLines };
115
+ }
116
+ function matchesAt(lines, block, position) {
117
+ if (position < 0 || position + block.length > lines.length)
118
+ return false;
119
+ return block.every((line, offset) => lines[position + offset] === line);
120
+ }
121
+ /**
122
+ * The position nearest `anchor`, at or after `floor`, where `block`
123
+ * matches, or -1.
124
+ */
125
+ function findBlock(lines, block, anchor, floor) {
126
+ const start = Math.max(anchor, floor);
127
+ for (let delta = 0; delta <= lines.length; delta += 1) {
128
+ if (matchesAt(lines, block, start + delta))
129
+ return start + delta;
130
+ const below = anchor - delta;
131
+ if (delta > 0 && below >= floor && matchesAt(lines, block, below))
132
+ return below;
133
+ }
134
+ return -1;
135
+ }
136
+ /**
137
+ * Applies `hunks` to `original`, strictly.
138
+ *
139
+ * @param original - The file's current text
140
+ * @param hunks - Hunks parsed from the control diff
141
+ * @param label - File label for refusal messages
142
+ * @returns The mutated text
143
+ * @throws GeneralError when any hunk does not apply
144
+ */
145
+ export function applyControlHunks(original, hunks, label) {
146
+ const hasFinalNewline = original.endsWith('\n');
147
+ const lines = original === '' ? [] : (hasFinalNewline ? original.slice(0, -1) : original).split('\n');
148
+ const result = [];
149
+ let cursor = 0;
150
+ let finalNewline = hasFinalNewline;
151
+ hunks.forEach((hunk, index) => {
152
+ const { oldLines, newLines } = hunkSides(hunk, label, index);
153
+ const anchor = hunk.oldCount === 0 ? hunk.oldStart : hunk.oldStart - 1;
154
+ const position = oldLines.length === 0
155
+ ? anchor >= cursor && anchor <= lines.length
156
+ ? anchor
157
+ : -1
158
+ : findBlock(lines, oldLines, anchor, cursor);
159
+ const reachesEnd = position + oldLines.length === lines.length;
160
+ const endMatches = position >= 0 &&
161
+ (reachesEnd && oldLines.length > 0
162
+ ? hunk.noNewlineAtEndOld === !hasFinalNewline
163
+ : !hunk.noNewlineAtEndOld);
164
+ if (position < 0 || !endMatches) {
165
+ const alreadyApplied = newLines.length > 0 && findBlock(lines, newLines, Math.max(0, hunk.newStart - 1), 0) >= 0;
166
+ refuse(`hunk ${index + 1} of ${label} (@@ -${hunk.oldStart},${hunk.oldCount} ` +
167
+ `+${hunk.newStart},${hunk.newCount} @@) does not apply to the current file.` +
168
+ (alreadyApplied
169
+ ? ' Its new side is already present: the mutation looks applied already (an earlier control that was not restored?).'
170
+ : ' The file changed since the diff was written; regenerate the control against it.'));
171
+ }
172
+ result.push(...lines.slice(cursor, position), ...newLines);
173
+ cursor = position + oldLines.length;
174
+ if (reachesEnd)
175
+ finalNewline = !hunk.noNewlineAtEndNew;
176
+ });
177
+ result.push(...lines.slice(cursor));
178
+ return result.join('\n') + (finalNewline && result.length > 0 ? '\n' : '');
179
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * `fireforge test --negative-control <diff>`: apply a reviewed mutation to
3
+ * engine sources for exactly one harness dispatch, then put every byte back.
4
+ *
5
+ * Safety model (also stated in docs/testing.md):
6
+ *
7
+ * - The control is applied and restored only while the caller holds the
8
+ * engine-session lock, after the pre-test build has packaged and before
9
+ * the harness spawns, so no peer build or test can observe it and a
10
+ * Furnace deploy cannot overwrite it.
11
+ * - Before the first mutated byte is written, the original bytes of every
12
+ * target go to `.fireforge/negative-control/` together with a journal
13
+ * recording each file's original and mutated SHA-256, mode and
14
+ * timestamps. A killed FireForge therefore leaves enough on disk to undo
15
+ * the control, and the next `fireforge test` does so before anything else.
16
+ * - Restore writes the original bytes back atomically, re-applies the
17
+ * original mode and timestamps, and reads the file back to prove the
18
+ * bytes match. It only overwrites a file that still holds exactly the
19
+ * bytes the control wrote: anything else means someone edited the file
20
+ * while the control ran, and that edit is kept, never clobbered, with the
21
+ * original left in the journal directory and the conflict reported.
22
+ * - A SIGINT or SIGTERM restores through {@link restoreActiveNegativeControlsForSignal},
23
+ * which the entry point runs after the harness has shut down and before
24
+ * it releases the held locks.
25
+ */
26
+ import type { ParsedHunk } from './patch-parse.js';
27
+ /** One file a control mutates. */
28
+ export interface NegativeControlTarget {
29
+ /** The path as the diff names it. */
30
+ diffPath: string;
31
+ /** The engine-relative file the control mutates. */
32
+ enginePath: string;
33
+ /** Hunks to apply to the engine file. */
34
+ hunks: ParsedHunk[];
35
+ /** True when the diff named a `components/` source mapped to its deployed copy. */
36
+ fromComponents: boolean;
37
+ }
38
+ /** A parsed, resolved control, ready to apply. */
39
+ export interface NegativeControlPlan {
40
+ /** The diff file, as the operator passed it. */
41
+ diffFile: string;
42
+ targets: NegativeControlTarget[];
43
+ /**
44
+ * Engine-relative targets only a build delivers (compiled sources). A
45
+ * control with any must be applied before the pre-test build, and is
46
+ * restored with a fresh mtime. See `negative-control-compiled.ts`.
47
+ */
48
+ compiled?: string[];
49
+ }
50
+ /** Locations a control works against. */
51
+ export interface NegativeControlPaths {
52
+ engineDir: string;
53
+ /** The project's `.fireforge/` directory. */
54
+ fireforgeDir: string;
55
+ }
56
+ interface JournalEntry {
57
+ enginePath: string;
58
+ backup: string;
59
+ originalSha256: string;
60
+ mutatedSha256: string;
61
+ mode: number;
62
+ atimeMs: number;
63
+ mtimeMs: number;
64
+ /**
65
+ * Restore with the current time as mtime, not the original: a compiled
66
+ * source restored with its old mtime is skipped by the incremental build,
67
+ * which would leave the mutated code in the binary.
68
+ */
69
+ freshMtime?: boolean;
70
+ }
71
+ interface Journal {
72
+ version: 1;
73
+ diffFile: string;
74
+ appliedAt: string;
75
+ entries: JournalEntry[];
76
+ }
77
+ /** A control currently applied to the engine. */
78
+ export interface ActiveNegativeControl {
79
+ paths: NegativeControlPaths;
80
+ journal: Journal;
81
+ /**
82
+ * The one restore in flight, set synchronously by whichever path (the
83
+ * run's own `finally`, or the signal handler) gets there first, so the
84
+ * other awaits the same restore instead of racing or skipping it.
85
+ */
86
+ restoring?: Promise<NegativeControlRestoreResult>;
87
+ }
88
+ /**
89
+ * Reads, parses and resolves a control diff, and (unless `deferApplyCheck`)
90
+ * proves every hunk applies to the current engine file, so a broken control
91
+ * is refused before any build time is spent.
92
+ *
93
+ * `deferApplyCheck` is for a run that builds first: Furnace redeploys a
94
+ * component's engine copy during the build, so a `components/` control can
95
+ * only be checked against what the build left behind.
96
+ *
97
+ * @param projectRoot - Project root; the diff path resolves against it
98
+ * @param engineDir - Absolute engine directory
99
+ * @param diffFile - The `--negative-control` argument
100
+ * @param options - `deferApplyCheck` skips the up-front apply check for
101
+ * `components/` targets
102
+ */
103
+ export declare function planNegativeControl(projectRoot: string, engineDir: string, diffFile: string, options?: {
104
+ deferApplyCheck?: boolean;
105
+ }): Promise<NegativeControlPlan>;
106
+ /**
107
+ * Applies the control: every target is computed first (a hunk that does
108
+ * not apply refuses with nothing written), the originals and the journal
109
+ * are persisted, then the mutated bytes are written. Runs as a signal
110
+ * critical section, so a Ctrl+C mid-apply waits for the apply to finish
111
+ * and the signal path then restores a complete journal.
112
+ *
113
+ * @returns The handle {@link restoreNegativeControl} takes
114
+ */
115
+ export declare function applyNegativeControl(paths: NegativeControlPaths, plan: NegativeControlPlan): Promise<ActiveNegativeControl>;
116
+ /** What happened to each file of a restored control. */
117
+ export interface NegativeControlRestoreResult {
118
+ /** Engine-relative files put back to their original bytes. */
119
+ restored: string[];
120
+ /** Engine-relative files that held neither the control's bytes nor the original. */
121
+ conflicts: string[];
122
+ }
123
+ /**
124
+ * Restores a control applied by {@link applyNegativeControl}. Idempotent:
125
+ * a second caller (the signal handler racing the run's own `finally`)
126
+ * receives the restore already in flight.
127
+ *
128
+ * @throws GeneralError when a file changed under the control (the edit is
129
+ * kept and the original stays in the journal directory) or did not read
130
+ * back byte-exact
131
+ */
132
+ export declare function restoreNegativeControl(control: ActiveNegativeControl): Promise<NegativeControlRestoreResult>;
133
+ /**
134
+ * Restores every applied control on the way out of a SIGINT/SIGTERM. Called
135
+ * by the entry point after child shutdown and before the held locks are
136
+ * force-released. Never throws: a failure is reported on stderr and the
137
+ * journal stays for the next run's recovery.
138
+ */
139
+ export declare function restoreActiveNegativeControlsForSignal(): Promise<void>;
140
+ /**
141
+ * Undoes a control a killed FireForge left applied. Called at the start of
142
+ * every `fireforge test`, under the engine-session lock. A file that still
143
+ * holds the control's bytes is restored; a file somebody changed since is
144
+ * refused rather than overwritten.
145
+ *
146
+ * @throws PreflightRefusalError (`note=negative-control-pending`) when a
147
+ * journal entry cannot be restored safely
148
+ */
149
+ export declare function recoverPendingNegativeControl(paths: NegativeControlPaths): Promise<void>;
150
+ export {};