@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
@@ -5,19 +5,25 @@
5
5
  * loop calls {@link reExportSinglePatchWithIndexLockRetry} per selected
6
6
  * patch.
7
7
  */
8
+ import { join } from 'node:path';
8
9
  import { stdioIsInteractive } from '../core/destructive.js';
9
10
  import { enforceFreshFurnaceSources } from '../core/furnace-stale-export.js';
10
11
  import { getDiffForFilesAgainstHead } from '../core/git-diff.js';
11
12
  import { listTrackedInHead } from '../core/git-file-ops.js';
12
13
  import { updatePatchAndMetadata } from '../core/patch-export.js';
14
+ import { withoutFields } from '../core/patch-export-update.js';
15
+ import { buildLintIgnoreChecks, lintIgnoreRule, mergeLintIgnoreIds, } from '../core/patch-lint-ignore.js';
13
16
  import { buildProjectedManifest, enforcePatchPolicy } from '../core/patch-policy.js';
14
17
  import { isGitIndexLockConflict } from '../errors/git.js';
18
+ import { readText } from '../utils/fs.js';
15
19
  import { info, success, warn } from '../utils/logger.js';
16
20
  import { sleep } from '../utils/sleep.js';
17
21
  import { findMissingFiles, reportAdjacentUnmanagedFiles } from './re-export-adjacent.js';
18
22
  import { reportForeignDrift } from './re-export-drift.js';
23
+ import { buildHunkSelectedDiff, hunkSelectionOf } from './re-export-hunks.js';
19
24
  import { assertRefreshedBodyHasNoNewQueueErrors, lintReExportedPatch, refreshQueueCtxEntry, storeReExportLintResult, } from './re-export-lint.js';
20
25
  import { assertScanAdoptionsHaveNoForwardImports, assertScanFileAdditionsHaveDiffHunks, confirmBroadScanAdditions, scanPatchFilesForReExport, } from './re-export-scan.js';
26
+ import { planStaleRegistrationDrop, recordStaleRegistrationDrop, reportStaleRegistrationDrop, } from './re-export-stale-registrations.js';
21
27
  const GIT_INDEX_LOCK_RETRY_MS = 300;
22
28
  /**
23
29
  * Retries a single patch re-export exactly once when the failure is
@@ -39,47 +45,74 @@ export async function reExportSinglePatchWithIndexLockRetry(args) {
39
45
  return await reExportSinglePatch(args);
40
46
  }
41
47
  }
48
+ /**
49
+ * The `--scan` branch: scans, gates the adoption on forward imports,
50
+ * confirms a broad scan and, under `--refuse-adjacent-unmanaged`, judges
51
+ * the neighbours the scan left. Undefined means the patch is not written.
52
+ */
53
+ async function adoptScannedFiles(args, currentFilesAffected) {
54
+ const { patch, paths, manifest, options, isDryRun, config, adjacentCtx } = args;
55
+ const scanResult = await scanPatchFilesForReExport({
56
+ currentFilesAffected,
57
+ engineDir: paths.engine,
58
+ manifest,
59
+ patchFilename: patch.filename,
60
+ isDryRun,
61
+ ...(options.scanFiles !== undefined ? { scanFiles: options.scanFiles } : {}),
62
+ });
63
+ // Forward-import gate at adoption time (runs in dry-run too): refuse
64
+ // to adopt unmanaged files that import modules created by later
65
+ // patches, because the after-the-fact lint failure this leaves behind
66
+ // is the field-reported footgun. Applies to broad --scan, --scan-file,
67
+ // and the --scan-files bulk assignments alike.
68
+ await assertScanAdoptionsHaveNoForwardImports({
69
+ patchesDir: paths.patches,
70
+ engineDir: paths.engine,
71
+ patchFilename: patch.filename,
72
+ added: scanResult.added,
73
+ config,
74
+ declarationsOut: options.declarationsOut,
75
+ });
76
+ if (options.scanFiles === undefined) {
77
+ const proceed = await confirmBroadScanAdditions({
78
+ patchFilename: patch.filename,
79
+ added: scanResult.added,
80
+ isDryRun,
81
+ yes: options.yes === true,
82
+ isInteractive: stdioIsInteractive(),
83
+ });
84
+ if (!proceed)
85
+ return undefined;
86
+ }
87
+ if (adjacentCtx.refuseAdjacentUnmanaged) {
88
+ const adjacentArgs = {
89
+ patch,
90
+ paths,
91
+ manifest,
92
+ currentFilesAffected: scanResult.updated,
93
+ ctx: adjacentCtx,
94
+ afterScan: true,
95
+ };
96
+ if (await reportAdjacentUnmanagedFiles(adjacentArgs))
97
+ return undefined;
98
+ }
99
+ return { updated: scanResult.updated, added: scanResult.added };
100
+ }
42
101
  async function reExportSinglePatch(args) {
43
102
  const { patch, paths, manifest, options, isDryRun, config, adjacentCtx, driftCtx, lintCtx } = args;
44
103
  const removed = new Set(options.expectRemoved ?? []);
45
- let currentFilesAffected = patch.filesAffected.filter((file) => !removed.has(file));
104
+ const retainedFiles = patch.filesAffected.filter((file) => !removed.has(file));
105
+ let currentFilesAffected = retainedFiles;
106
+ let adoptedFiles = [];
46
107
  for (const file of patch.filesAffected.filter((path) => removed.has(path)))
47
108
  info(` - ${file} (--expect-removed)`);
48
109
  // --- Scan for new/removed files ---
49
110
  if (options.scan) {
50
- const scanResult = await scanPatchFilesForReExport({
51
- currentFilesAffected,
52
- engineDir: paths.engine,
53
- manifest,
54
- patchFilename: patch.filename,
55
- isDryRun,
56
- ...(options.scanFiles !== undefined ? { scanFiles: options.scanFiles } : {}),
57
- });
58
- // Forward-import gate at adoption time (runs in dry-run too): refuse
59
- // to adopt unmanaged files that import modules created by later
60
- // patches, because the after-the-fact lint failure this leaves behind
61
- // is the field-reported footgun. Applies to broad --scan, --scan-file,
62
- // and the --scan-files bulk assignments alike.
63
- await assertScanAdoptionsHaveNoForwardImports({
64
- patchesDir: paths.patches,
65
- engineDir: paths.engine,
66
- patchFilename: patch.filename,
67
- added: scanResult.added,
68
- });
69
- if (options.scanFiles === undefined) {
70
- const isInteractive = stdioIsInteractive();
71
- const proceed = await confirmBroadScanAdditions({
72
- patchFilename: patch.filename,
73
- added: scanResult.added,
74
- isDryRun,
75
- yes: options.yes === true,
76
- isInteractive,
77
- });
78
- if (!proceed) {
79
- return false;
80
- }
81
- }
82
- currentFilesAffected = scanResult.updated;
111
+ const adopted = await adoptScannedFiles(args, currentFilesAffected);
112
+ if (adopted === undefined)
113
+ return false;
114
+ currentFilesAffected = adopted.updated;
115
+ adoptedFiles = adopted.added;
83
116
  }
84
117
  else if (options.files === undefined) {
85
118
  // When neither `--scan` nor `--files` is set and some of the manifest's
@@ -138,7 +171,17 @@ async function reExportSinglePatch(args) {
138
171
  }
139
172
  const untrackedSet = new Set(untrackedAbsent);
140
173
  const existingFiles = currentFilesAffected.filter((f) => !untrackedSet.has(f));
141
- const diffContent = await getDiffForFilesAgainstHead(paths.engine, existingFiles);
174
+ let diffContent = await getDiffForFilesAgainstHead(paths.engine, existingFiles);
175
+ const selection = hunkSelectionOf(options);
176
+ if (selection !== undefined) {
177
+ diffContent = await buildHunkSelectedDiff({
178
+ engineDir: paths.engine,
179
+ selection,
180
+ oldBody: await readText(join(paths.patches, patch.filename)),
181
+ normalDiff: diffContent,
182
+ files: existingFiles,
183
+ });
184
+ }
142
185
  assertScanFileAdditionsHaveDiffHunks({
143
186
  diffContent,
144
187
  patchFilename: patch.filename,
@@ -153,17 +196,25 @@ async function reExportSinglePatch(args) {
153
196
  // payload lines are about to enter the body that the old body did not
154
197
  // carry, the case where a concurrent session's uncommitted edits in
155
198
  // owned files would be silently absorbed. Always previews (including
156
- // dry-run and --scan). Refuses only under --refuse-foreign-drift.
199
+ // dry-run and --scan). Refuses only under --refuse-foreign-drift. Covers
200
+ // the files the patch already owned; adopted and retired files are the
201
+ // run's stated intent, not drift.
157
202
  if (await reportForeignDrift({
158
203
  patch,
159
204
  patchesDir: paths.patches,
160
205
  engineDir: paths.engine,
161
206
  newDiffContent: diffContent,
162
207
  ctx: driftCtx,
208
+ ownedFiles: retainedFiles,
209
+ adoptedFiles,
163
210
  })) {
164
211
  return false;
165
212
  }
166
213
  const { updates, ignoreChecks, effectiveTier, existingIgnoreSet, flagIgnoreSet } = computeReExportUpdates(patch, options, currentFilesAffected);
214
+ const stalePlan = planStaleRegistrationDrop(manifest, patch, currentFilesAffected);
215
+ if (stalePlan !== undefined)
216
+ reportStaleRegistrationDrop(patch.filename, stalePlan, isDryRun);
217
+ const unset = applyStaleRegistrationDrop(stalePlan, updates);
167
218
  enforceProjectedManifestPolicy({ config, manifest, patch, updates, options });
168
219
  // Cross-patch projection gate (runs in dry-run too): the refreshed body
169
220
  // must not introduce queue-level errors the current queue lacks, e.g. an
@@ -179,7 +230,7 @@ async function reExportSinglePatch(args) {
179
230
  // Lint against the once-per-invocation hoisted context (queue context +
180
231
  // queue-wide checkJs program + per-patch result cache) instead of
181
232
  // rebuilding ~37 s of setup for every patch in the loop.
182
- const projectedMetadata = { ...patch, ...updates };
233
+ const projectedMetadata = withoutFields({ ...patch, ...updates }, unset);
183
234
  const lintResult = await lintReExportedPatch({
184
235
  lintCtx,
185
236
  patch,
@@ -213,6 +264,8 @@ async function reExportSinglePatch(args) {
213
264
  lintCtx,
214
265
  diffContent,
215
266
  updates,
267
+ unset,
268
+ stalePlan,
216
269
  projectedMetadata,
217
270
  existingFiles,
218
271
  lintResult,
@@ -228,6 +281,13 @@ function enforceProjectedManifestPolicy(args) {
228
281
  manifest: buildProjectedManifest(manifest, manifest.patches.map((entry) => entry.filename === patch.filename ? { ...entry, ...updates } : entry)),
229
282
  command: 're-export',
230
283
  forceUnsafe: options.forceUnsafe === true,
284
+ // A re-export changes only this row's contents, so only its findings
285
+ // can be new; another patch's stale row must not fail this one.
286
+ scope: [patch.filename],
287
+ hints: {
288
+ 'reserved-files': 'A path whose engine copy is back at HEAD can be dropped from the patch with ' +
289
+ '--expect-removed <path>; any other path needs its reserved allowlist entry.',
290
+ },
231
291
  });
232
292
  }
233
293
  /**
@@ -247,11 +307,13 @@ async function commitRefreshedPatch(args) {
247
307
  filename: patch.filename,
248
308
  newContent: diffContent,
249
309
  updates,
250
- onCommitted: undefined,
310
+ ...(args.unset.length > 0 ? { unset: args.unset } : {}),
311
+ onCommitted: staleRecorder(paths.patches, patch.filename, args.stalePlan),
251
312
  policyGate: {
252
313
  config,
253
314
  command: 're-export',
254
315
  forceUnsafe: options.forceUnsafe === true,
316
+ scope: [patch.filename],
255
317
  },
256
318
  });
257
319
  refreshQueueCtxEntry(lintCtx, patch.filename, diffContent);
@@ -262,10 +324,7 @@ async function commitRefreshedPatch(args) {
262
324
  if (patchIndex !== -1) {
263
325
  const existingEntry = manifest.patches[patchIndex];
264
326
  if (existingEntry) {
265
- manifest.patches[patchIndex] = {
266
- ...existingEntry,
267
- ...updates,
268
- };
327
+ manifest.patches[patchIndex] = withoutFields({ ...existingEntry, ...updates }, args.unset);
269
328
  }
270
329
  }
271
330
  // A bulk run refreshes every patch. Saying "Re-exported" for one whose body
@@ -278,6 +337,24 @@ async function commitRefreshedPatch(args) {
278
337
  info(`Unchanged ${patch.filename}`);
279
338
  }
280
339
  }
340
+ /** The history hook for a write that drops stale registrations, if any. */
341
+ function staleRecorder(patchesDir, patchFilename, plan) {
342
+ if (plan === undefined)
343
+ return undefined;
344
+ return () => recordStaleRegistrationDrop(patchesDir, patchFilename, plan);
345
+ }
346
+ /**
347
+ * Folds the stale-registration drop into `updates`: the kept staged block
348
+ * is set, or the field is returned for unsetting when nothing is left.
349
+ */
350
+ function applyStaleRegistrationDrop(plan, updates) {
351
+ if (plan === undefined)
352
+ return [];
353
+ if (plan.stagedDependencies === undefined)
354
+ return ['stagedDependencies'];
355
+ updates.stagedDependencies = plan.stagedDependencies;
356
+ return [];
357
+ }
281
358
  /**
282
359
  * Threads the patch's own `lintIgnore` list through so the per-patch
283
360
  * suppression honoured by export/export-all is also honoured here. A
@@ -289,10 +366,9 @@ async function commitRefreshedPatch(args) {
289
366
  * pass so the new intent takes effect on this invocation.
290
367
  */
291
368
  function computeReExportUpdates(patch, options, currentFilesAffected) {
292
- const existingIgnoreSet = new Set(patch.lintIgnore ?? []);
369
+ const existingIgnoreSet = new Set((patch.lintIgnore ?? []).map(lintIgnoreRule));
293
370
  const flagIgnoreSet = new Set(options.lintIgnore ?? []);
294
- const mergedIgnoreSet = new Set([...existingIgnoreSet, ...flagIgnoreSet]);
295
- const effectiveLintIgnore = mergedIgnoreSet.size > 0 ? [...mergedIgnoreSet] : undefined;
371
+ const effectiveLintIgnore = mergeLintIgnoreIds(patch.lintIgnore, [...flagIgnoreSet]);
296
372
  const updates = {
297
373
  filesAffected: currentFilesAffected,
298
374
  };
@@ -304,7 +380,7 @@ function computeReExportUpdates(patch, options, currentFilesAffected) {
304
380
  }
305
381
  return {
306
382
  updates,
307
- ignoreChecks: effectiveLintIgnore ? new Set(effectiveLintIgnore) : undefined,
383
+ ignoreChecks: buildLintIgnoreChecks(effectiveLintIgnore),
308
384
  effectiveTier: options.tier ?? patch.tier,
309
385
  existingIgnoreSet,
310
386
  flagIgnoreSet,
@@ -0,0 +1,18 @@
1
+ import type { PatchesManifest, PatchMetadata, PatchStagedDependencies, PatchStagedRegistration } from '../types/commands/index.js';
2
+ /** The holder's registrations split by whether the queue still owns `creates`. */
3
+ export interface StaleRegistrationPlan {
4
+ /** Registrations whose `creates` path no patch owns. */
5
+ dropped: PatchStagedRegistration[];
6
+ /** The staged block to write, or undefined when nothing is left. */
7
+ stagedDependencies: PatchStagedDependencies | undefined;
8
+ }
9
+ /**
10
+ * Finds `patch`'s registrations whose `creates` path no patch in the queue
11
+ * owns, judging `patch` by the file list this re-export will write.
12
+ * Returns undefined when nothing is stale.
13
+ */
14
+ export declare function planStaleRegistrationDrop(manifest: PatchesManifest, patch: PatchMetadata, currentFilesAffected: readonly string[]): StaleRegistrationPlan | undefined;
15
+ /** Names each dropped registration, in both a dry run and a write. */
16
+ export declare function reportStaleRegistrationDrop(patchFilename: string, plan: StaleRegistrationPlan, isDryRun: boolean): void;
17
+ /** Records the dropped declarations as a delta, like `staged-dependency --remove`. */
18
+ export declare function recordStaleRegistrationDrop(patchesDir: string, patchFilename: string, plan: StaleRegistrationPlan): Promise<void>;
@@ -0,0 +1,62 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Re-export prunes a staged registration the queue can no longer satisfy.
4
+ *
5
+ * A merge that deletes a file whose jar.mn line lives in another patch
6
+ * left the staged registration on that patch: re-export kept it, lint then
7
+ * warned `staged-dependency-unused`, and the stale declaration also kept
8
+ * the holder measuring above a just-lowered size ceiling. When no patch in
9
+ * the queue owns a registration's `creates` path any more, the declaration
10
+ * cannot be met, so the holder's own re-export drops it and says so.
11
+ */
12
+ import { appendHistoryBestEffort } from '../core/history-log.js';
13
+ import { info } from '../utils/logger.js';
14
+ /**
15
+ * Finds `patch`'s registrations whose `creates` path no patch in the queue
16
+ * owns, judging `patch` by the file list this re-export will write.
17
+ * Returns undefined when nothing is stale.
18
+ */
19
+ export function planStaleRegistrationDrop(manifest, patch, currentFilesAffected) {
20
+ const registrations = patch.stagedDependencies?.registrations ?? [];
21
+ if (registrations.length === 0)
22
+ return undefined;
23
+ const owned = new Set(currentFilesAffected);
24
+ for (const entry of manifest.patches) {
25
+ if (entry.filename === patch.filename)
26
+ continue;
27
+ for (const file of entry.filesAffected)
28
+ owned.add(file);
29
+ }
30
+ const dropped = registrations.filter((registration) => !owned.has(registration.creates));
31
+ if (dropped.length === 0)
32
+ return undefined;
33
+ const kept = registrations.filter((registration) => owned.has(registration.creates));
34
+ const forwardImports = patch.stagedDependencies?.forwardImports ?? [];
35
+ const staged = {
36
+ ...(forwardImports.length > 0 ? { forwardImports } : {}),
37
+ ...(kept.length > 0 ? { registrations: kept } : {}),
38
+ };
39
+ return {
40
+ dropped,
41
+ stagedDependencies: Object.keys(staged).length > 0 ? staged : undefined,
42
+ };
43
+ }
44
+ /** Names each dropped registration, in both a dry run and a write. */
45
+ export function reportStaleRegistrationDrop(patchFilename, plan, isDryRun) {
46
+ const verb = isDryRun ? 'would drop' : 'drops';
47
+ for (const registration of plan.dropped) {
48
+ info(`${patchFilename}: ${verb} staged registration ${registration.file} "${registration.line.trim()}": ` +
49
+ `no patch in the queue creates ${registration.creates} any more.`);
50
+ }
51
+ }
52
+ /** Records the dropped declarations as a delta, like `staged-dependency --remove`. */
53
+ export async function recordStaleRegistrationDrop(patchesDir, patchFilename, plan) {
54
+ await appendHistoryBestEffort(patchesDir, {
55
+ operation: 're-export-staged-prune',
56
+ args: {
57
+ filename: patchFilename,
58
+ removed: plan.dropped.map((registration) => ({ kind: 'registration', ...registration })),
59
+ },
60
+ result: 'ok',
61
+ }, `re-export pruned stale staged registrations on ${patchFilename}`);
62
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The one-line end-of-run summary of a multi-patch `re-export`.
3
+ *
4
+ * A long run interleaves per-patch lint output, drift previews and
5
+ * refusals, and the patches it wrote were easy to confuse with the one it
6
+ * did not. The summary names both sets and why each unwritten patch was
7
+ * not written, so the re-run list is one line to read.
8
+ */
9
+ /** What became of each selected patch. */
10
+ export interface ReExportRunTally {
11
+ /** Selected patches, in run order. */
12
+ selected: readonly string[];
13
+ /** Patches written (or, in a dry run, that would be written). */
14
+ written: readonly string[];
15
+ /** Patches whose re-export threw. */
16
+ failed: readonly string[];
17
+ /** Patches refused by `--refuse-adjacent-unmanaged`. */
18
+ refusedAdjacent: readonly string[];
19
+ /** Patches refused by `--refuse-foreign-drift`. */
20
+ refusedDrift: readonly string[];
21
+ /** Whether the run is a dry run. */
22
+ isDryRun: boolean;
23
+ }
24
+ /**
25
+ * Renders the summary, or undefined for a single-patch run, where the
26
+ * outcome line already says everything.
27
+ */
28
+ export declare function formatReExportRunSummary(tally: ReExportRunTally): string | undefined;
@@ -0,0 +1,36 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * The one-line end-of-run summary of a multi-patch `re-export`.
4
+ *
5
+ * A long run interleaves per-patch lint output, drift previews and
6
+ * refusals, and the patches it wrote were easy to confuse with the one it
7
+ * did not. The summary names both sets and why each unwritten patch was
8
+ * not written, so the re-run list is one line to read.
9
+ */
10
+ /**
11
+ * Renders the summary, or undefined for a single-patch run, where the
12
+ * outcome line already says everything.
13
+ */
14
+ export function formatReExportRunSummary(tally) {
15
+ if (tally.selected.length <= 1)
16
+ return undefined;
17
+ const written = new Set(tally.written);
18
+ const reasons = new Map();
19
+ for (const name of tally.failed)
20
+ reasons.set(name, 'failed');
21
+ for (const name of tally.refusedAdjacent)
22
+ reasons.set(name, 'refused: adjacent unmanaged');
23
+ for (const name of tally.refusedDrift)
24
+ reasons.set(name, 'refused: foreign drift');
25
+ const notWritten = tally.selected
26
+ .filter((name) => !written.has(name))
27
+ .map((name) => `${name} (${reasons.get(name) ?? 'skipped'})`);
28
+ const verb = tally.isDryRun ? 'would write' : 'wrote';
29
+ const writtenPart = tally.written.length > 0
30
+ ? `${verb} ${tally.written.length} of ${tally.selected.length}: ${tally.written.join(', ')}`
31
+ : `${verb} 0 of ${tally.selected.length}`;
32
+ const notWrittenPart = notWritten.length > 0
33
+ ? `; ${tally.isDryRun ? 'would NOT write' : 'NOT written'}: ${notWritten.join(', ')}`
34
+ : '';
35
+ return `Re-export summary: ${writtenPart}${notWrittenPart}.`;
36
+ }