@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
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `patch staged-dependency --add --from <json-file>`: adds every
3
+ * declaration a file supplies for one patch in a single manifest update
4
+ * under one lock hold. The file format and the history delta live in
5
+ * `staged-dependency-batch.ts`.
6
+ */
7
+ import type { PatchStagedDependencyOptions } from '../../types/commands/index.js';
8
+ import { type StagedDependencyMode } from './staged-dependency-entries.js';
9
+ /**
10
+ * `--add --from <json-file>`: every declaration the file supplies for the
11
+ * target patch, validated up front and written in one manifest update
12
+ * under one lock hold, with one delta history record.
13
+ */
14
+ export declare function runBatchAdd(projectRoot: string, identifier: string, mode: StagedDependencyMode, options: PatchStagedDependencyOptions): Promise<void>;
@@ -0,0 +1,108 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * `patch staged-dependency --add --from <json-file>`: adds every
4
+ * declaration a file supplies for one patch in a single manifest update
5
+ * under one lock hold. The file format and the history delta live in
6
+ * `staged-dependency-batch.ts`.
7
+ */
8
+ import { appendHistoryBestEffort } from '../../core/history-log.js';
9
+ import { mutatePatchMetadata } from '../../core/patch-export.js';
10
+ import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
11
+ import { info, outro } from '../../utils/logger.js';
12
+ import { resolveWaitLockSeconds } from '../../utils/options.js';
13
+ import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
14
+ import { readStagedDependencyBatch, stagedDependencyDelta, } from './staged-dependency-batch.js';
15
+ import { applyMode, countStagedEntries, importView, registrationView, } from './staged-dependency-entries.js';
16
+ import { validateStagedDependencyAdd } from './staged-dependency-validate.js';
17
+ /** Flags that describe one declaration and so cannot combine with `--from`. */
18
+ const SINGLE_DECLARATION_FLAGS = [
19
+ ['--kind', 'kind'],
20
+ ['--file', 'file'],
21
+ ['--specifier', 'specifier'],
22
+ ['--line', 'line'],
23
+ ['--creates', 'creates'],
24
+ ['--owner', 'owner'],
25
+ ];
26
+ /** Adds every `--from` declaration not already present, keyed like a single `--add`. */
27
+ function mergeBatch(staged, batch) {
28
+ let forwardImports = [...(staged?.forwardImports ?? [])];
29
+ for (const entry of batch.forwardImports) {
30
+ forwardImports = applyMode(forwardImports, 'add', importView(entry), importView, entry);
31
+ }
32
+ let registrations = [...(staged?.registrations ?? [])];
33
+ for (const entry of batch.registrations) {
34
+ registrations = applyMode(registrations, 'add', registrationView(entry), registrationView, entry);
35
+ }
36
+ return {
37
+ ...(forwardImports.length > 0 ? { forwardImports } : {}),
38
+ ...(registrations.length > 0 ? { registrations } : {}),
39
+ };
40
+ }
41
+ /**
42
+ * `--add --from <json-file>`: every declaration the file supplies for the
43
+ * target patch, validated up front and written in one manifest update
44
+ * under one lock hold, with one delta history record.
45
+ */
46
+ export async function runBatchAdd(projectRoot, identifier, mode, options) {
47
+ const from = options.from ?? '';
48
+ if (mode !== 'add') {
49
+ throw new InvalidArgumentError('--from only applies to --add.', '--from');
50
+ }
51
+ const clashing = SINGLE_DECLARATION_FLAGS.filter(([, key]) => options[key] !== undefined);
52
+ if (clashing.length > 0) {
53
+ throw new InvalidArgumentError(`--from supplies the declarations itself; drop ${clashing.map(([flag]) => flag).join(', ')}.`, '--from');
54
+ }
55
+ const { paths, manifest } = await requirePatchQueue(projectRoot);
56
+ const targetPatch = requirePatchTarget(identifier, manifest.patches);
57
+ const batch = await readStagedDependencyBatch(from, targetPatch.filename, options.reason);
58
+ for (const entry of [...batch.forwardImports, ...batch.registrations]) {
59
+ validateStagedDependencyAdd(entry, manifest.patches);
60
+ }
61
+ const supplied = batch.forwardImports.length + batch.registrations.length;
62
+ if (batch.skippedForOtherPatches > 0) {
63
+ info(`Skipped ${batch.skippedForOtherPatches} declaration(s) in ${from} that name another patch.`);
64
+ }
65
+ if (supplied === 0) {
66
+ info(`${from} holds no declarations for ${targetPatch.filename}; nothing to add.`);
67
+ outro('Patch staged-dependency complete');
68
+ return;
69
+ }
70
+ const existing = targetPatch.stagedDependencies;
71
+ const projectedCount = countStagedEntries(mergeBatch(existing, batch));
72
+ const describe = (beforeCount, afterCount) => `added ${afterCount - beforeCount} of ${supplied} staged declaration(s) from ${from}` +
73
+ (supplied > afterCount - beforeCount
74
+ ? ` (${supplied - (afterCount - beforeCount)} already present or repeated)`
75
+ : '');
76
+ if (options.dryRun === true) {
77
+ info(`[dry-run] ${targetPatch.filename}: ${describe(countStagedEntries(existing), projectedCount)}.`);
78
+ outro('Dry run complete — no changes made');
79
+ return;
80
+ }
81
+ const result = await mutatePatchMetadata(paths.patches, targetPatch.filename, (current) => {
82
+ const after = mergeBatch(current.stagedDependencies, batch);
83
+ if (countStagedEntries(after) === 0)
84
+ return { unset: ['stagedDependencies'] };
85
+ return { set: { stagedDependencies: after } };
86
+ }, {
87
+ waitLockSeconds: resolveWaitLockSeconds(options.waitLock),
88
+ command: 'patch staged-dependency',
89
+ });
90
+ if (!result) {
91
+ throw new GeneralError(`Patch ${targetPatch.filename} disappeared from the manifest during the update. Re-run after investigating.`);
92
+ }
93
+ const before = result.before.stagedDependencies;
94
+ const after = result.after.stagedDependencies;
95
+ info(`${targetPatch.filename}: ${describe(countStagedEntries(before), countStagedEntries(after))}.`);
96
+ await appendHistoryBestEffort(paths.patches, {
97
+ operation: 'patch-staged-dependency',
98
+ args: {
99
+ filename: targetPatch.filename,
100
+ mode,
101
+ from,
102
+ ...stagedDependencyDelta(before, after),
103
+ },
104
+ ...(options.yes === true ? { yes: true } : {}),
105
+ result: 'ok',
106
+ }, `patch staged-dependency committed (${targetPatch.filename})`);
107
+ outro('Patch staged-dependency complete');
108
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `--remove` target selection for `patch staged-dependency`. Split out of
3
+ * `staged-dependency.ts` for the per-file line budget.
4
+ *
5
+ * A removal names its entries by any of `--file`, `--specifier`/`--line`,
6
+ * `--creates` and `--owner`, and must give at least `--creates` or the
7
+ * `--file` + matcher pair. Registration lines compare whitespace-
8
+ * insensitively (runs of whitespace collapse, ends trimmed), the way the
9
+ * lint compares them, so a line copied from a patch hunk matches the stored
10
+ * one whatever its padding. A selection that matches nothing is refused
11
+ * rather than reported as a no-op.
12
+ */
13
+ import type { PatchStagedDependencies, PatchStagedDependencyOptions } from '../../types/commands/index.js';
14
+ import { type StagedDependencyKind, type StagedEntryView } from './staged-dependency-entries.js';
15
+ /**
16
+ * Resolves the staged entries a `--remove` invocation names. The returned
17
+ * views are the stored entries themselves, so the removal matches them
18
+ * exactly.
19
+ *
20
+ * - `--file` + matcher identifying one entry infers `--creates`.
21
+ * - `--file` + matcher identifying several entries without `--creates`
22
+ * refuses with the candidate list.
23
+ * - `--creates` alone selects every declaration for that created path.
24
+ *
25
+ * @param kind - Declaration kind (`--kind`)
26
+ * @param options - Command options
27
+ * @param staged - The target patch's current staged dependencies
28
+ * @returns The matching stored entries (never empty)
29
+ * @throws InvalidArgumentError when the selectors are insufficient or match nothing
30
+ */
31
+ export declare function selectRemovalEntries(kind: StagedDependencyKind, options: PatchStagedDependencyOptions, staged: PatchStagedDependencies | undefined): StagedEntryView[];
@@ -0,0 +1,80 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * `--remove` target selection for `patch staged-dependency`. Split out of
4
+ * `staged-dependency.ts` for the per-file line budget.
5
+ *
6
+ * A removal names its entries by any of `--file`, `--specifier`/`--line`,
7
+ * `--creates` and `--owner`, and must give at least `--creates` or the
8
+ * `--file` + matcher pair. Registration lines compare whitespace-
9
+ * insensitively (runs of whitespace collapse, ends trimmed), the way the
10
+ * lint compares them, so a line copied from a patch hunk matches the stored
11
+ * one whatever its padding. A selection that matches nothing is refused
12
+ * rather than reported as a no-op.
13
+ */
14
+ import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
15
+ import { info } from '../../utils/logger.js';
16
+ import { dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
17
+ /** Collapses whitespace runs and trims, for registration-line comparison. */
18
+ function normalizeRegistrationLine(line) {
19
+ return line.trim().replace(/\s+/g, ' ');
20
+ }
21
+ function stagedViews(kind, staged) {
22
+ return kind === 'import'
23
+ ? (staged?.forwardImports ?? []).map(importView)
24
+ : (staged?.registrations ?? []).map(registrationView);
25
+ }
26
+ /**
27
+ * Resolves the staged entries a `--remove` invocation names. The returned
28
+ * views are the stored entries themselves, so the removal matches them
29
+ * exactly.
30
+ *
31
+ * - `--file` + matcher identifying one entry infers `--creates`.
32
+ * - `--file` + matcher identifying several entries without `--creates`
33
+ * refuses with the candidate list.
34
+ * - `--creates` alone selects every declaration for that created path.
35
+ *
36
+ * @param kind - Declaration kind (`--kind`)
37
+ * @param options - Command options
38
+ * @param staged - The target patch's current staged dependencies
39
+ * @returns The matching stored entries (never empty)
40
+ * @throws InvalidArgumentError when the selectors are insufficient or match nothing
41
+ */
42
+ export function selectRemovalEntries(kind, options, staged) {
43
+ const matcherFlag = kind === 'import' ? '--specifier' : '--line';
44
+ const matcher = kind === 'import' ? options.specifier : options.line;
45
+ const hasPair = Boolean(options.file) && Boolean(matcher);
46
+ if (!options.creates && !hasPair) {
47
+ throw new InvalidArgumentError(`--remove${kind === 'registration' ? ' --kind registration' : ''} requires --creates, ` +
48
+ `or --file with ${matcherFlag}; --creates alone removes every declaration for that path.`, matcher && !options.file
49
+ ? '--file'
50
+ : options.file && !matcher
51
+ ? matcherFlag
52
+ : `--creates or --file + ${matcherFlag}`);
53
+ }
54
+ const wanted = matcher === undefined ? undefined : comparableMatcher(kind, matcher);
55
+ const views = stagedViews(kind, staged);
56
+ const candidates = views.filter((view) => (!options.file || view.file === options.file) &&
57
+ (wanted === undefined || comparableMatcher(kind, view.matcher) === wanted) &&
58
+ (!options.creates || view.creates === options.creates) &&
59
+ (options.owner === undefined || view.owner === options.owner));
60
+ if (candidates.length === 0) {
61
+ const noun = kind === 'import' ? 'staged forward-import' : 'staged registration';
62
+ const existing = views.length === 0
63
+ ? `This patch has no ${noun}s.`
64
+ : `This patch's ${noun}s:\n${views.map((view) => ` - ${dependencyLabel(kind, view)}`).join('\n')}`;
65
+ throw new InvalidArgumentError(`--remove matched no ${noun}. ${existing}`, '--remove');
66
+ }
67
+ if (candidates.length > 1 && !options.creates) {
68
+ const list = candidates.map((view) => ` - ${dependencyLabel(kind, view)}`).join('\n');
69
+ const noun = kind === 'import' ? 'staged forward-imports' : 'staged registrations';
70
+ throw new GeneralError(`--remove matches ${candidates.length} ${noun} on this patch; pass --creates to pick one:\n${list}`);
71
+ }
72
+ const single = candidates.length === 1 ? candidates[0] : undefined;
73
+ if (single !== undefined && !options.creates) {
74
+ info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
75
+ }
76
+ return candidates;
77
+ }
78
+ function comparableMatcher(kind, matcher) {
79
+ return kind === 'registration' ? normalizeRegistrationLine(matcher) : matcher;
80
+ }
@@ -10,6 +10,10 @@ import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
10
10
  import { info, intro, outro } from '../../utils/logger.js';
11
11
  import { addWaitLockOption, resolveWaitLockSeconds } from '../../utils/options.js';
12
12
  import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
13
+ import { stagedDependencyDelta } from './staged-dependency-batch.js';
14
+ import { applyMode, countStagedEntries, dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
15
+ import { runBatchAdd } from './staged-dependency-from.js';
16
+ import { selectRemovalEntries } from './staged-dependency-remove.js';
13
17
  import { validateStagedDependencyAdd } from './staged-dependency-validate.js';
14
18
  /** Joins the names of the missing flags for error attribution. */
15
19
  function missingFlagList(pairs) {
@@ -82,128 +86,27 @@ function requireRegistrationOptions(options) {
82
86
  dependency.reason = options.reason;
83
87
  return dependency;
84
88
  }
85
- /**
86
- * Resolves the `--remove` target for forward-imports:
87
- * `--file` + `--specifier` suffice when they identify at most one staged
88
- * entry. `--creates` is inferred from a unique match, an ambiguous match
89
- * refuses with the candidate list, and no match falls through to the
90
- * honest "no staged forward-import matched" summary.
91
- */
92
- function resolveImportRemovalTarget(options, staged) {
93
- if (!options.file || !options.specifier) {
94
- throw new InvalidArgumentError('--remove requires --file and --specifier; --creates is only needed to disambiguate when several staged entries share them.', missingFlagList([
95
- ['--file', options.file],
96
- ['--specifier', options.specifier],
97
- ]));
98
- }
99
- if (options.creates) {
100
- return requireForwardImportOptions(options);
101
- }
102
- const { file, specifier } = options;
103
- const candidates = (staged?.forwardImports ?? []).filter((entry) => entry.file === file &&
104
- entry.specifier === specifier &&
105
- (options.owner === undefined || entry.owner === options.owner));
106
- const single = candidates.length === 1 ? candidates[0] : undefined;
107
- if (single !== undefined) {
108
- info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
109
- return { ...single };
110
- }
111
- if (candidates.length > 1) {
112
- const list = candidates
113
- .map((entry) => ` - ${dependencyLabel('import', importView(entry))}`)
114
- .join('\n');
115
- throw new GeneralError(`--remove matches ${candidates.length} staged forward-imports on this patch; ` +
116
- `pass --creates to pick one:\n${list}`);
117
- }
118
- return { file, specifier, creates: '(no match)' };
119
- }
120
- /** Registration twin of {@link resolveImportRemovalTarget}, keyed on `--line`. */
121
- function resolveRegistrationRemovalTarget(options, staged) {
122
- if (!options.file || !options.line) {
123
- throw new InvalidArgumentError('--remove --kind registration requires --file and --line; --creates is only needed to disambiguate when several staged entries share them.', missingFlagList([
124
- ['--file', options.file],
125
- ['--line', options.line],
126
- ]));
127
- }
128
- if (options.creates) {
129
- return requireRegistrationOptions(options);
130
- }
131
- const { file, line } = options;
132
- const candidates = (staged?.registrations ?? []).filter((entry) => entry.file === file &&
133
- entry.line === line &&
134
- (options.owner === undefined || entry.owner === options.owner));
135
- const single = candidates.length === 1 ? candidates[0] : undefined;
136
- if (single !== undefined) {
137
- info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
138
- return { ...single };
139
- }
140
- if (candidates.length > 1) {
141
- const list = candidates
142
- .map((entry) => ` - ${dependencyLabel('registration', registrationView(entry))}`)
143
- .join('\n');
144
- throw new GeneralError(`--remove matches ${candidates.length} staged registrations on this patch; ` +
145
- `pass --creates to pick one:\n${list}`);
146
- }
147
- return { file, line, creates: '(no match)' };
148
- }
149
- function importView(dependency) {
150
- return { ...dependency, matcher: dependency.specifier };
151
- }
152
- function registrationView(dependency) {
153
- return { ...dependency, matcher: dependency.line };
154
- }
155
- function dependencyKey(view) {
156
- return [view.file, view.matcher, view.creates, view.owner ?? ''].join('\0');
157
- }
158
- function dependencyLabel(kind, view) {
159
- const owner = view.owner ? ` owner=${view.owner}` : '';
160
- const reason = view.reason ? ` reason="${view.reason}"` : '';
161
- if (kind === 'import') {
162
- return `${view.file} imports "${view.matcher}" from ${view.creates}${owner}${reason}`;
163
- }
164
- return `${view.file} registers "${view.matcher}" for ${view.creates}${owner}${reason}`;
165
- }
166
- function matchesTarget(view, target) {
167
- return (view.file === target.file &&
168
- view.matcher === target.matcher &&
169
- view.creates === target.creates &&
170
- (target.owner === undefined || view.owner === target.owner));
171
- }
172
- function applyMode(existing, mode, target, toView, addition) {
173
- if (mode === 'clear')
174
- return [];
175
- if (!target)
176
- return [...existing];
177
- if (mode === 'remove')
178
- return existing.filter((entry) => !matchesTarget(toView(entry), target));
179
- const seen = new Set(existing.map((entry) => dependencyKey(toView(entry))));
180
- if (seen.has(dependencyKey(target)) || addition === undefined)
181
- return [...existing];
182
- return [...existing, addition];
183
- }
184
89
  /**
185
90
  * Renders a one-line summary of a staged-dependency metadata change.
186
91
  */
187
- function describeStagedDependencyChange(beforeCount, afterCount, mode, kind, target) {
92
+ function describeStagedDependencyChange(beforeCount, afterCount, mode, kind, targets) {
188
93
  const noun = kind === 'import' ? 'staged forward-import' : 'staged registration';
189
94
  if (mode === 'clear') {
190
95
  return beforeCount === 0
191
96
  ? 'stagedDependencies was already empty — no change'
192
97
  : `cleared ${beforeCount} staged dependency declaration(s)`;
193
98
  }
194
- if (!target)
99
+ const label = targets.map((target) => dependencyLabel(kind, target)).join('; ');
100
+ if (targets.length === 0)
195
101
  return 'stagedDependencies unchanged';
196
102
  if (mode === 'add') {
197
103
  return afterCount === beforeCount
198
- ? `${noun} already present: ${dependencyLabel(kind, target)}`
199
- : `added ${noun}: ${dependencyLabel(kind, target)}`;
104
+ ? `${noun} already present: ${label}`
105
+ : `added ${noun}: ${label}`;
200
106
  }
201
107
  return afterCount === beforeCount
202
- ? `no ${noun} matched: ${dependencyLabel(kind, target)}`
203
- : `removed ${beforeCount - afterCount} ${noun} declaration(s): ${dependencyLabel(kind, target)}`;
204
- }
205
- function countStagedEntries(staged) {
206
- return (staged?.forwardImports?.length ?? 0) + (staged?.registrations?.length ?? 0);
108
+ ? `no ${noun} matched: ${label}`
109
+ : `removed ${beforeCount - afterCount} ${noun} declaration(s): ${label}`;
207
110
  }
208
111
  /**
209
112
  * Runs the metadata-only staged-dependency mutation command.
@@ -216,41 +119,44 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
216
119
  const isDryRun = options.dryRun === true;
217
120
  intro(isDryRun ? 'FireForge patch staged-dependency (dry run)' : 'FireForge patch staged-dependency');
218
121
  const mode = modeFromOptions(options);
122
+ if (options.from !== undefined) {
123
+ await runBatchAdd(projectRoot, identifier, mode, options);
124
+ return;
125
+ }
219
126
  const kind = kindFromOptions(options);
220
127
  // The patch queue loads before the declaration fields resolve so
221
128
  // `--remove` can infer `--creates` from the target patch's staged
222
129
  // entries.
223
130
  const { paths, manifest } = await requirePatchQueue(projectRoot);
224
131
  const targetPatch = requirePatchTarget(identifier, manifest.patches);
225
- const importDependency = mode === 'clear' || kind !== 'import'
226
- ? undefined
227
- : mode === 'add'
228
- ? requireForwardImportOptions(options)
229
- : resolveImportRemovalTarget(options, targetPatch.stagedDependencies);
230
- const registrationDependency = mode === 'clear' || kind !== 'registration'
231
- ? undefined
232
- : mode === 'add'
233
- ? requireRegistrationOptions(options)
234
- : resolveRegistrationRemovalTarget(options, targetPatch.stagedDependencies);
132
+ const importDependency = mode === 'add' && kind === 'import' ? requireForwardImportOptions(options) : undefined;
133
+ const registrationDependency = mode === 'add' && kind === 'registration' ? requireRegistrationOptions(options) : undefined;
235
134
  // Shape-check --add declarations against the loaded queue: a
236
135
  // patch-name-shaped --creates/--file is refused now instead of surfacing
237
136
  // later as an undischargeable staged-dependency-unused.
238
- if (mode === 'add') {
239
- const added = importDependency ?? registrationDependency;
240
- if (added !== undefined) {
241
- validateStagedDependencyAdd(added, manifest.patches);
242
- }
243
- }
244
- const target = importDependency !== undefined
245
- ? importView(importDependency)
246
- : registrationDependency !== undefined
247
- ? registrationView(registrationDependency)
248
- : undefined;
137
+ const added = importDependency ?? registrationDependency;
138
+ if (added !== undefined) {
139
+ validateStagedDependencyAdd(added, manifest.patches);
140
+ }
141
+ const targets = mode === 'remove'
142
+ ? selectRemovalEntries(kind, options, targetPatch.stagedDependencies)
143
+ : importDependency !== undefined
144
+ ? [importView(importDependency)]
145
+ : registrationDependency !== undefined
146
+ ? [registrationView(registrationDependency)]
147
+ : [];
148
+ const applyKind = (entries, own, toView, addition) => {
149
+ if (!own)
150
+ return [...entries];
151
+ if (mode !== 'remove')
152
+ return applyMode(entries, mode, targets[0], toView, addition);
153
+ return targets.reduce((remaining, target) => applyMode(remaining, 'remove', target, toView, undefined), [...entries]);
154
+ };
249
155
  const applyToStaged = (staged) => {
250
156
  if (mode === 'clear')
251
157
  return {};
252
- const forwardImports = applyMode(staged?.forwardImports ?? [], kind === 'import' ? mode : 'add', kind === 'import' ? target : undefined, importView, importDependency);
253
- const registrations = applyMode(staged?.registrations ?? [], kind === 'registration' ? mode : 'add', kind === 'registration' ? target : undefined, registrationView, registrationDependency);
158
+ const forwardImports = applyKind(staged?.forwardImports ?? [], kind === 'import', importView, importDependency);
159
+ const registrations = applyKind(staged?.registrations ?? [], kind === 'registration', registrationView, registrationDependency);
254
160
  return {
255
161
  ...(forwardImports.length > 0 ? { forwardImports } : {}),
256
162
  ...(registrations.length > 0 ? { registrations } : {}),
@@ -258,7 +164,7 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
258
164
  };
259
165
  const existing = targetPatch.stagedDependencies;
260
166
  const projected = applyToStaged(existing);
261
- const summary = describeStagedDependencyChange(countStagedEntries(existing), countStagedEntries(projected), mode, kind, target);
167
+ const summary = describeStagedDependencyChange(countStagedEntries(existing), countStagedEntries(projected), mode, kind, targets);
262
168
  if (isDryRun) {
263
169
  info(`[dry-run] ${targetPatch.filename}: ${summary}.`);
264
170
  outro('Dry run complete — no changes made');
@@ -278,15 +184,21 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
278
184
  }
279
185
  const before = result.before.stagedDependencies;
280
186
  const after = result.after.stagedDependencies;
281
- info(`${targetPatch.filename}: ${describeStagedDependencyChange(countStagedEntries(before), countStagedEntries(after), mode, kind, target)}.`);
187
+ info(`${targetPatch.filename}: ${describeStagedDependencyChange(countStagedEntries(before), countStagedEntries(after), mode, kind, targets)}.`);
188
+ if (mode === 'remove' && countStagedEntries(after) === countStagedEntries(before)) {
189
+ // The selection matched when the queue was read; a peer removed the
190
+ // entries before the locked write. Still a miss, so still a refusal.
191
+ throw new InvalidArgumentError(`${targetPatch.filename}: the selected staged declaration(s) were already gone when the manifest was written.`, '--remove');
192
+ }
282
193
  await appendHistoryBestEffort(paths.patches, {
283
194
  operation: 'patch-staged-dependency',
195
+ // Only the delta: the whole list on both sides grew the log
196
+ // quadratically with the list (see staged-dependency-batch.ts).
284
197
  args: {
285
198
  filename: targetPatch.filename,
286
199
  mode,
287
200
  kind,
288
- before: before ?? {},
289
- after: after ?? {},
201
+ ...stagedDependencyDelta(before, after),
290
202
  },
291
203
  ...(options.yes === true ? { yes: true } : {}),
292
204
  result: 'ok',
@@ -305,15 +217,18 @@ export function registerPatchStagedDependency(parent, context) {
305
217
  .command('staged-dependency <name>')
306
218
  .description('Edit PatchMetadata.stagedDependencies on a single patch (no .patch body rewrite).')
307
219
  .option('--add', 'Add a staged dependency declaration')
308
- .option('--remove', 'Remove matching staged dependency declaration(s)')
220
+ .option('--remove', 'Remove matching staged dependency declaration(s); a selection that matches nothing exits 8')
309
221
  .option('--clear', 'Drop the stagedDependencies field entirely')
310
222
  .option('--kind <kind>', 'Declaration shape: "import" (forward import, the default) or "registration" (jar.mn packaging line, customElements or actor registration)')
311
223
  .option('--file <path>', 'Declaring file path relative to engine/')
312
224
  .option('--specifier <specifier>', 'Exact import specifier as it appears in source (--kind import)')
313
- .option('--line <text>', 'Registration/packaging line as the patch adds it, compared whitespace-trimmed (--kind registration)')
314
- .option('--creates <path>', 'Later-created file path relative to engine/')
225
+ .option('--line <text>', 'Registration/packaging line as the patch adds it, compared whitespace-insensitively (--kind registration)')
226
+ .option('--creates <path>', 'Later-created file path relative to engine/ (with --remove and no --file: removes every declaration for that path)')
315
227
  .option('--owner <patch>', 'Exact later patch filename expected to create --creates')
316
- .option('--reason <text>', 'Human-readable rationale stored with the declaration')
228
+ .option('--reason <text>', 'Human-readable rationale stored with the declaration (with --from: the default for entries without one)')
229
+ .option('--from <json-file>', 'Add every declaration in a JSON file under one lock hold (--add only): a "lint --per-patch --report" ' +
230
+ "document (its findings' stagedDeclarations for this patch) or an array of " +
231
+ '{ file, specifier | line, creates, owner?, reason?, patch? } entries')
317
232
  .option('--dry-run', 'Show what would change without writing')
318
233
  .option('-y, --yes', 'Record scripted consent in the destructive-operation history log. This command never prompts; the flag exists for workflow uniformity with commands that do.');
319
234
  addWaitLockOption(command).action(withErrorHandling(async (name, options) => {
@@ -0,0 +1,20 @@
1
+ /** One changed engine file a registration line the patch adds names. */
2
+ export interface RegisteredChangedFile {
3
+ /** Engine-relative path of the named file. */
4
+ file: string;
5
+ /** Engine-relative path of the carrier whose added line names it. */
6
+ carrier: string;
7
+ }
8
+ /**
9
+ * Lists the changed (modified, deleted or untracked) engine files named by
10
+ * the registration lines the patch's owned carriers add relative to HEAD.
11
+ * Only added lines count: an upstream line naming an upstream file is not
12
+ * the patch's registration. A wildcard token is matched against the changed
13
+ * files under its carrier's directory, the only place such a token reaches
14
+ * without the build system.
15
+ *
16
+ * @param engineDir - Engine checkout
17
+ * @param ownedFiles - The patch's current filesAffected
18
+ * @returns Named changed files, first carrier wins, sorted by path
19
+ */
20
+ export declare function findRegisteredChangedFiles(engineDir: string, ownedFiles: readonly string[]): Promise<RegisteredChangedFile[]>;
@@ -0,0 +1,75 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * The registration arm of the scan-less re-export adjacency belt.
4
+ *
5
+ * A file the patch registers (a jar.mn, moz.build or test-manifest line the
6
+ * patch adds names it) belongs with the patch even when it lives in another
7
+ * directory, so an unmanaged one is adjacent in the sense that matters: the
8
+ * refreshed body would ship a registration for a file it leaves out. This
9
+ * module answers which changed engine files those lines name. The caller
10
+ * filters out owned, claimed and tool-managed paths.
11
+ *
12
+ * Split out of re-export-adjacent.ts to keep that module about the
13
+ * classification, not the carrier parsing.
14
+ */
15
+ import { dirname } from 'node:path';
16
+ import { getDiffForFilesAgainstHead } from '../core/git-diff.js';
17
+ import { getDirtyFiles, getModifiedFilesInDir, getUntrackedFilesInDir, } from '../core/git-status.js';
18
+ import { extractAddedLinesPerFile } from '../core/patch-lint-diff.js';
19
+ import { isRegistrationCarrier, resolveCarrierReferences, } from '../core/patch-lint-forward-registration-extended.js';
20
+ import { normalizePathSlashes } from '../utils/paths.js';
21
+ /**
22
+ * Lists the changed (modified, deleted or untracked) engine files named by
23
+ * the registration lines the patch's owned carriers add relative to HEAD.
24
+ * Only added lines count: an upstream line naming an upstream file is not
25
+ * the patch's registration. A wildcard token is matched against the changed
26
+ * files under its carrier's directory, the only place such a token reaches
27
+ * without the build system.
28
+ *
29
+ * @param engineDir - Engine checkout
30
+ * @param ownedFiles - The patch's current filesAffected
31
+ * @returns Named changed files, first carrier wins, sorted by path
32
+ */
33
+ export async function findRegisteredChangedFiles(engineDir, ownedFiles) {
34
+ const carriers = ownedFiles.filter(isRegistrationCarrier);
35
+ if (carriers.length === 0)
36
+ return [];
37
+ const diff = await getDiffForFilesAgainstHead(engineDir, carriers);
38
+ const exactToCarrier = new Map();
39
+ const wildcardsByCarrier = new Map();
40
+ for (const [carrier, lines] of extractAddedLinesPerFile(diff)) {
41
+ for (const ref of resolveCarrierReferences(carrier, lines.join('\n'))) {
42
+ if (ref.exact !== undefined) {
43
+ if (!exactToCarrier.has(ref.exact))
44
+ exactToCarrier.set(ref.exact, carrier);
45
+ }
46
+ else {
47
+ const list = wildcardsByCarrier.get(carrier) ?? [];
48
+ list.push(ref.matches);
49
+ wildcardsByCarrier.set(carrier, list);
50
+ }
51
+ }
52
+ }
53
+ const found = new Map();
54
+ if (exactToCarrier.size > 0) {
55
+ for (const file of await getDirtyFiles(engineDir, [...exactToCarrier.keys()])) {
56
+ const carrier = exactToCarrier.get(file);
57
+ if (carrier !== undefined)
58
+ found.set(file, carrier);
59
+ }
60
+ }
61
+ for (const [carrier, matchers] of wildcardsByCarrier) {
62
+ const scope = normalizePathSlashes(dirname(carrier));
63
+ const [modified, untracked] = await Promise.all([
64
+ getModifiedFilesInDir(engineDir, scope),
65
+ getUntrackedFilesInDir(engineDir, scope),
66
+ ]);
67
+ for (const file of [...modified, ...untracked]) {
68
+ if (!found.has(file) && matchers.some((matches) => matches(file)))
69
+ found.set(file, carrier);
70
+ }
71
+ }
72
+ return [...found.entries()]
73
+ .map(([file, carrier]) => ({ file, carrier }))
74
+ .sort((a, b) => a.file.localeCompare(b.file));
75
+ }