@hominis/fireforge 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (662) hide show
  1. package/CHANGELOG.md +409 -446
  2. package/dist/bin/fireforge.d.ts +1 -1
  3. package/dist/bin/fireforge.js +21 -15
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/cli-usage-error.d.ts +46 -0
  6. package/dist/src/cli-usage-error.js +81 -0
  7. package/dist/src/cli.d.ts +7 -2
  8. package/dist/src/cli.js +47 -47
  9. package/dist/src/commands/bootstrap-checks.js +2 -1
  10. package/dist/src/commands/bootstrap.js +3 -4
  11. package/dist/src/commands/build.js +27 -17
  12. package/dist/src/commands/config.js +9 -9
  13. package/dist/src/commands/destructive-decision.d.ts +19 -0
  14. package/dist/src/commands/destructive-decision.js +31 -0
  15. package/dist/src/commands/discard.js +5 -5
  16. package/dist/src/commands/doctor-check-core.d.ts +4 -10
  17. package/dist/src/commands/doctor-check-core.js +0 -8
  18. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  19. package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
  20. package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
  21. package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
  22. package/dist/src/commands/doctor-furnace-jar.js +1 -1
  23. package/dist/src/commands/doctor-furnace.js +22 -22
  24. package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
  25. package/dist/src/commands/doctor-orphaned-harness.js +14 -23
  26. package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
  27. package/dist/src/commands/doctor-patch-manifest.js +7 -6
  28. package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
  29. package/dist/src/commands/doctor-source-pin.d.ts +12 -12
  30. package/dist/src/commands/doctor-source-pin.js +14 -14
  31. package/dist/src/commands/doctor-working-tree.d.ts +3 -3
  32. package/dist/src/commands/doctor-working-tree.js +3 -3
  33. package/dist/src/commands/doctor.d.ts +3 -1
  34. package/dist/src/commands/doctor.js +15 -16
  35. package/dist/src/commands/download.js +50 -37
  36. package/dist/src/commands/export-all.js +29 -12
  37. package/dist/src/commands/export-flow.d.ts +5 -5
  38. package/dist/src/commands/export-flow.js +29 -59
  39. package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
  40. package/dist/src/commands/export-placement-conflicts.js +12 -12
  41. package/dist/src/commands/export-placement-gate.d.ts +2 -2
  42. package/dist/src/commands/export-placement-gate.js +7 -13
  43. package/dist/src/commands/export-placement-policy.d.ts +1 -1
  44. package/dist/src/commands/export-placement-policy.js +4 -6
  45. package/dist/src/commands/export-shared.d.ts +51 -32
  46. package/dist/src/commands/export-shared.js +17 -32
  47. package/dist/src/commands/export.js +14 -5
  48. package/dist/src/commands/furnace/apply.js +16 -16
  49. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  50. package/dist/src/commands/furnace/authoring-config.js +19 -0
  51. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
  52. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  53. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
  54. package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
  55. package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
  56. package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
  57. package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
  58. package/dist/src/commands/furnace/chrome-doc.js +18 -18
  59. package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
  60. package/dist/src/commands/furnace/create-browser-test.js +7 -12
  61. package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
  62. package/dist/src/commands/furnace/create-dry-run.js +6 -9
  63. package/dist/src/commands/furnace/create-features.d.ts +2 -2
  64. package/dist/src/commands/furnace/create-features.js +2 -2
  65. package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
  66. package/dist/src/commands/furnace/create-mochikit.js +7 -7
  67. package/dist/src/commands/furnace/create-templates.d.ts +31 -15
  68. package/dist/src/commands/furnace/create-templates.js +20 -19
  69. package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
  70. package/dist/src/commands/furnace/create-xpcshell.js +8 -8
  71. package/dist/src/commands/furnace/create.d.ts +1 -1
  72. package/dist/src/commands/furnace/create.js +35 -29
  73. package/dist/src/commands/furnace/deploy.js +15 -6
  74. package/dist/src/commands/furnace/diff.js +7 -7
  75. package/dist/src/commands/furnace/index.js +1 -1
  76. package/dist/src/commands/furnace/init.js +17 -16
  77. package/dist/src/commands/furnace/list.js +2 -2
  78. package/dist/src/commands/furnace/override.d.ts +1 -1
  79. package/dist/src/commands/furnace/override.js +43 -34
  80. package/dist/src/commands/furnace/preview.js +17 -17
  81. package/dist/src/commands/furnace/refresh.js +15 -7
  82. package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
  83. package/dist/src/commands/furnace/remove-mutations.js +19 -19
  84. package/dist/src/commands/furnace/remove-state.d.ts +1 -1
  85. package/dist/src/commands/furnace/remove-state.js +1 -1
  86. package/dist/src/commands/furnace/remove.js +4 -8
  87. package/dist/src/commands/furnace/rename-browser-test.js +10 -15
  88. package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
  89. package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
  90. package/dist/src/commands/furnace/rename.js +36 -36
  91. package/dist/src/commands/furnace/scan.js +3 -3
  92. package/dist/src/commands/furnace/status.js +19 -16
  93. package/dist/src/commands/furnace/sync.js +6 -6
  94. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  95. package/dist/src/commands/furnace/test-file-name.js +39 -0
  96. package/dist/src/commands/furnace/validate.js +11 -12
  97. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  98. package/dist/src/commands/furnace/validation-output.js +3 -8
  99. package/dist/src/commands/import.js +22 -29
  100. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  101. package/dist/src/commands/lint-per-patch.js +27 -12
  102. package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
  103. package/dist/src/commands/lint-per-run-checkjs.js +14 -15
  104. package/dist/src/commands/lint-report.d.ts +3 -3
  105. package/dist/src/commands/lint-report.js +4 -4
  106. package/dist/src/commands/lint.d.ts +5 -4
  107. package/dist/src/commands/lint.js +36 -36
  108. package/dist/src/commands/manifest.d.ts +4 -4
  109. package/dist/src/commands/manifest.js +1 -1
  110. package/dist/src/commands/package.js +4 -6
  111. package/dist/src/commands/patch/compact.d.ts +2 -2
  112. package/dist/src/commands/patch/compact.js +19 -20
  113. package/dist/src/commands/patch/delete.d.ts +1 -1
  114. package/dist/src/commands/patch/delete.js +23 -33
  115. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  116. package/dist/src/commands/patch/entry-projection.js +24 -0
  117. package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
  118. package/dist/src/commands/patch/lint-ignore.js +33 -44
  119. package/dist/src/commands/patch/move-files-create.d.ts +2 -2
  120. package/dist/src/commands/patch/move-files-create.js +29 -15
  121. package/dist/src/commands/patch/move-files-into.d.ts +2 -2
  122. package/dist/src/commands/patch/move-files-into.js +41 -37
  123. package/dist/src/commands/patch/move-files.js +5 -14
  124. package/dist/src/commands/patch/patch-context.d.ts +1 -1
  125. package/dist/src/commands/patch/rename.d.ts +4 -4
  126. package/dist/src/commands/patch/rename.js +35 -49
  127. package/dist/src/commands/patch/reorder.js +35 -48
  128. package/dist/src/commands/patch/split-plan.d.ts +7 -8
  129. package/dist/src/commands/patch/split-plan.js +10 -13
  130. package/dist/src/commands/patch/split.d.ts +2 -2
  131. package/dist/src/commands/patch/split.js +50 -48
  132. package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
  133. package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
  134. package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
  135. package/dist/src/commands/patch/staged-dependency.js +22 -28
  136. package/dist/src/commands/patch/tier.d.ts +2 -2
  137. package/dist/src/commands/patch/tier.js +20 -30
  138. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  139. package/dist/src/commands/patch-rename-map.js +36 -0
  140. package/dist/src/commands/pending-resolution.d.ts +15 -0
  141. package/dist/src/commands/pending-resolution.js +25 -0
  142. package/dist/src/commands/re-export-adjacent.d.ts +25 -3
  143. package/dist/src/commands/re-export-adjacent.js +40 -24
  144. package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
  145. package/dist/src/commands/re-export-bulk-scan.js +23 -27
  146. package/dist/src/commands/re-export-drift.d.ts +10 -10
  147. package/dist/src/commands/re-export-drift.js +33 -33
  148. package/dist/src/commands/re-export-files.d.ts +2 -3
  149. package/dist/src/commands/re-export-files.js +52 -44
  150. package/dist/src/commands/re-export-lint.d.ts +29 -30
  151. package/dist/src/commands/re-export-lint.js +36 -29
  152. package/dist/src/commands/re-export-options.d.ts +1 -1
  153. package/dist/src/commands/re-export-options.js +1 -1
  154. package/dist/src/commands/re-export-register.d.ts +1 -1
  155. package/dist/src/commands/re-export-register.js +1 -1
  156. package/dist/src/commands/re-export-scan.d.ts +1 -1
  157. package/dist/src/commands/re-export-scan.js +12 -9
  158. package/dist/src/commands/re-export-single.d.ts +23 -4
  159. package/dist/src/commands/re-export-single.js +39 -31
  160. package/dist/src/commands/re-export.js +35 -17
  161. package/dist/src/commands/rebase/abort.js +9 -14
  162. package/dist/src/commands/rebase/continue.js +20 -19
  163. package/dist/src/commands/rebase/index.d.ts +1 -1
  164. package/dist/src/commands/rebase/index.js +5 -5
  165. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  166. package/dist/src/commands/rebase/patch-loop.js +20 -24
  167. package/dist/src/commands/register.js +5 -5
  168. package/dist/src/commands/reset.js +1 -1
  169. package/dist/src/commands/resolve.d.ts +2 -2
  170. package/dist/src/commands/resolve.js +21 -13
  171. package/dist/src/commands/run.d.ts +0 -13
  172. package/dist/src/commands/run.js +38 -51
  173. package/dist/src/commands/setup-support.d.ts +16 -4
  174. package/dist/src/commands/setup-support.js +20 -20
  175. package/dist/src/commands/setup.js +4 -10
  176. package/dist/src/commands/source.js +9 -2
  177. package/dist/src/commands/status-check.d.ts +3 -3
  178. package/dist/src/commands/status-check.js +6 -6
  179. package/dist/src/commands/status-json.d.ts +14 -13
  180. package/dist/src/commands/status-json.js +9 -8
  181. package/dist/src/commands/status-output.d.ts +3 -3
  182. package/dist/src/commands/status-output.js +5 -5
  183. package/dist/src/commands/status-ownership.d.ts +3 -3
  184. package/dist/src/commands/status-ownership.js +3 -3
  185. package/dist/src/commands/status.js +25 -26
  186. package/dist/src/commands/test-build-phase.d.ts +3 -3
  187. package/dist/src/commands/test-build-phase.js +48 -24
  188. package/dist/src/commands/test-diagnose.d.ts +1 -1
  189. package/dist/src/commands/test-diagnose.js +20 -20
  190. package/dist/src/commands/test-modes.d.ts +4 -4
  191. package/dist/src/commands/test-modes.js +4 -5
  192. package/dist/src/commands/test-register.js +5 -3
  193. package/dist/src/commands/test-run.d.ts +11 -11
  194. package/dist/src/commands/test-run.js +40 -33
  195. package/dist/src/commands/test-stale-gate.d.ts +12 -12
  196. package/dist/src/commands/test-stale-gate.js +17 -17
  197. package/dist/src/commands/test-verdict.d.ts +19 -5
  198. package/dist/src/commands/test-verdict.js +26 -11
  199. package/dist/src/commands/test.d.ts +3 -3
  200. package/dist/src/commands/test.js +73 -36
  201. package/dist/src/commands/token-coverage.js +3 -3
  202. package/dist/src/commands/token-list.d.ts +26 -0
  203. package/dist/src/commands/token-list.js +153 -0
  204. package/dist/src/commands/token.js +26 -10
  205. package/dist/src/commands/tree.js +26 -21
  206. package/dist/src/commands/typecheck.d.ts +6 -6
  207. package/dist/src/commands/typecheck.js +16 -16
  208. package/dist/src/commands/verify.d.ts +3 -3
  209. package/dist/src/commands/verify.js +10 -10
  210. package/dist/src/commands/watch.js +11 -11
  211. package/dist/src/commands/wire.js +17 -16
  212. package/dist/src/core/ast-utils.d.ts +7 -7
  213. package/dist/src/core/ast-utils.js +8 -8
  214. package/dist/src/core/branding.d.ts +5 -12
  215. package/dist/src/core/branding.js +6 -5
  216. package/dist/src/core/browser-wire.d.ts +1 -1
  217. package/dist/src/core/browser-wire.js +10 -7
  218. package/dist/src/core/build-audit-platform.d.ts +32 -3
  219. package/dist/src/core/build-audit-platform.js +153 -13
  220. package/dist/src/core/build-audit-registration.d.ts +5 -5
  221. package/dist/src/core/build-audit-registration.js +10 -9
  222. package/dist/src/core/build-audit-resolve.d.ts +5 -5
  223. package/dist/src/core/build-audit-resolve.js +6 -6
  224. package/dist/src/core/build-audit-skip.d.ts +57 -0
  225. package/dist/src/core/build-audit-skip.js +112 -0
  226. package/dist/src/core/build-audit-transforms.d.ts +2 -2
  227. package/dist/src/core/build-audit-transforms.js +3 -3
  228. package/dist/src/core/build-audit.d.ts +21 -8
  229. package/dist/src/core/build-audit.js +142 -40
  230. package/dist/src/core/build-baseline-types.d.ts +19 -18
  231. package/dist/src/core/build-baseline-types.js +1 -1
  232. package/dist/src/core/build-baseline.d.ts +48 -31
  233. package/dist/src/core/build-baseline.js +20 -43
  234. package/dist/src/core/build-jar-escalation.d.ts +8 -8
  235. package/dist/src/core/build-jar-escalation.js +18 -17
  236. package/dist/src/core/build-overwrite-guard.d.ts +4 -4
  237. package/dist/src/core/build-overwrite-guard.js +14 -14
  238. package/dist/src/core/build-prepare.d.ts +4 -12
  239. package/dist/src/core/build-prepare.js +22 -26
  240. package/dist/src/core/config-mutate.js +4 -4
  241. package/dist/src/core/config-paths.d.ts +2 -6
  242. package/dist/src/core/config-paths.js +4 -2
  243. package/dist/src/core/config-state.d.ts +0 -6
  244. package/dist/src/core/config-state.js +3 -21
  245. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  246. package/dist/src/core/config-validate-build-audit.js +80 -0
  247. package/dist/src/core/config-validate-file-size.d.ts +1 -1
  248. package/dist/src/core/config-validate-file-size.js +3 -3
  249. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  250. package/dist/src/core/config-validate-patch-policy.js +3 -3
  251. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  252. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  253. package/dist/src/core/config-validate.js +22 -12
  254. package/dist/src/core/config.d.ts +12 -12
  255. package/dist/src/core/config.js +21 -25
  256. package/dist/src/core/coverage-extend.d.ts +16 -16
  257. package/dist/src/core/coverage-extend.js +20 -20
  258. package/dist/src/core/destructive.d.ts +14 -14
  259. package/dist/src/core/destructive.js +9 -9
  260. package/dist/src/core/diff-hunks.d.ts +2 -2
  261. package/dist/src/core/diff-hunks.js +7 -7
  262. package/dist/src/core/discard-baseline.d.ts +10 -10
  263. package/dist/src/core/discard-baseline.js +22 -23
  264. package/dist/src/core/display-state.d.ts +11 -11
  265. package/dist/src/core/display-state.js +12 -12
  266. package/dist/src/core/engine-changes.d.ts +2 -2
  267. package/dist/src/core/engine-changes.js +2 -2
  268. package/dist/src/core/engine-precondition.d.ts +5 -13
  269. package/dist/src/core/engine-precondition.js +5 -10
  270. package/dist/src/core/engine-session-lock.d.ts +18 -18
  271. package/dist/src/core/engine-session-lock.js +50 -54
  272. package/dist/src/core/export-moved-code-shape.d.ts +7 -7
  273. package/dist/src/core/export-moved-code-shape.js +10 -10
  274. package/dist/src/core/file-lock-owner.d.ts +103 -0
  275. package/dist/src/core/file-lock-owner.js +259 -0
  276. package/dist/src/core/file-lock.d.ts +14 -19
  277. package/dist/src/core/file-lock.js +90 -128
  278. package/dist/src/core/firefox-cache.d.ts +13 -1
  279. package/dist/src/core/firefox-cache.js +61 -36
  280. package/dist/src/core/firefox-download.d.ts +15 -0
  281. package/dist/src/core/firefox-download.js +38 -22
  282. package/dist/src/core/firefox-extract.d.ts +8 -7
  283. package/dist/src/core/firefox-extract.js +45 -27
  284. package/dist/src/core/firefox.d.ts +34 -36
  285. package/dist/src/core/firefox.js +13 -44
  286. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  287. package/dist/src/core/furnace-apply-dry-run.js +2 -8
  288. package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
  289. package/dist/src/core/furnace-apply-ftl.js +8 -8
  290. package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
  291. package/dist/src/core/furnace-apply-helpers.js +28 -39
  292. package/dist/src/core/furnace-apply-output.js +1 -1
  293. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
  294. package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
  295. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
  296. package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
  297. package/dist/src/core/furnace-apply.d.ts +4 -4
  298. package/dist/src/core/furnace-apply.js +50 -29
  299. package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
  300. package/dist/src/core/furnace-checksum-utils.js +5 -5
  301. package/dist/src/core/furnace-config-custom.d.ts +1 -1
  302. package/dist/src/core/furnace-config-custom.js +2 -2
  303. package/dist/src/core/furnace-config-order.js +1 -1
  304. package/dist/src/core/furnace-config-tokens.d.ts +3 -3
  305. package/dist/src/core/furnace-config-tokens.js +3 -3
  306. package/dist/src/core/furnace-config-validate.js +2 -2
  307. package/dist/src/core/furnace-config.d.ts +5 -5
  308. package/dist/src/core/furnace-config.js +40 -53
  309. package/dist/src/core/furnace-constants.d.ts +6 -6
  310. package/dist/src/core/furnace-constants.js +9 -8
  311. package/dist/src/core/furnace-css-fragments.d.ts +6 -6
  312. package/dist/src/core/furnace-css-fragments.js +11 -11
  313. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  314. package/dist/src/core/furnace-dir-entry.js +21 -0
  315. package/dist/src/core/furnace-jsconfig.d.ts +7 -7
  316. package/dist/src/core/furnace-jsconfig.js +22 -20
  317. package/dist/src/core/furnace-operation.d.ts +22 -19
  318. package/dist/src/core/furnace-operation.js +38 -34
  319. package/dist/src/core/furnace-precondition.d.ts +10 -10
  320. package/dist/src/core/furnace-precondition.js +8 -8
  321. package/dist/src/core/furnace-refresh.d.ts +18 -6
  322. package/dist/src/core/furnace-refresh.js +5 -8
  323. package/dist/src/core/furnace-registration-ast.d.ts +2 -3
  324. package/dist/src/core/furnace-registration-ast.js +9 -12
  325. package/dist/src/core/furnace-registration-remove.d.ts +4 -4
  326. package/dist/src/core/furnace-registration-remove.js +6 -6
  327. package/dist/src/core/furnace-registration-validate.d.ts +2 -2
  328. package/dist/src/core/furnace-registration-validate.js +2 -2
  329. package/dist/src/core/furnace-registration.d.ts +7 -6
  330. package/dist/src/core/furnace-registration.js +29 -36
  331. package/dist/src/core/furnace-rollback.d.ts +1 -1
  332. package/dist/src/core/furnace-rollback.js +5 -5
  333. package/dist/src/core/furnace-scanner.js +3 -6
  334. package/dist/src/core/furnace-stale-export.d.ts +17 -16
  335. package/dist/src/core/furnace-stale-export.js +16 -15
  336. package/dist/src/core/furnace-staleness.d.ts +2 -2
  337. package/dist/src/core/furnace-staleness.js +2 -2
  338. package/dist/src/core/furnace-state-persist.d.ts +12 -12
  339. package/dist/src/core/furnace-state-persist.js +10 -10
  340. package/dist/src/core/furnace-step-errors.d.ts +6 -6
  341. package/dist/src/core/furnace-step-errors.js +6 -6
  342. package/dist/src/core/furnace-validate-accessibility.js +14 -14
  343. package/dist/src/core/furnace-validate-compatibility.js +9 -9
  344. package/dist/src/core/furnace-validate-registration.d.ts +2 -2
  345. package/dist/src/core/furnace-validate-registration.js +18 -20
  346. package/dist/src/core/furnace-validate-structure.d.ts +1 -1
  347. package/dist/src/core/furnace-validate-structure.js +4 -4
  348. package/dist/src/core/furnace-validate.js +9 -9
  349. package/dist/src/core/furnace-version-drift.d.ts +5 -5
  350. package/dist/src/core/furnace-version-drift.js +5 -5
  351. package/dist/src/core/git-base.d.ts +6 -4
  352. package/dist/src/core/git-base.js +29 -7
  353. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  354. package/dist/src/core/git-diff-new-file.js +119 -0
  355. package/dist/src/core/git-diff.d.ts +13 -13
  356. package/dist/src/core/git-diff.js +121 -189
  357. package/dist/src/core/git-file-ops.d.ts +6 -13
  358. package/dist/src/core/git-file-ops.js +11 -35
  359. package/dist/src/core/git-readonly-index.d.ts +12 -14
  360. package/dist/src/core/git-readonly-index.js +12 -16
  361. package/dist/src/core/git-status.d.ts +9 -2
  362. package/dist/src/core/git-status.js +23 -11
  363. package/dist/src/core/git.d.ts +3 -9
  364. package/dist/src/core/git.js +28 -57
  365. package/dist/src/core/harness-orphans.d.ts +17 -17
  366. package/dist/src/core/harness-orphans.js +28 -27
  367. package/dist/src/core/history-log.d.ts +19 -0
  368. package/dist/src/core/history-log.js +29 -0
  369. package/dist/src/core/license-headers.d.ts +19 -18
  370. package/dist/src/core/license-headers.js +29 -28
  371. package/dist/src/core/mach-build-artifacts.d.ts +21 -21
  372. package/dist/src/core/mach-build-artifacts.js +23 -23
  373. package/dist/src/core/mach-error-hints.d.ts +5 -10
  374. package/dist/src/core/mach-error-hints.js +14 -14
  375. package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
  376. package/dist/src/core/mach-known-noise-filter.js +57 -56
  377. package/dist/src/core/mach-mozconfig.d.ts +6 -6
  378. package/dist/src/core/mach-mozconfig.js +17 -16
  379. package/dist/src/core/mach-python.d.ts +3 -0
  380. package/dist/src/core/mach-python.js +13 -7
  381. package/dist/src/core/mach-resource-shim.d.ts +24 -12
  382. package/dist/src/core/mach-resource-shim.js +124 -21
  383. package/dist/src/core/mach.d.ts +59 -73
  384. package/dist/src/core/mach.js +47 -115
  385. package/dist/src/core/marionette-port.d.ts +15 -30
  386. package/dist/src/core/marionette-port.js +46 -89
  387. package/dist/src/core/marionette-preflight.d.ts +6 -6
  388. package/dist/src/core/marionette-preflight.js +32 -50
  389. package/dist/src/core/markdown-table.d.ts +9 -9
  390. package/dist/src/core/markdown-table.js +14 -14
  391. package/dist/src/core/mochitest-server-port.d.ts +8 -8
  392. package/dist/src/core/mochitest-server-port.js +17 -17
  393. package/dist/src/core/module-resolution-preflight.d.ts +8 -8
  394. package/dist/src/core/module-resolution-preflight.js +11 -11
  395. package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
  396. package/dist/src/core/moz-manifest-helpers.js +7 -7
  397. package/dist/src/core/moz-manifest-register.d.ts +1 -1
  398. package/dist/src/core/moz-manifest-register.js +2 -2
  399. package/dist/src/core/moz-manifest-rules.js +46 -42
  400. package/dist/src/core/moz-manifest-tokenizers.js +1 -1
  401. package/dist/src/core/ownership-table.d.ts +5 -5
  402. package/dist/src/core/ownership-table.js +7 -7
  403. package/dist/src/core/parser-fallback.d.ts +3 -3
  404. package/dist/src/core/parser-fallback.js +3 -3
  405. package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
  406. package/dist/src/core/patch-apply-fuzz.js +13 -13
  407. package/dist/src/core/patch-apply.d.ts +13 -14
  408. package/dist/src/core/patch-apply.js +36 -42
  409. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  410. package/dist/src/core/patch-export-coverage.js +1 -30
  411. package/dist/src/core/patch-export-update.d.ts +21 -4
  412. package/dist/src/core/patch-export-update.js +7 -6
  413. package/dist/src/core/patch-export.d.ts +20 -30
  414. package/dist/src/core/patch-export.js +55 -77
  415. package/dist/src/core/patch-files.d.ts +0 -4
  416. package/dist/src/core/patch-files.js +0 -11
  417. package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
  418. package/dist/src/core/patch-identifier-suggest.js +4 -4
  419. package/dist/src/core/patch-lint-binary.d.ts +12 -18
  420. package/dist/src/core/patch-lint-cache.d.ts +18 -2
  421. package/dist/src/core/patch-lint-cache.js +16 -19
  422. package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
  423. package/dist/src/core/patch-lint-checkjs.js +78 -64
  424. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
  425. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
  426. package/dist/src/core/patch-lint-creators.d.ts +5 -9
  427. package/dist/src/core/patch-lint-creators.js +3 -3
  428. package/dist/src/core/patch-lint-cross.d.ts +27 -19
  429. package/dist/src/core/patch-lint-cross.js +67 -110
  430. package/dist/src/core/patch-lint-css.d.ts +1 -1
  431. package/dist/src/core/patch-lint-css.js +15 -11
  432. package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
  433. package/dist/src/core/patch-lint-diff-tag.js +5 -5
  434. package/dist/src/core/patch-lint-diff.d.ts +4 -4
  435. package/dist/src/core/patch-lint-diff.js +4 -4
  436. package/dist/src/core/patch-lint-file-size.d.ts +3 -3
  437. package/dist/src/core/patch-lint-file-size.js +6 -6
  438. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  439. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  440. package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
  441. package/dist/src/core/patch-lint-jsdoc.js +46 -46
  442. package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
  443. package/dist/src/core/patch-lint-module-registration.js +1 -1
  444. package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
  445. package/dist/src/core/patch-lint-mozbuild.js +10 -10
  446. package/dist/src/core/patch-lint-observer.d.ts +3 -3
  447. package/dist/src/core/patch-lint-observer.js +7 -7
  448. package/dist/src/core/patch-lint-ownership.d.ts +6 -6
  449. package/dist/src/core/patch-lint-ownership.js +6 -6
  450. package/dist/src/core/patch-lint-prettier.d.ts +6 -6
  451. package/dist/src/core/patch-lint-prettier.js +7 -7
  452. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  453. package/dist/src/core/patch-lint-queue-types.js +12 -0
  454. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  455. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  456. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
  457. package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
  458. package/dist/src/core/patch-lint.d.ts +41 -35
  459. package/dist/src/core/patch-lint.js +52 -49
  460. package/dist/src/core/patch-lock.d.ts +1 -1
  461. package/dist/src/core/patch-lock.js +11 -11
  462. package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
  463. package/dist/src/core/patch-manifest-consistency.js +16 -17
  464. package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
  465. package/dist/src/core/patch-manifest-files-affected.js +3 -3
  466. package/dist/src/core/patch-manifest-io.d.ts +14 -14
  467. package/dist/src/core/patch-manifest-io.js +35 -34
  468. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  469. package/dist/src/core/patch-manifest-query.js +4 -4
  470. package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
  471. package/dist/src/core/patch-manifest-resolve.js +7 -7
  472. package/dist/src/core/patch-manifest-validate.js +3 -3
  473. package/dist/src/core/patch-manifest.d.ts +2 -2
  474. package/dist/src/core/patch-manifest.js +2 -2
  475. package/dist/src/core/patch-parse.d.ts +32 -21
  476. package/dist/src/core/patch-parse.js +40 -15
  477. package/dist/src/core/patch-policy.js +15 -27
  478. package/dist/src/core/patch-registration-refs.d.ts +4 -4
  479. package/dist/src/core/patch-registration-refs.js +7 -7
  480. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  481. package/dist/src/core/patch-source-metadata.js +0 -4
  482. package/dist/src/core/patch-transform.d.ts +8 -16
  483. package/dist/src/core/patch-transform.js +13 -23
  484. package/dist/src/core/process-cpu-time.d.ts +1 -1
  485. package/dist/src/core/process-cpu-time.js +6 -6
  486. package/dist/src/core/rebase-session.d.ts +9 -15
  487. package/dist/src/core/rebase-session.js +13 -25
  488. package/dist/src/core/register-browser-content.js +3 -2
  489. package/dist/src/core/register-browser-test.js +2 -1
  490. package/dist/src/core/register-module.js +2 -1
  491. package/dist/src/core/register-result.d.ts +1 -1
  492. package/dist/src/core/register-result.js +1 -1
  493. package/dist/src/core/register-scaffold.d.ts +2 -2
  494. package/dist/src/core/register-scaffold.js +8 -7
  495. package/dist/src/core/register-shared-css.d.ts +3 -3
  496. package/dist/src/core/register-shared-css.js +6 -5
  497. package/dist/src/core/register-xpcshell-test.d.ts +2 -2
  498. package/dist/src/core/register-xpcshell-test.js +2 -2
  499. package/dist/src/core/run-log-redact.d.ts +38 -0
  500. package/dist/src/core/run-log-redact.js +69 -0
  501. package/dist/src/core/run-log.d.ts +21 -10
  502. package/dist/src/core/run-log.js +76 -27
  503. package/dist/src/core/shared-ftl.d.ts +2 -2
  504. package/dist/src/core/shared-ftl.js +6 -6
  505. package/dist/src/core/signal-critical.d.ts +2 -2
  506. package/dist/src/core/signal-critical.js +4 -6
  507. package/dist/src/core/smoke-patterns.d.ts +5 -6
  508. package/dist/src/core/smoke-patterns.js +15 -20
  509. package/dist/src/core/state-file.d.ts +15 -4
  510. package/dist/src/core/state-file.js +14 -1
  511. package/dist/src/core/status-binary.d.ts +8 -8
  512. package/dist/src/core/status-binary.js +12 -12
  513. package/dist/src/core/status-classify.d.ts +17 -17
  514. package/dist/src/core/status-classify.js +13 -12
  515. package/dist/src/core/test-changed-prefs.d.ts +12 -12
  516. package/dist/src/core/test-changed-prefs.js +40 -25
  517. package/dist/src/core/test-harness-crash.d.ts +39 -39
  518. package/dist/src/core/test-harness-crash.js +69 -69
  519. package/dist/src/core/test-harness-output.d.ts +7 -7
  520. package/dist/src/core/test-harness-output.js +7 -7
  521. package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
  522. package/dist/src/core/test-harness-verdict-notes.js +4 -4
  523. package/dist/src/core/test-path-scope.d.ts +8 -8
  524. package/dist/src/core/test-path-scope.js +11 -11
  525. package/dist/src/core/test-stale-check.d.ts +22 -23
  526. package/dist/src/core/test-stale-check.js +31 -30
  527. package/dist/src/core/test-stale-symlink.d.ts +1 -1
  528. package/dist/src/core/test-stale-symlink.js +1 -1
  529. package/dist/src/core/test-stall-triage.d.ts +9 -9
  530. package/dist/src/core/test-stall-triage.js +22 -22
  531. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  532. package/dist/src/core/test-xpcshell-retry.js +14 -11
  533. package/dist/src/core/token-category.d.ts +35 -2
  534. package/dist/src/core/token-category.js +67 -58
  535. package/dist/src/core/token-coverage.js +4 -5
  536. package/dist/src/core/token-dark-mode.d.ts +9 -9
  537. package/dist/src/core/token-dark-mode.js +13 -25
  538. package/dist/src/core/token-docs.d.ts +1 -1
  539. package/dist/src/core/token-inventory.d.ts +56 -0
  540. package/dist/src/core/token-inventory.js +109 -0
  541. package/dist/src/core/token-manager.d.ts +4 -4
  542. package/dist/src/core/token-manager.js +22 -22
  543. package/dist/src/core/token-scaffold.d.ts +4 -4
  544. package/dist/src/core/token-scaffold.js +4 -4
  545. package/dist/src/core/token-variant.d.ts +14 -14
  546. package/dist/src/core/token-variant.js +52 -53
  547. package/dist/src/core/toolchain-preflight.d.ts +15 -15
  548. package/dist/src/core/toolchain-preflight.js +23 -23
  549. package/dist/src/core/tree-cow.d.ts +3 -5
  550. package/dist/src/core/tree-cow.js +8 -8
  551. package/dist/src/core/tree-guard.d.ts +3 -3
  552. package/dist/src/core/tree-guard.js +23 -23
  553. package/dist/src/core/tree-store.d.ts +15 -15
  554. package/dist/src/core/tree-store.js +39 -38
  555. package/dist/src/core/typecheck-shim.d.ts +16 -15
  556. package/dist/src/core/typecheck-shim.js +26 -25
  557. package/dist/src/core/typecheck.d.ts +12 -12
  558. package/dist/src/core/typecheck.js +33 -33
  559. package/dist/src/core/wire-destroy.d.ts +2 -2
  560. package/dist/src/core/wire-destroy.js +5 -5
  561. package/dist/src/core/wire-dom-fragment.d.ts +3 -3
  562. package/dist/src/core/wire-dom-fragment.js +12 -23
  563. package/dist/src/core/wire-init.d.ts +2 -2
  564. package/dist/src/core/wire-init.js +7 -7
  565. package/dist/src/core/wire-subscript.d.ts +1 -1
  566. package/dist/src/core/wire-subscript.js +3 -3
  567. package/dist/src/core/wire-utils.d.ts +9 -9
  568. package/dist/src/core/wire-utils.js +16 -28
  569. package/dist/src/core/xpcshell-appdir.d.ts +20 -20
  570. package/dist/src/core/xpcshell-appdir.js +28 -30
  571. package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
  572. package/dist/src/core/xpcshell-profile-dir.js +7 -7
  573. package/dist/src/errors/base.d.ts +69 -16
  574. package/dist/src/errors/base.js +95 -26
  575. package/dist/src/errors/build.d.ts +6 -6
  576. package/dist/src/errors/build.js +26 -34
  577. package/dist/src/errors/codes.d.ts +10 -10
  578. package/dist/src/errors/codes.js +10 -10
  579. package/dist/src/errors/config.d.ts +0 -14
  580. package/dist/src/errors/config.js +13 -34
  581. package/dist/src/errors/download.d.ts +13 -0
  582. package/dist/src/errors/download.js +53 -24
  583. package/dist/src/errors/furnace.d.ts +2 -2
  584. package/dist/src/errors/furnace.js +8 -9
  585. package/dist/src/errors/git.d.ts +9 -9
  586. package/dist/src/errors/git.js +21 -31
  587. package/dist/src/errors/patch.d.ts +3 -3
  588. package/dist/src/errors/patch.js +11 -13
  589. package/dist/src/errors/rebase.d.ts +1 -1
  590. package/dist/src/errors/rebase.js +8 -8
  591. package/dist/src/errors/run.d.ts +1 -1
  592. package/dist/src/errors/run.js +1 -1
  593. package/dist/src/index.d.ts +4 -4
  594. package/dist/src/index.js +4 -4
  595. package/dist/src/types/commands/options.d.ts +155 -200
  596. package/dist/src/types/commands/patches.d.ts +19 -19
  597. package/dist/src/types/commands/project.d.ts +3 -3
  598. package/dist/src/types/config.d.ts +52 -19
  599. package/dist/src/types/furnace.d.ts +17 -17
  600. package/dist/src/types/index.d.ts +0 -1
  601. package/dist/src/types/json.d.ts +3 -3
  602. package/dist/src/types/json.js +2 -2
  603. package/dist/src/types/typecheck.d.ts +3 -3
  604. package/dist/src/utils/assert.d.ts +4 -16
  605. package/dist/src/utils/assert.js +7 -24
  606. package/dist/src/utils/build-info.d.ts +6 -6
  607. package/dist/src/utils/build-info.js +6 -6
  608. package/dist/src/utils/child-env.d.ts +7 -6
  609. package/dist/src/utils/child-env.js +5 -5
  610. package/dist/src/utils/concurrency.d.ts +2 -2
  611. package/dist/src/utils/concurrency.js +2 -2
  612. package/dist/src/utils/elapsed.js +10 -1
  613. package/dist/src/utils/errors.d.ts +8 -8
  614. package/dist/src/utils/errors.js +8 -8
  615. package/dist/src/utils/fs.d.ts +1 -1
  616. package/dist/src/utils/fs.js +15 -20
  617. package/dist/src/utils/hash.d.ts +12 -0
  618. package/dist/src/utils/hash.js +16 -0
  619. package/dist/src/utils/line-dispatch.d.ts +15 -0
  620. package/dist/src/utils/line-dispatch.js +48 -0
  621. package/dist/src/utils/logger.d.ts +4 -4
  622. package/dist/src/utils/logger.js +11 -11
  623. package/dist/src/utils/machine-output.js +2 -2
  624. package/dist/src/utils/options.d.ts +14 -20
  625. package/dist/src/utils/options.js +26 -27
  626. package/dist/src/utils/package-root.js +5 -14
  627. package/dist/src/utils/paths.d.ts +4 -4
  628. package/dist/src/utils/paths.js +4 -4
  629. package/dist/src/utils/platform.d.ts +0 -4
  630. package/dist/src/utils/process-group.d.ts +10 -9
  631. package/dist/src/utils/process-group.js +37 -36
  632. package/dist/src/utils/process.d.ts +70 -55
  633. package/dist/src/utils/process.js +129 -179
  634. package/dist/src/utils/ps-duration.d.ts +4 -4
  635. package/dist/src/utils/ps-duration.js +9 -9
  636. package/dist/src/utils/regex.d.ts +4 -4
  637. package/dist/src/utils/regex.js +7 -7
  638. package/dist/src/utils/sleep.d.ts +26 -0
  639. package/dist/src/utils/sleep.js +31 -0
  640. package/dist/src/utils/stdio-drain.d.ts +7 -7
  641. package/dist/src/utils/stdio-drain.js +8 -8
  642. package/dist/src/utils/validation.d.ts +12 -49
  643. package/dist/src/utils/validation.js +26 -36
  644. package/docs/README.md +2 -2
  645. package/docs/configuration.md +163 -69
  646. package/docs/exit-codes.md +66 -49
  647. package/docs/furnace.md +20 -19
  648. package/docs/lifecycle-invariants.md +414 -247
  649. package/docs/machine-output.md +58 -34
  650. package/docs/patch-workflow.md +48 -44
  651. package/docs/run-logs.md +72 -28
  652. package/docs/testing.md +105 -98
  653. package/docs/verification-trees.md +23 -22
  654. package/package.json +7 -6
  655. package/dist/src/commands/rebase.d.ts +0 -4
  656. package/dist/src/commands/rebase.js +0 -5
  657. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  658. package/dist/src/core/patch-artifact-normalize.js +0 -24
  659. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  660. package/dist/src/core/patch-lint-reexports.js +0 -8
  661. package/dist/src/core/wire-targets.d.ts +0 -7
  662. package/dist/src/core/wire-targets.js +0 -8
@@ -9,12 +9,13 @@ import { assertBuildArtifacts } from '../core/mach-build-artifacts.js';
9
9
  import { assertMarionettePortAvailable, ensureLaunchableBrowserNotRunning, ensureMarionettePortAvailable, extractForwardedMarionettePort, forwardedMachArgsIncludeMarionetteClient, shouldAutoForwardMarionettePortToMach, } from '../core/marionette-port.js';
10
10
  import { formatMarionettePreflightLine, reportMarionettePreflight, runMarionettePreflight, } from '../core/marionette-preflight.js';
11
11
  import { ensureMochitestServerPortAvailable } from '../core/mochitest-server-port.js';
12
- import { closeActiveRunLog, openRunLog, setActiveRunLog } from '../core/run-log.js';
12
+ import { closeActiveRunLog, openRunLog, setActiveRunLog, writeToActiveRunLog, } from '../core/run-log.js';
13
13
  import { createPostRebuildFailureContext } from '../core/test-harness-output.js';
14
14
  import { analyzeTestPathScopes, formatScopeNotice, } from '../core/test-path-scope.js';
15
15
  import { assertObjdirMatchesTreeMarker } from '../core/tree-store.js';
16
- import { GeneralError } from '../errors/base.js';
16
+ import { FireForgeError, GeneralError, PreflightRefusalError } from '../errors/base.js';
17
17
  import { BuildError } from '../errors/build.js';
18
+ import { toError } from '../utils/errors.js';
18
19
  import { pathExists } from '../utils/fs.js';
19
20
  import { info, intro, notice, outro, verbose } from '../utils/logger.js';
20
21
  import { stripEnginePrefix } from '../utils/paths.js';
@@ -41,7 +42,7 @@ async function assertTestPathsExist(engineDir, testPaths) {
41
42
  * auto-routes to the suite-specific command (`mach xpcshell-test` /
42
43
  * `mach mochitest`), which degrades a broken host resource monitor to a
43
44
  * warning instead of crashing generic `mach test` at startup. Mixed runs are
44
- * rejected before this point; a path-less "run all" or an explicit
45
+ * rejected before this point. A path-less "run all" or an explicit
45
46
  * `--generic-mach-test` opt-out stays on the generic command.
46
47
  */
47
48
  function resolveTestSuite(classification, forceGeneric) {
@@ -101,14 +102,14 @@ function logTestSelection(scopes) {
101
102
  }
102
103
  /**
103
104
  * Runs the `--doctor` marionette handshake probe. With no test paths the
104
- * probe is the entire command (returns `'stop'` after reporting); with
105
- * paths it gates the mach invocation — a FAIL throws before mach runs.
105
+ * probe is the entire command (returns `'stop'` after reporting). With
106
+ * paths it gates the mach invocation, where a FAIL throws before mach runs.
106
107
  */
107
108
  async function runDoctorPreflight(args) {
108
109
  const { engineDir, effectivePort, hasTestPaths, objDir, binaryName, launchablePath } = args;
109
110
  // Non-TTY captures need the banner even if clack's renderer defers output
110
- // in pipe mode; TTY users need the clack framing. Gated rather than
111
- // written twice — the unconditional pair printed the same line twice on a
111
+ // in pipe mode. TTY users need the clack framing. Gated rather than
112
+ // written twice: the unconditional pair printed the same line twice on a
112
113
  // terminal.
113
114
  if (process.stdout.isTTY) {
114
115
  info('Running marionette preflight...');
@@ -124,7 +125,7 @@ async function runDoctorPreflight(args) {
124
125
  // can drop the summary under non-TTY capture.
125
126
  //
126
127
  // Gated on non-TTY: unconditional, it stacks with the two clack renderings
127
- // below and the same line appears THREE times on a terminal. Captured
128
+ // below and the same line appears three times on a terminal. Captured
128
129
  // streams are exactly where this branch still fires.
129
130
  const directLine = formatMarionettePreflightLine(preflight);
130
131
  if (!process.stdout.isTTY) {
@@ -138,7 +139,7 @@ async function runDoctorPreflight(args) {
138
139
  throw new GeneralError('Marionette preflight reported FAIL — see output above.');
139
140
  }
140
141
  // Doctor-only runs end here, so they carry their own verdict line
141
- // (reason=preflight on failure); with test paths the verdict comes
142
+ // (reason=preflight on failure). With test paths the verdict comes
142
143
  // from the actual harness run downstream.
143
144
  emitPassVerdict();
144
145
  outro('Test completed');
@@ -160,12 +161,12 @@ async function runDoctorPreflight(args) {
160
161
  function appendMarionetteForwardingArgs(extraArgs, options, forwardedPort, xpcshellOnly = false) {
161
162
  // Auto-forward the Marionette port to mach when `--marionette-port` is set.
162
163
  // `--setpref=marionette.port=<n>` configures where the browser listener
163
- // binds; `--marionette=127.0.0.1:<n>` tells the mochitest harness client to
164
+ // binds. `--marionette=127.0.0.1:<n>` tells the mochitest harness client to
164
165
  // connect there (default client is 127.0.0.1:2828). xpcshell ignores both
165
166
  // for browser Marionette.
166
167
  //
167
168
  // Skip setpref forwarding when the operator already supplied an equivalent
168
- // arg via `--mach-arg` — duplicates would confuse without changing
169
+ // arg via `--mach-arg`: duplicates would confuse without changing
169
170
  // semantics. Skip when mach args explicitly request `--flavor=xpcshell` (or
170
171
  // `xpcshell-tests`): the preflight still honours `--marionette-port`, but
171
172
  // mach does not use the marionette.port pref on that harness. Any other arg
@@ -177,7 +178,7 @@ function appendMarionetteForwardingArgs(extraArgs, options, forwardedPort, xpcsh
177
178
  if (options.marionettePort === undefined)
178
179
  return;
179
180
  if (xpcshellOnly) {
180
- // Manifest classification says every requested path is xpcshell —
181
+ // Manifest classification says every requested path is xpcshell.
181
182
  // xpcshell ignores the browser Marionette path entirely, and forwarding
182
183
  // the mochitest client flags here makes mach reject the dispatch.
183
184
  info(`--marionette-port=${options.marionettePort} applied to the preflight probe only: the requested paths are xpcshell-only, and xpcshell ignores the browser Marionette port. Not forwarding --setpref=marionette.port or --marionette to mach.`);
@@ -271,9 +272,9 @@ const TEST_BUILD_PREFLIGHT = {
271
272
  *
272
273
  * Owns the run's exactly-one-`FIREFORGE-VERDICT:`-line guarantee: the sink
273
274
  * is re-armed at entry, and any failure that reaches this boundary without
274
- * an inner writer having emitted — the preflight ladder (missing engine or
275
- * build, config errors, stale-build and port gates, missing paths), and a
276
- * harness process that failed to start — emits `FAIL reason=preflight`,
275
+ * an inner writer having emitted (the preflight ladder: missing engine or
276
+ * build, config errors, stale-build and port gates, missing paths, and a
277
+ * harness process that failed to start) emits `FAIL reason=preflight`,
277
278
  * since no harness classification exists for such a run. Writers closer to
278
279
  * the harness (doctor, canary, single, sharded, the engine-generation
279
280
  * guard) emit first and win.
@@ -284,7 +285,7 @@ const TEST_BUILD_PREFLIGHT = {
284
285
  export async function testCommand(projectRoot, testPaths, options = {}) {
285
286
  intro('FireForge Test');
286
287
  resetVerdictEmission();
287
- // Opened before ANY work so a preflight refusal is logged too — those are
288
+ // Opened before any work so a preflight refusal is logged too. Those are
288
289
  // exactly the runs whose only output a `tail` throws away. Closed in
289
290
  // `finally`, after the verdict line has already read the path.
290
291
  setActiveRunLog(await openRunLog(projectRoot, 'test'));
@@ -292,19 +293,55 @@ export async function testCommand(projectRoot, testPaths, options = {}) {
292
293
  await runTestCommandBody(projectRoot, testPaths, options);
293
294
  }
294
295
  catch (error) {
295
- if (!verdictEmitted())
296
- emitFailVerdict('preflight');
296
+ if (!verdictEmitted()) {
297
+ renderPreflightRefusal(error);
298
+ emitFailVerdict('preflight', refusalNote(error));
299
+ }
297
300
  throw error;
298
301
  }
299
302
  finally {
300
303
  await closeActiveRunLog();
301
304
  }
302
305
  }
306
+ /** The refusal class a preflight gate named, when it named one. */
307
+ function refusalNote(error) {
308
+ return error instanceof PreflightRefusalError ? error.note : undefined;
309
+ }
310
+ /**
311
+ * Puts a preflight refusal's own text on the operator's channel before the
312
+ * verdict line, and into the run log.
313
+ *
314
+ * Both halves matter, and neither happened before:
315
+ *
316
+ * - `withErrorHandling` renders `error.userMessage` back in `cli.ts`, but
317
+ * by then `emitFailVerdict` has called `setStdoutSealed(true)`, the seal
318
+ * that keeps the verdict the last stdout write, so `logError` routes to
319
+ * stderr. A run captured with `> file` therefore kept the verdict and
320
+ * dropped the reason.
321
+ * - That same rendering happens after this function's caller returns, and
322
+ * the `finally` below has already closed the run log. So the artifact the
323
+ * verdict's own `log=` key points at did not contain the refusal either,
324
+ * which is what left `.fireforge/logs/test-*.log` holding only the
325
+ * pre-test build.
326
+ *
327
+ * Writing here, before the seal, fixes both without trading away the
328
+ * contract: the refusal lands on stdout and in the log, and the verdict
329
+ * line still comes last.
330
+ */
331
+ function renderPreflightRefusal(error) {
332
+ const text = error instanceof FireForgeError ? error.userMessage : toError(error).message;
333
+ const block = `Preflight refused:\n${text}\n`;
334
+ // Raw stdout rather than the clack logger: this must land on the captured
335
+ // stream verbatim, and clack's renderer can drop output under non-TTY
336
+ // capture, the same reason the verdict line is written this way.
337
+ process.stdout.write(block);
338
+ writeToActiveRunLog(block);
339
+ }
303
340
  /**
304
341
  * Verifies `engine/` did not change under the run before any PASS verdict
305
- * may print. On failure the run's verdict is `FAIL reason=inconclusive` —
306
- * the harness result exists but cannot be trusted (`preflight` would
307
- * misdescribe a run whose harness already executed) — emitted here so the
342
+ * may print. On failure the run's verdict is `FAIL reason=inconclusive`,
343
+ * because the harness result exists but cannot be trusted (`preflight` would
344
+ * misdescribe a run whose harness already executed). It is emitted here so the
308
345
  * guard's throw can never leave a stale or missing verdict line behind.
309
346
  */
310
347
  async function verifyEngineGenerationOrEmitInconclusive(engineDir, before) {
@@ -324,7 +361,7 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
324
361
  const buildCheck = await hasBuildArtifacts(paths.engine);
325
362
  assertBuildArtifacts(paths.engine, buildCheck, TEST_BUILD_PREFLIGHT);
326
363
  // Inside a verification tree, only the objdir the marker records was
327
- // proven rewritten-and-reconfigured to the tree; refuse any other.
364
+ // proven rewritten-and-reconfigured to the tree. Refuse any other.
328
365
  await assertObjdirMatchesTreeMarker(projectRoot, buildCheck.objDir);
329
366
  // Load the project config once so both the build and the port
330
367
  // probe have access to `binaryName` (the port probe uses it to
@@ -332,11 +369,11 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
332
369
  const projectConfig = await loadConfig(projectRoot);
333
370
  const canaryPath = resolveCanaryPath(options, projectConfig);
334
371
  assertTestModeCombinations(testPaths, options, canaryPath);
335
- // `hasBuildArtifacts` only confirms `obj-*/dist/` exists; a partial build
372
+ // `hasBuildArtifacts` only confirms `obj-*/dist/` exists. A partial build
336
373
  // (linker failed, packaging step interrupted) can satisfy that check
337
374
  // without ever writing the launchable binary the marionette preflight
338
375
  // needs to spawn. `fireforge run` already uses `hasRunnableBundle` to fail
339
- // fast with a precise message; mirroring it here makes `test --doctor`
376
+ // fast with a precise message. Mirroring it here makes `test --doctor`
340
377
  // against an incomplete build surface the missing-bundle path instead of a
341
378
  // cryptic `Browser process exited during spawn (exit code 1, signal none).
342
379
  // stderr tail: (empty)`.
@@ -345,8 +382,8 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
345
382
  // Normalized engine-relative request paths, hoisted above the build/stale
346
383
  // gate: the pre-test build records them as the packaging-coverage claim,
347
384
  // and the --allow-stale-build path checks the request against the
348
- // recorded coverage. (Existence is still asserted later, after the gate —
349
- // stale/coverage refusals keep precedence over missing-path errors.)
385
+ // recorded coverage. (Existence is still asserted later, after the gate,
386
+ // so stale/coverage refusals keep precedence over missing-path errors.)
350
387
  const requestedPaths = canaryPath !== undefined ? [canaryPath] : testPaths;
351
388
  const normalizedPaths = requestedPaths.map((p) => stripEnginePrefix(p).trim());
352
389
  const { classification, xpcshellOnly } = await classifyBeforeDispatch(paths.engine, normalizedPaths, { allowMixed: options.buildOnly === true });
@@ -392,26 +429,26 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
392
429
  extraArgs.push('--auto');
393
430
  }
394
431
  if (canaryPath !== undefined) {
395
- extraArgs.push(`--timeout=${String(canaryTimeoutSeconds(projectConfig))}`);
432
+ extraArgs.push(`--timeout=${canaryTimeoutSeconds(projectConfig)}`);
396
433
  }
397
434
  // --mach-arg is a verbatim passthrough for upstream mach/xpcshell/mochitest
398
435
  // flags FireForge does not model directly (see the xpcshell appdir hint
399
- // above for why). Appended AFTER --headless so mach sees
436
+ // above for why). Appended after --headless so mach sees
400
437
  // the FireForge-managed flags first and the escape-valve ones last, which
401
438
  // keeps the override precedence predictable.
402
439
  if (forwardedMachArgs.length > 0) {
403
440
  extraArgs.push(...forwardedMachArgs);
404
441
  }
405
442
  appendMarionetteForwardingArgs(extraArgs, options, forwardedPort, xpcshellOnly);
406
- // Directory arguments mean EXACTLY that directory: mozbuild's test
443
+ // Directory arguments mean exactly that directory: mozbuild's test
407
444
  // resolver matches paths by string prefix, so a bare directory arg
408
- // silently sweeps in prefix-named siblings — `…/test/hominis` also running
409
- // `…/test/hominis-tiles`, with no indication the scope widened. Each
445
+ // silently sweeps in prefix-named siblings, with `…/test/hominis` also
446
+ // running `…/test/hominis-tiles`, with no indication the scope widened. Each
410
447
  // directory argument therefore dispatches as its enumerated explicit
411
- // test-file list, which cannot prefix-match a sibling; a trailing-`/`
448
+ // test-file list, which cannot prefix-match a sibling. A trailing-`/`
412
449
  // normalization does not work, as mach still sweeps the sibling in. Any
413
450
  // prefix-siblings are echoed so the narrowed scope is visible.
414
- // Classification above intentionally used the raw argument forms; only the
451
+ // Classification above intentionally used the raw argument forms. Only the
415
452
  // mach dispatch needs the exact-match shape.
416
453
  const scopes = await analyzeTestPathScopes(paths.engine, normalizedPaths);
417
454
  const dispatchGroups = scopes.map((scope) => ({
@@ -445,10 +482,10 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
445
482
  : undefined;
446
483
  // Multi-argument requests shard into sequential harness runs by default:
447
484
  // one shared mochitest profile across files bleeds pref/media-query state
448
- // into later files. Sharding is per path ARGUMENT — a directory argument
485
+ // into later files. Sharding is per path argument: a directory argument
449
486
  // keeps its enumerated files together in one invocation, preserving the
450
487
  // one-browser-instance semantics of a directory run. `--no-shard` restores
451
- // the combined invocation. The default must not be SILENT: a cross-file
488
+ // the combined invocation. The default must not be silent: a cross-file
452
489
  // pollution repro otherwise "passes" because the comparison run was
453
490
  // sharded without saying so, misattributing a suite-context bug upstream.
454
491
  // Hence the one-line notice stating what sharding does and does not
@@ -463,7 +500,7 @@ async function runTestCommandBody(projectRoot, testPaths, options = {}) {
463
500
  summary = await runShardedTests(runCtx, dispatchGroups, (outcome, label) => diagnoseShardOutcome(outcome, label, projectConfig.binaryName, postRebuildContext));
464
501
  }
465
502
  finally {
466
- // Runs BEFORE the aggregate verdict below: a mutated engine/ emits
503
+ // Runs before the aggregate verdict below: a mutated engine/ emits
467
504
  // `FAIL reason=inconclusive` and throws, so an invalidated run can
468
505
  // never print `PASS shards=N/N` first. (A throw here masks an
469
506
  // in-flight shard error, as the plain assert always did.)
@@ -34,11 +34,11 @@ export async function tokenCoverageCommand(projectRoot) {
34
34
  .map((f) => f.file);
35
35
  // Also scan CSS files deployed by Furnace custom components. Deployed
36
36
  // files can be committed (and therefore absent from `git status`) while
37
- // still being the primary surface where token adoption matters; looking
37
+ // still being the primary surface where token adoption matters. Looking
38
38
  // only at modified files silently undercounts projects where Furnace
39
39
  // writes many component-CSS files into the engine.
40
40
  const furnaceCssFiles = await collectFurnaceCustomCssFiles(projectRoot, paths.engine, tokensCssPath);
41
- // De-dupe so a file that is both a custom deploy target AND modified is
41
+ // De-dupe so a file that is both a custom deploy target and modified is
42
42
  // scanned exactly once.
43
43
  const cssFiles = [...new Set([...statusCssFiles, ...furnaceCssFiles])];
44
44
  const tokenSourceFiles = [...new Set(statusTokenCssFiles)];
@@ -129,7 +129,7 @@ async function validateTokenSourceFiles(engineDir, tokenSourceFiles, tokenPrefix
129
129
  /**
130
130
  * Returns engine-relative `.css` paths deployed by every Furnace custom
131
131
  * component registered in `furnace.json`. Only files that actually exist
132
- * on disk are included — a component whose deploy target is missing (e.g.
132
+ * on disk are included. A component whose deploy target is missing (e.g.
133
133
  * `furnace apply` has not run yet) is skipped silently so a fresh
134
134
  * `furnace init` followed immediately by `token coverage` does not error.
135
135
  *
@@ -0,0 +1,26 @@
1
+ /** Options accepted by {@link tokenListCommand}. */
2
+ export interface TokenListOptions {
3
+ /** Restrict the report to one category. */
4
+ category?: string;
5
+ /** Emit the machine-readable envelope instead of the human report. */
6
+ json?: boolean;
7
+ }
8
+ /**
9
+ * Lists the categories declared in the tokens CSS with their token names,
10
+ * in file order.
11
+ *
12
+ * @param projectRoot - Root directory of the project
13
+ * @param options - Filter and output-mode options
14
+ */
15
+ export declare function tokenListCommand(projectRoot: string, options?: TokenListOptions): Promise<void>;
16
+ /**
17
+ * Reports one token: the category that owns it and the value it takes in
18
+ * every block that declares it.
19
+ *
20
+ * @param projectRoot - Root directory of the project
21
+ * @param tokenName - Custom-property name, with or without the leading `--`
22
+ * @param options - Output-mode options
23
+ */
24
+ export declare function tokenShowCommand(projectRoot: string, tokenName: string, options?: {
25
+ json?: boolean;
26
+ }): Promise<void>;
@@ -0,0 +1,153 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * `token list` and `token show`: the read half of design-token management.
4
+ *
5
+ * `token add` requires `--category` and refuses an unknown one, but nothing
6
+ * reported the categories a project has, so naming one meant hand-parsing a
7
+ * neighbouring `= Category =` banner out of the tokens CSS. Both commands
8
+ * read through `token-inventory.ts`, which is built on the same banner and
9
+ * `:root`-bounds primitives `token add` and `token coverage` use, because
10
+ * a second tokens-CSS parser would let the report and the writer disagree about
11
+ * which section a token lives in.
12
+ *
13
+ * Helper module: no registrar, called from `token.ts`.
14
+ */
15
+ import { join } from 'node:path';
16
+ import { getProjectPaths, loadConfig } from '../core/config.js';
17
+ import { collectTokenBlockValues, collectTokenInventory, } from '../core/token-inventory.js';
18
+ import { getTokensCssPath } from '../core/token-manager.js';
19
+ import { GeneralError } from '../errors/base.js';
20
+ import { toError } from '../utils/errors.js';
21
+ import { pathExists, readText } from '../utils/fs.js';
22
+ import { info, intro, outro, setMachineOutputMode, setStdoutSealed } from '../utils/logger.js';
23
+ import { emitMachineError, MACHINE_OUTPUT_SCHEMA_VERSION } from '../utils/machine-output.js';
24
+ /** Reads the project's tokens CSS as lines, refusing when it is absent. */
25
+ async function readTokensCssLines(projectRoot) {
26
+ const paths = getProjectPaths(projectRoot);
27
+ const config = await loadConfig(projectRoot);
28
+ const tokensCssPath = getTokensCssPath(config.binaryName);
29
+ const filePath = join(paths.engine, tokensCssPath);
30
+ if (!(await pathExists(filePath))) {
31
+ throw new GeneralError(`Token CSS file not found: ${tokensCssPath}. Run "fireforge furnace init" to seed it.`);
32
+ }
33
+ return { lines: (await readText(filePath)).split('\n'), tokensCssPath };
34
+ }
35
+ /** Applies the `--category` filter, refusing a name the file does not carry. */
36
+ function filterByCategory(groups, category, tokensCssPath) {
37
+ const matched = groups.filter((group) => group.category === category);
38
+ if (matched.length > 0)
39
+ return matched;
40
+ // Same "name the alternatives" contract `token add` gives for an unknown
41
+ // category: a filter that silently prints nothing reads as "this
42
+ // category is empty", which is a different fact.
43
+ const available = groups
44
+ .map((group) => group.category)
45
+ .filter((name) => name !== null);
46
+ const suffix = available.length > 0
47
+ ? `Available categories: ${available.map((name) => `"${name}"`).join(', ')}.`
48
+ : 'The file declares no category banners.';
49
+ throw new GeneralError(`Category "${category}" not found in ${tokensCssPath}.\n\n${suffix}`);
50
+ }
51
+ /**
52
+ * Lists the categories declared in the tokens CSS with their token names,
53
+ * in file order.
54
+ *
55
+ * @param projectRoot - Root directory of the project
56
+ * @param options - Filter and output-mode options
57
+ */
58
+ export async function tokenListCommand(projectRoot, options = {}) {
59
+ if (options.json === true) {
60
+ // stdout belongs exclusively to the payload from here on. A later
61
+ // diagnostic (including withErrorHandling's) routes to stderr.
62
+ setMachineOutputMode(true);
63
+ try {
64
+ const { lines, tokensCssPath } = await readTokensCssLines(projectRoot);
65
+ const all = collectTokenInventory(lines);
66
+ const groups = options.category === undefined
67
+ ? all
68
+ : filterByCategory(all, options.category, tokensCssPath);
69
+ process.stdout.write(`${JSON.stringify({
70
+ schemaVersion: MACHINE_OUTPUT_SCHEMA_VERSION,
71
+ tokensCssPath,
72
+ categories: groups.map((group) => ({
73
+ category: group.category,
74
+ tokens: group.tokens.map((token) => ({
75
+ name: token.name,
76
+ line: token.line,
77
+ value: token.value,
78
+ })),
79
+ })),
80
+ }, null, 2)}\n`);
81
+ setStdoutSealed(true);
82
+ }
83
+ catch (error) {
84
+ emitMachineError('token-list-failed', toError(error).message);
85
+ }
86
+ finally {
87
+ setMachineOutputMode(false);
88
+ }
89
+ return;
90
+ }
91
+ const { lines, tokensCssPath } = await readTokensCssLines(projectRoot);
92
+ const all = collectTokenInventory(lines);
93
+ const groups = options.category === undefined ? all : filterByCategory(all, options.category, tokensCssPath);
94
+ intro('Design Tokens');
95
+ info(tokensCssPath);
96
+ if (groups.length === 0) {
97
+ outro('No token declarations found in the :root block');
98
+ return;
99
+ }
100
+ let total = 0;
101
+ for (const group of groups) {
102
+ info(` ${group.category ?? '(no category)'} — ${String(group.tokens.length)} token(s)`);
103
+ for (const token of group.tokens) {
104
+ info(` ${token.name}`);
105
+ }
106
+ total += group.tokens.length;
107
+ }
108
+ outro(`${String(groups.length)} category/categories, ${String(total)} token(s)`);
109
+ }
110
+ /**
111
+ * Reports one token: the category that owns it and the value it takes in
112
+ * every block that declares it.
113
+ *
114
+ * @param projectRoot - Root directory of the project
115
+ * @param tokenName - Custom-property name, with or without the leading `--`
116
+ * @param options - Output-mode options
117
+ */
118
+ export async function tokenShowCommand(projectRoot, tokenName, options = {}) {
119
+ const emit = async () => {
120
+ const { lines, tokensCssPath } = await readTokensCssLines(projectRoot);
121
+ const name = tokenName.startsWith('--') ? tokenName : `--${tokenName}`;
122
+ const declarations = collectTokenBlockValues(lines, name);
123
+ if (declarations.length === 0) {
124
+ throw new GeneralError(`Token "${name}" is not declared in ${tokensCssPath}. ` +
125
+ 'Run "fireforge token list" to see the declared tokens.');
126
+ }
127
+ const owning = collectTokenInventory(lines).find((group) => group.tokens.some((token) => token.name === name));
128
+ return { tokensCssPath, name, category: owning?.category ?? null, declarations };
129
+ };
130
+ if (options.json === true) {
131
+ setMachineOutputMode(true);
132
+ try {
133
+ const report = await emit();
134
+ process.stdout.write(`${JSON.stringify({ schemaVersion: MACHINE_OUTPUT_SCHEMA_VERSION, ...report }, null, 2)}\n`);
135
+ setStdoutSealed(true);
136
+ }
137
+ catch (error) {
138
+ emitMachineError('token-show-failed', toError(error).message);
139
+ }
140
+ finally {
141
+ setMachineOutputMode(false);
142
+ }
143
+ return;
144
+ }
145
+ const report = await emit();
146
+ intro('Design Token');
147
+ info(`${report.name} — category: ${report.category ?? '(no category)'}`);
148
+ info(report.tokensCssPath);
149
+ for (const declaration of report.declarations) {
150
+ info(` ${declaration.block}: ${declaration.value} (line ${String(declaration.line)})`);
151
+ }
152
+ outro(`${String(report.declarations.length)} declaration(s)`);
153
+ }
@@ -10,6 +10,7 @@ import { info, intro, outro, success, warn } from '../utils/logger.js';
10
10
  import { pickDefined } from '../utils/options.js';
11
11
  import { normalizeTokenName } from '../utils/validation.js';
12
12
  import { tokenCoverageCommand } from './token-coverage.js';
13
+ import { tokenListCommand, tokenShowCommand } from './token-list.js';
13
14
  async function normalizeTokenNameForProject(projectRoot, rawTokenName) {
14
15
  if (rawTokenName.startsWith('--')) {
15
16
  return normalizeTokenName(rawTokenName);
@@ -20,7 +21,7 @@ async function normalizeTokenNameForProject(projectRoot, rawTokenName) {
20
21
  const strippedPrefix = furnaceConfig.tokenPrefix.replace(/^--/, '').replace(/-$/, '');
21
22
  const strippedName = rawTokenName.replace(/^--/, '');
22
23
  // A bare name that already starts with the configured prefix text is
23
- // treated as fully qualified — blindly prepending would silently
24
+ // treated as fully qualified. Blindly prepending would silently
24
25
  // produce a double-prefixed token (e.g. "--hominis-hominis-shadow-low").
25
26
  if (strippedName === strippedPrefix || strippedName.startsWith(`${strippedPrefix}-`)) {
26
27
  info(`Token name "${rawTokenName}" already starts with the configured prefix ` +
@@ -36,12 +37,12 @@ async function normalizeTokenNameForProject(projectRoot, rawTokenName) {
36
37
  return normalizeTokenName(rawTokenName);
37
38
  }
38
39
  /**
39
- * Reports a no-op add, naming WHERE the existing declaration lives.
40
+ * Reports a no-op add, naming where the existing declaration lives.
40
41
  *
41
- * A variant skip has no category to name — the declaration lives in a
42
- * `:root<selector>` block — so the location reads as that block. The
42
+ * A variant skip has no category to name, because the declaration lives in
43
+ * a `:root<selector>` block, so the location reads as that block. The
43
44
  * variant path used to report no location at all, so a re-run meant to
44
- * CHANGE a value exited 0 having silently changed nothing.
45
+ * change a value exited 0 having silently changed nothing.
45
46
  *
46
47
  * @param tokenName - Full token name including prefix
47
48
  * @param result - Result carrying the skip location, when known
@@ -52,7 +53,7 @@ function reportSkippedToken(tokenName, result, options) {
52
53
  ? `:root${options.variant}`
53
54
  : `category "${result.skippedExisting?.category ?? options.category ?? ''}"`;
54
55
  const where = result.skippedExisting
55
- ? ` in ${scope} (line ${String(result.skippedExisting.line)}), unchanged`
56
+ ? ` in ${scope} (line ${result.skippedExisting.line}), unchanged`
56
57
  : '';
57
58
  info(`Token ${tokenName} already exists${where} (skipped)`);
58
59
  }
@@ -68,8 +69,8 @@ export async function tokenAddCommand(projectRoot, tokenName, value, options) {
68
69
  intro('Token Add');
69
70
  // A fresh project without furnace.json otherwise fails deep inside the
70
71
  // token-manager's `assertTokenCategoryExists` with "Token CSS file not
71
- // found: browser/themes/shared/<binary>-tokens.css" — technically correct,
72
- // but the operator's actual next step is to initialize Furnace, which
72
+ // found: browser/themes/shared/<binary>-tokens.css", which is technically
73
+ // correct, but the operator's actual next step is to initialize Furnace, which
73
74
  // scaffolds the tokens CSS file. Catching the uninitialized case here
74
75
  // gives the right guidance before the generic "file not found" error.
75
76
  if (!(await furnaceConfigExists(projectRoot))) {
@@ -170,9 +171,9 @@ export function registerToken(program, { getProjectRoot, withErrorHandling }) {
170
171
  // Commander's argument parsing.
171
172
  // Description ends with `(required)` because Commander's
172
173
  // `makeOptionMandatory` does not render a required marker in `--help`
173
- // output — only `.requiredOption` does that, and switching to
174
+ // output. Only `.requiredOption` does that, and switching to
174
175
  // `.requiredOption` would lose the `.choices()` enforcement. The
175
- // explicit suffix keeps the runtime validation AND surfaces required
176
+ // explicit suffix keeps the runtime validation and surfaces required
176
177
  // status in help alongside the other options that use `.requiredOption`.
177
178
  new Option('--mode <mode>', 'Dark mode behavior (required)')
178
179
  .choices(['auto', 'static', 'override'])
@@ -201,6 +202,21 @@ export function registerToken(program, { getProjectRoot, withErrorHandling }) {
201
202
  }),
202
203
  });
203
204
  }));
205
+ token
206
+ .command('list')
207
+ .description('List the design-token categories declared in the tokens CSS with their token names, in file order')
208
+ .option('--category <name>', 'Restrict the report to one category')
209
+ .option('--json', 'Emit the machine-readable envelope on stdout (see docs/machine-output.md)')
210
+ .action(withErrorHandling(async (options) => {
211
+ await tokenListCommand(getProjectRoot(), pickDefined({ category: options.category, json: options.json }));
212
+ }));
213
+ token
214
+ .command('show <token-name>')
215
+ .description('Show one token: its category, the value it takes in every declaring block, and where it is defined. The leading `--` is optional; with it, use the `--` separator first (e.g. `fireforge token show -- --my-token`).')
216
+ .option('--json', 'Emit the machine-readable envelope on stdout (see docs/machine-output.md)')
217
+ .action(withErrorHandling(async (tokenName, options) => {
218
+ await tokenShowCommand(getProjectRoot(), tokenName, pickDefined({ json: options.json }));
219
+ }));
204
220
  token
205
221
  .command('coverage')
206
222
  .description('Measure design token usage across modified CSS files')