@hominis/fireforge 0.45.0 → 0.46.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 (359) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/bin/fireforge.js +6 -0
  3. package/dist/build-info.json +4 -4
  4. package/dist/src/cli-usage-error.d.ts +46 -0
  5. package/dist/src/cli-usage-error.js +81 -0
  6. package/dist/src/cli.d.ts +5 -1
  7. package/dist/src/cli.js +20 -21
  8. package/dist/src/commands/bootstrap.js +1 -2
  9. package/dist/src/commands/build.js +15 -6
  10. package/dist/src/commands/destructive-decision.d.ts +19 -0
  11. package/dist/src/commands/destructive-decision.js +31 -0
  12. package/dist/src/commands/doctor-check-core.d.ts +0 -6
  13. package/dist/src/commands/doctor-check-core.js +0 -8
  14. package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
  15. package/dist/src/commands/doctor-orphaned-harness.js +4 -12
  16. package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
  17. package/dist/src/commands/doctor.d.ts +2 -0
  18. package/dist/src/commands/doctor.js +7 -8
  19. package/dist/src/commands/download.js +35 -24
  20. package/dist/src/commands/export-all.js +21 -4
  21. package/dist/src/commands/export-flow.js +15 -45
  22. package/dist/src/commands/export-placement-conflicts.js +3 -3
  23. package/dist/src/commands/export-placement-gate.js +2 -8
  24. package/dist/src/commands/export-placement-policy.js +3 -5
  25. package/dist/src/commands/export-shared.d.ts +42 -23
  26. package/dist/src/commands/export-shared.js +4 -19
  27. package/dist/src/commands/export.js +10 -1
  28. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  29. package/dist/src/commands/furnace/authoring-config.js +19 -0
  30. package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
  31. package/dist/src/commands/furnace/create-browser-test.js +3 -8
  32. package/dist/src/commands/furnace/create-dry-run.js +2 -5
  33. package/dist/src/commands/furnace/create-templates.d.ts +17 -1
  34. package/dist/src/commands/furnace/create-templates.js +2 -1
  35. package/dist/src/commands/furnace/create.js +25 -19
  36. package/dist/src/commands/furnace/deploy.js +11 -2
  37. package/dist/src/commands/furnace/init.js +2 -1
  38. package/dist/src/commands/furnace/override.js +28 -19
  39. package/dist/src/commands/furnace/refresh.js +9 -1
  40. package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
  41. package/dist/src/commands/furnace/remove-mutations.js +0 -1
  42. package/dist/src/commands/furnace/remove.js +2 -6
  43. package/dist/src/commands/furnace/rename-browser-test.js +1 -7
  44. package/dist/src/commands/furnace/rename.js +29 -29
  45. package/dist/src/commands/furnace/status.js +12 -9
  46. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  47. package/dist/src/commands/furnace/test-file-name.js +39 -0
  48. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  49. package/dist/src/commands/furnace/validation-output.js +3 -8
  50. package/dist/src/commands/import.js +2 -9
  51. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  52. package/dist/src/commands/lint-per-patch.js +19 -4
  53. package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
  54. package/dist/src/commands/lint.d.ts +2 -1
  55. package/dist/src/commands/lint.js +1 -1
  56. package/dist/src/commands/manifest.js +1 -1
  57. package/dist/src/commands/package.js +2 -4
  58. package/dist/src/commands/patch/compact.js +14 -15
  59. package/dist/src/commands/patch/delete.js +15 -25
  60. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  61. package/dist/src/commands/patch/entry-projection.js +24 -0
  62. package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
  63. package/dist/src/commands/patch/lint-ignore.js +19 -29
  64. package/dist/src/commands/patch/move-files-create.js +24 -10
  65. package/dist/src/commands/patch/move-files-into.js +38 -34
  66. package/dist/src/commands/patch/move-files.js +4 -13
  67. package/dist/src/commands/patch/rename.js +27 -41
  68. package/dist/src/commands/patch/reorder.js +25 -38
  69. package/dist/src/commands/patch/split-plan.d.ts +4 -5
  70. package/dist/src/commands/patch/split-plan.js +4 -8
  71. package/dist/src/commands/patch/split.js +45 -43
  72. package/dist/src/commands/patch/staged-dependency.js +16 -22
  73. package/dist/src/commands/patch/tier.js +15 -25
  74. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  75. package/dist/src/commands/patch-rename-map.js +36 -0
  76. package/dist/src/commands/pending-resolution.d.ts +15 -0
  77. package/dist/src/commands/pending-resolution.js +25 -0
  78. package/dist/src/commands/re-export-adjacent.d.ts +24 -2
  79. package/dist/src/commands/re-export-adjacent.js +32 -16
  80. package/dist/src/commands/re-export-bulk-scan.js +6 -10
  81. package/dist/src/commands/re-export-drift.js +4 -4
  82. package/dist/src/commands/re-export-files.d.ts +2 -3
  83. package/dist/src/commands/re-export-files.js +38 -29
  84. package/dist/src/commands/re-export-lint.d.ts +3 -4
  85. package/dist/src/commands/re-export-lint.js +9 -2
  86. package/dist/src/commands/re-export-scan.js +5 -2
  87. package/dist/src/commands/re-export-single.d.ts +22 -3
  88. package/dist/src/commands/re-export-single.js +19 -11
  89. package/dist/src/commands/re-export.js +28 -11
  90. package/dist/src/commands/rebase/abort.js +3 -8
  91. package/dist/src/commands/rebase/continue.js +12 -12
  92. package/dist/src/commands/rebase/index.js +2 -2
  93. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  94. package/dist/src/commands/rebase/patch-loop.js +2 -7
  95. package/dist/src/commands/resolve.js +18 -10
  96. package/dist/src/commands/run.d.ts +0 -13
  97. package/dist/src/commands/run.js +12 -25
  98. package/dist/src/commands/setup-support.d.ts +16 -4
  99. package/dist/src/commands/setup-support.js +16 -16
  100. package/dist/src/commands/setup.js +3 -9
  101. package/dist/src/commands/source.js +8 -1
  102. package/dist/src/commands/status-check.js +2 -2
  103. package/dist/src/commands/status-output.js +2 -2
  104. package/dist/src/commands/status.js +3 -4
  105. package/dist/src/commands/test-build-phase.d.ts +2 -2
  106. package/dist/src/commands/test-build-phase.js +31 -7
  107. package/dist/src/commands/test-modes.d.ts +2 -2
  108. package/dist/src/commands/test-modes.js +0 -1
  109. package/dist/src/commands/test-register.js +5 -3
  110. package/dist/src/commands/test-run.js +25 -18
  111. package/dist/src/commands/test-stale-gate.js +4 -4
  112. package/dist/src/commands/test-verdict.d.ts +16 -2
  113. package/dist/src/commands/test-verdict.js +18 -3
  114. package/dist/src/commands/test.js +42 -5
  115. package/dist/src/commands/token-list.d.ts +26 -0
  116. package/dist/src/commands/token-list.js +153 -0
  117. package/dist/src/commands/token.js +17 -1
  118. package/dist/src/commands/tree.js +7 -2
  119. package/dist/src/commands/typecheck.js +9 -9
  120. package/dist/src/commands/wire.js +4 -3
  121. package/dist/src/core/branding.d.ts +0 -7
  122. package/dist/src/core/branding.js +3 -2
  123. package/dist/src/core/browser-wire.js +6 -3
  124. package/dist/src/core/build-audit-platform.d.ts +29 -0
  125. package/dist/src/core/build-audit-platform.js +140 -0
  126. package/dist/src/core/build-audit-registration.js +3 -2
  127. package/dist/src/core/build-audit-skip.d.ts +57 -0
  128. package/dist/src/core/build-audit-skip.js +112 -0
  129. package/dist/src/core/build-audit.d.ts +15 -2
  130. package/dist/src/core/build-audit.js +110 -10
  131. package/dist/src/core/build-baseline.d.ts +45 -28
  132. package/dist/src/core/build-baseline.js +6 -29
  133. package/dist/src/core/build-jar-escalation.js +3 -2
  134. package/dist/src/core/build-overwrite-guard.js +1 -1
  135. package/dist/src/core/build-prepare.d.ts +0 -8
  136. package/dist/src/core/build-prepare.js +7 -12
  137. package/dist/src/core/config-paths.d.ts +2 -6
  138. package/dist/src/core/config-paths.js +4 -2
  139. package/dist/src/core/config-state.d.ts +0 -6
  140. package/dist/src/core/config-state.js +1 -19
  141. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  142. package/dist/src/core/config-validate-build-audit.js +80 -0
  143. package/dist/src/core/config-validate-file-size.js +1 -1
  144. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  145. package/dist/src/core/config-validate-patch-policy.js +3 -3
  146. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  147. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  148. package/dist/src/core/config-validate.js +14 -3
  149. package/dist/src/core/config.d.ts +2 -2
  150. package/dist/src/core/config.js +11 -15
  151. package/dist/src/core/coverage-extend.js +4 -4
  152. package/dist/src/core/discard-baseline.js +7 -7
  153. package/dist/src/core/engine-precondition.d.ts +1 -9
  154. package/dist/src/core/engine-precondition.js +3 -8
  155. package/dist/src/core/engine-session-lock.js +13 -17
  156. package/dist/src/core/export-moved-code-shape.js +2 -2
  157. package/dist/src/core/file-lock-owner.d.ts +103 -0
  158. package/dist/src/core/file-lock-owner.js +259 -0
  159. package/dist/src/core/file-lock.d.ts +2 -7
  160. package/dist/src/core/file-lock.js +40 -91
  161. package/dist/src/core/firefox-cache.d.ts +13 -1
  162. package/dist/src/core/firefox-cache.js +59 -34
  163. package/dist/src/core/firefox-download.d.ts +15 -0
  164. package/dist/src/core/firefox-download.js +37 -21
  165. package/dist/src/core/firefox-extract.d.ts +6 -5
  166. package/dist/src/core/firefox-extract.js +36 -18
  167. package/dist/src/core/firefox.d.ts +30 -32
  168. package/dist/src/core/firefox.js +5 -36
  169. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  170. package/dist/src/core/furnace-apply-dry-run.js +1 -7
  171. package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
  172. package/dist/src/core/furnace-apply-helpers.js +8 -19
  173. package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
  174. package/dist/src/core/furnace-apply.d.ts +1 -1
  175. package/dist/src/core/furnace-apply.js +30 -10
  176. package/dist/src/core/furnace-config.d.ts +1 -1
  177. package/dist/src/core/furnace-config.js +23 -36
  178. package/dist/src/core/furnace-constants.js +3 -2
  179. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  180. package/dist/src/core/furnace-dir-entry.js +21 -0
  181. package/dist/src/core/furnace-operation.d.ts +2 -0
  182. package/dist/src/core/furnace-operation.js +3 -1
  183. package/dist/src/core/furnace-refresh.d.ts +18 -6
  184. package/dist/src/core/furnace-refresh.js +3 -6
  185. package/dist/src/core/furnace-registration-ast.d.ts +0 -1
  186. package/dist/src/core/furnace-registration-ast.js +0 -3
  187. package/dist/src/core/furnace-registration.d.ts +2 -1
  188. package/dist/src/core/furnace-registration.js +22 -29
  189. package/dist/src/core/furnace-scanner.js +3 -6
  190. package/dist/src/core/furnace-state-persist.d.ts +2 -2
  191. package/dist/src/core/furnace-validate-registration.js +5 -7
  192. package/dist/src/core/git-base.d.ts +3 -1
  193. package/dist/src/core/git-base.js +25 -3
  194. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  195. package/dist/src/core/git-diff-new-file.js +119 -0
  196. package/dist/src/core/git-diff.d.ts +9 -9
  197. package/dist/src/core/git-diff.js +88 -157
  198. package/dist/src/core/git-file-ops.d.ts +0 -7
  199. package/dist/src/core/git-file-ops.js +4 -28
  200. package/dist/src/core/git-readonly-index.d.ts +0 -2
  201. package/dist/src/core/git-readonly-index.js +0 -4
  202. package/dist/src/core/git-status.d.ts +7 -0
  203. package/dist/src/core/git-status.js +21 -9
  204. package/dist/src/core/git.d.ts +0 -6
  205. package/dist/src/core/git.js +14 -43
  206. package/dist/src/core/harness-orphans.js +8 -7
  207. package/dist/src/core/history-log.d.ts +19 -0
  208. package/dist/src/core/history-log.js +29 -0
  209. package/dist/src/core/mach-error-hints.d.ts +0 -5
  210. package/dist/src/core/mach-error-hints.js +1 -1
  211. package/dist/src/core/mach-known-noise-filter.d.ts +4 -3
  212. package/dist/src/core/mach-known-noise-filter.js +7 -9
  213. package/dist/src/core/mach-mozconfig.js +2 -1
  214. package/dist/src/core/mach-python.d.ts +2 -0
  215. package/dist/src/core/mach-python.js +12 -7
  216. package/dist/src/core/mach-resource-shim.d.ts +13 -1
  217. package/dist/src/core/mach-resource-shim.js +112 -9
  218. package/dist/src/core/mach.d.ts +39 -53
  219. package/dist/src/core/mach.js +13 -81
  220. package/dist/src/core/marionette-port.d.ts +0 -17
  221. package/dist/src/core/marionette-port.js +12 -58
  222. package/dist/src/core/marionette-preflight.js +9 -27
  223. package/dist/src/core/mochitest-server-port.js +3 -3
  224. package/dist/src/core/moz-manifest-rules.js +37 -33
  225. package/dist/src/core/patch-apply-fuzz.js +4 -4
  226. package/dist/src/core/patch-apply.d.ts +4 -5
  227. package/dist/src/core/patch-apply.js +6 -12
  228. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  229. package/dist/src/core/patch-export-coverage.js +1 -30
  230. package/dist/src/core/patch-export-update.d.ts +18 -1
  231. package/dist/src/core/patch-export-update.js +4 -3
  232. package/dist/src/core/patch-export.d.ts +11 -21
  233. package/dist/src/core/patch-export.js +44 -66
  234. package/dist/src/core/patch-files.d.ts +0 -4
  235. package/dist/src/core/patch-files.js +0 -11
  236. package/dist/src/core/patch-lint-binary.d.ts +6 -12
  237. package/dist/src/core/patch-lint-cache.d.ts +17 -1
  238. package/dist/src/core/patch-lint-cache.js +3 -6
  239. package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
  240. package/dist/src/core/patch-lint-checkjs.js +37 -24
  241. package/dist/src/core/patch-lint-creators.d.ts +2 -6
  242. package/dist/src/core/patch-lint-cross.d.ts +16 -8
  243. package/dist/src/core/patch-lint-cross.js +49 -92
  244. package/dist/src/core/patch-lint-css.js +10 -6
  245. package/dist/src/core/patch-lint-file-size.js +3 -3
  246. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  247. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  248. package/dist/src/core/patch-lint-jsdoc.js +36 -36
  249. package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
  250. package/dist/src/core/patch-lint-prettier.js +1 -1
  251. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  252. package/dist/src/core/patch-lint-queue-types.js +12 -0
  253. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  254. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  255. package/dist/src/core/patch-lint.d.ts +14 -9
  256. package/dist/src/core/patch-lint.js +4 -3
  257. package/dist/src/core/patch-lock.js +3 -3
  258. package/dist/src/core/patch-manifest-io.js +8 -7
  259. package/dist/src/core/patch-parse.d.ts +19 -8
  260. package/dist/src/core/patch-parse.js +25 -0
  261. package/dist/src/core/patch-policy.js +15 -27
  262. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  263. package/dist/src/core/patch-source-metadata.js +0 -4
  264. package/dist/src/core/patch-transform.d.ts +0 -8
  265. package/dist/src/core/patch-transform.js +0 -10
  266. package/dist/src/core/process-cpu-time.js +1 -1
  267. package/dist/src/core/rebase-session.d.ts +2 -8
  268. package/dist/src/core/rebase-session.js +5 -17
  269. package/dist/src/core/register-browser-content.js +3 -2
  270. package/dist/src/core/register-browser-test.js +2 -1
  271. package/dist/src/core/register-module.js +2 -1
  272. package/dist/src/core/register-scaffold.js +5 -4
  273. package/dist/src/core/register-shared-css.js +2 -1
  274. package/dist/src/core/run-log-redact.d.ts +38 -0
  275. package/dist/src/core/run-log-redact.js +69 -0
  276. package/dist/src/core/run-log.d.ts +13 -2
  277. package/dist/src/core/run-log.js +67 -18
  278. package/dist/src/core/signal-critical.js +2 -4
  279. package/dist/src/core/smoke-patterns.d.ts +0 -1
  280. package/dist/src/core/smoke-patterns.js +6 -11
  281. package/dist/src/core/state-file.d.ts +12 -1
  282. package/dist/src/core/state-file.js +14 -1
  283. package/dist/src/core/status-classify.js +2 -1
  284. package/dist/src/core/test-changed-prefs.js +26 -11
  285. package/dist/src/core/test-harness-crash.js +2 -2
  286. package/dist/src/core/test-stale-check.d.ts +0 -2
  287. package/dist/src/core/test-stale-check.js +2 -2
  288. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  289. package/dist/src/core/test-xpcshell-retry.js +14 -11
  290. package/dist/src/core/token-category.d.ts +33 -0
  291. package/dist/src/core/token-category.js +56 -48
  292. package/dist/src/core/token-dark-mode.js +2 -14
  293. package/dist/src/core/token-inventory.d.ts +56 -0
  294. package/dist/src/core/token-inventory.js +109 -0
  295. package/dist/src/core/token-manager.d.ts +1 -1
  296. package/dist/src/core/token-manager.js +1 -1
  297. package/dist/src/core/token-variant.js +21 -22
  298. package/dist/src/core/toolchain-preflight.js +1 -1
  299. package/dist/src/core/tree-cow.d.ts +0 -2
  300. package/dist/src/core/tree-cow.js +2 -2
  301. package/dist/src/core/tree-store.js +4 -5
  302. package/dist/src/core/typecheck.js +2 -2
  303. package/dist/src/core/wire-dom-fragment.js +6 -17
  304. package/dist/src/core/wire-utils.js +5 -17
  305. package/dist/src/core/xpcshell-appdir.js +2 -4
  306. package/dist/src/errors/base.d.ts +53 -1
  307. package/dist/src/errors/base.js +79 -11
  308. package/dist/src/errors/build.js +20 -28
  309. package/dist/src/errors/config.d.ts +0 -14
  310. package/dist/src/errors/config.js +13 -34
  311. package/dist/src/errors/download.d.ts +13 -0
  312. package/dist/src/errors/download.js +53 -24
  313. package/dist/src/errors/furnace.js +8 -9
  314. package/dist/src/errors/git.d.ts +8 -8
  315. package/dist/src/errors/git.js +20 -30
  316. package/dist/src/errors/patch.js +8 -10
  317. package/dist/src/errors/rebase.js +7 -7
  318. package/dist/src/types/commands/options.d.ts +77 -123
  319. package/dist/src/types/config.d.ts +34 -2
  320. package/dist/src/types/index.d.ts +0 -1
  321. package/dist/src/utils/assert.d.ts +3 -15
  322. package/dist/src/utils/assert.js +1 -18
  323. package/dist/src/utils/build-info.d.ts +1 -1
  324. package/dist/src/utils/child-env.d.ts +2 -1
  325. package/dist/src/utils/elapsed.js +10 -1
  326. package/dist/src/utils/fs.js +8 -13
  327. package/dist/src/utils/hash.d.ts +12 -0
  328. package/dist/src/utils/hash.js +16 -0
  329. package/dist/src/utils/line-dispatch.d.ts +15 -0
  330. package/dist/src/utils/line-dispatch.js +48 -0
  331. package/dist/src/utils/options.d.ts +1 -7
  332. package/dist/src/utils/options.js +6 -7
  333. package/dist/src/utils/package-root.js +3 -12
  334. package/dist/src/utils/platform.d.ts +0 -4
  335. package/dist/src/utils/process-group.d.ts +2 -1
  336. package/dist/src/utils/process-group.js +20 -19
  337. package/dist/src/utils/process.d.ts +40 -26
  338. package/dist/src/utils/process.js +115 -166
  339. package/dist/src/utils/ps-duration.js +3 -3
  340. package/dist/src/utils/sleep.d.ts +26 -0
  341. package/dist/src/utils/sleep.js +31 -0
  342. package/dist/src/utils/validation.d.ts +2 -38
  343. package/dist/src/utils/validation.js +7 -16
  344. package/docs/configuration.md +89 -1
  345. package/docs/exit-codes.md +31 -19
  346. package/docs/lifecycle-invariants.md +18 -12
  347. package/docs/machine-output.md +31 -8
  348. package/docs/patch-workflow.md +2 -1
  349. package/docs/run-logs.md +44 -4
  350. package/docs/testing.md +8 -1
  351. package/package.json +8 -7
  352. package/dist/src/commands/rebase.d.ts +0 -4
  353. package/dist/src/commands/rebase.js +0 -5
  354. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  355. package/dist/src/core/patch-artifact-normalize.js +0 -24
  356. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  357. package/dist/src/core/patch-lint-reexports.js +0 -8
  358. package/dist/src/core/wire-targets.d.ts +0 -7
  359. package/dist/src/core/wire-targets.js +0 -8
@@ -6,7 +6,7 @@
6
6
  * the string only when the assertion actually fails, where a plain
7
7
  * template literal would build it on every call.
8
8
  */
9
- export type AssertionMessage = string | (() => string);
9
+ type AssertionMessage = string | (() => string);
10
10
  /**
11
11
  * Asserts that an internal invariant holds.
12
12
  *
@@ -18,23 +18,10 @@ export type AssertionMessage = string | (() => string);
18
18
  * @throws {@link InternalInvariantError} when `condition` is falsy.
19
19
  */
20
20
  export declare function assert(condition: unknown, message: AssertionMessage): asserts condition;
21
- /**
22
- * Asserts that a value is neither `null` nor `undefined`, narrowing it in
23
- * place for the statements that follow.
24
- *
25
- * Use this in statement position, where the value is already bound to a
26
- * name. Use {@link expectDefined} in expression position, where it is not.
27
- *
28
- * @param value - The value that should be present
29
- * @param message - What was supposed to be present, and why
30
- * @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
31
- */
32
- export declare function assertDefined<T>(value: T, message: AssertionMessage): asserts value is NonNullable<T>;
33
21
  /**
34
22
  * Returns a value that must be present, throwing if it is not.
35
23
  *
36
- * The expression-position counterpart to {@link assertDefined}: it checks
37
- * and returns in one step, so an indexed read can be asserted inline
24
+ * Checks and returns in one step, so an indexed read can be asserted inline
38
25
  * (`push({ content: expectDefined(lines[k], …) })`) without first binding
39
26
  * it to a local.
40
27
  *
@@ -44,3 +31,4 @@ export declare function assertDefined<T>(value: T, message: AssertionMessage): a
44
31
  * @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
45
32
  */
46
33
  export declare function expectDefined<T>(value: T, message: AssertionMessage): NonNullable<T>;
34
+ export {};
@@ -46,27 +46,10 @@ export function assert(condition, message) {
46
46
  throw new InternalInvariantError(resolveMessage(message));
47
47
  }
48
48
  }
49
- /**
50
- * Asserts that a value is neither `null` nor `undefined`, narrowing it in
51
- * place for the statements that follow.
52
- *
53
- * Use this in statement position, where the value is already bound to a
54
- * name. Use {@link expectDefined} in expression position, where it is not.
55
- *
56
- * @param value - The value that should be present
57
- * @param message - What was supposed to be present, and why
58
- * @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
59
- */
60
- export function assertDefined(value, message) {
61
- if (value === null || value === undefined) {
62
- throw new InternalInvariantError(resolveMessage(message));
63
- }
64
- }
65
49
  /**
66
50
  * Returns a value that must be present, throwing if it is not.
67
51
  *
68
- * The expression-position counterpart to {@link assertDefined}: it checks
69
- * and returns in one step, so an indexed read can be asserted inline
52
+ * Checks and returns in one step, so an indexed read can be asserted inline
70
53
  * (`push({ content: expectDefined(lines[k], …) })`) without first binding
71
54
  * it to a local.
72
55
  *
@@ -1,5 +1,5 @@
1
1
  /** Source identity of the running build. */
2
- export interface BuildIdentity {
2
+ interface BuildIdentity {
3
3
  shortCommit: string;
4
4
  dirty: boolean;
5
5
  /**
@@ -5,7 +5,7 @@
5
5
  * file sits on a 500-line budget; the logic belongs to the exec layer.
6
6
  */
7
7
  /** The `env` / `envUnset` slice of exec options this module needs. */
8
- export interface ChildEnvOptions {
8
+ interface ChildEnvOptions {
9
9
  /** Variables to add or overwrite on top of `process.env`. */
10
10
  env?: Record<string, string> | undefined;
11
11
  /** Variables to remove after the merge. */
@@ -28,3 +28,4 @@ export interface ChildEnvOptions {
28
28
  * @returns The environment to hand `spawn`
29
29
  */
30
30
  export declare function buildChildEnv(options: ChildEnvOptions): NodeJS.ProcessEnv;
31
+ export {};
@@ -1,5 +1,14 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- /** Formats elapsed milliseconds for progress messages. */
2
+ /**
3
+ * Formats a duration in milliseconds as `Xm Ys`, or `Ys` under a minute.
4
+ *
5
+ * The single spelling of FireForge's elapsed-time wording: `build` and
6
+ * `package` each hand-rolled the same minute/second split, so a change to
7
+ * the format silently applied to some progress lines and not others.
8
+ *
9
+ * @param ms - Duration in milliseconds; negative input is clamped to zero.
10
+ * @returns The duration as `Xm Ys`, or `Ys` when under one minute.
11
+ */
3
12
  function formatElapsed(ms) {
4
13
  const totalSeconds = Math.max(0, Math.round(ms / 1000));
5
14
  const minutes = Math.floor(totalSeconds / 60);
@@ -3,13 +3,9 @@ import { randomUUID } from 'node:crypto';
3
3
  import { access, chmod, copyFile as fsCopyFile, lstat, mkdir, open, readdir, readFile, rename, rm, stat, statfs, } from 'node:fs/promises';
4
4
  import { basename, dirname, join } from 'node:path';
5
5
  import { getNodeErrorCode } from './errors.js';
6
+ import { sleep } from './sleep.js';
6
7
  const RETRIABLE_REMOVE_ERRORS = new Set(['ENOTEMPTY', 'EBUSY', 'EPERM']);
7
8
  const RETRIABLE_RENAME_ERRORS = new Set(['EPERM', 'EACCES', 'EBUSY']);
8
- function sleep(ms) {
9
- return new Promise((resolve) => {
10
- setTimeout(resolve, ms);
11
- });
12
- }
13
9
  /**
14
10
  * Checks if a path exists.
15
11
  * @param path - Path to check
@@ -19,8 +15,7 @@ export async function pathExists(path) {
19
15
  await access(path);
20
16
  return true;
21
17
  }
22
- catch (error) {
23
- void error;
18
+ catch {
24
19
  return false;
25
20
  }
26
21
  }
@@ -92,8 +87,7 @@ export async function isSymlink(path) {
92
87
  try {
93
88
  return (await lstat(path)).isSymbolicLink();
94
89
  }
95
- catch (error) {
96
- void error;
90
+ catch {
97
91
  return false;
98
92
  }
99
93
  }
@@ -234,15 +228,16 @@ async function syncParentDir(path) {
234
228
  directoryHandle = await open(dirname(path), 'r');
235
229
  await directoryHandle.sync();
236
230
  }
237
- catch (error) {
238
- void error;
231
+ catch {
232
+ // Best-effort durability: a directory that cannot be opened or fsynced
233
+ // (network mounts, Windows) must not fail the write it was protecting.
239
234
  }
240
235
  finally {
241
236
  try {
242
237
  await directoryHandle?.close();
243
238
  }
244
- catch (error) {
245
- void error;
239
+ catch {
240
+ // Nothing left to do — the handle is being discarded either way.
246
241
  }
247
242
  }
248
243
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Computes the hexadecimal SHA-256 digest of a string or buffer.
3
+ *
4
+ * Eleven sites across `src/core/` inlined the same
5
+ * `createHash('sha256').update(input).digest('hex')` chain for cache keys,
6
+ * fingerprints and content addresses. They all share this helper instead, so
7
+ * the digest algorithm and encoding are decided in exactly one place.
8
+ *
9
+ * @param input - Data to digest, as a UTF-8 string or a raw buffer.
10
+ * @returns The 64-character lowercase hexadecimal digest.
11
+ */
12
+ export declare function sha256Hex(input: string | Buffer): string;
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { createHash } from 'node:crypto';
3
+ /**
4
+ * Computes the hexadecimal SHA-256 digest of a string or buffer.
5
+ *
6
+ * Eleven sites across `src/core/` inlined the same
7
+ * `createHash('sha256').update(input).digest('hex')` chain for cache keys,
8
+ * fingerprints and content addresses. They all share this helper instead, so
9
+ * the digest algorithm and encoding are decided in exactly one place.
10
+ *
11
+ * @param input - Data to digest, as a UTF-8 string or a raw buffer.
12
+ * @returns The 64-character lowercase hexadecimal digest.
13
+ */
14
+ export function sha256Hex(input) {
15
+ return createHash('sha256').update(input).digest('hex');
16
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Line splitting for the smoke-run stream dispatch in `process.ts`. Kept as
3
+ * a sibling so the exec module stays within its size budget; the contract
4
+ * (terminators, partial-line cap) is documented on the function.
5
+ */
6
+ /**
7
+ * Drains complete lines from `buffer`, dispatching each to `cb`. Treats
8
+ * `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
9
+ * matters for progress-bar style output (mach, cargo) that repaints a line
10
+ * with carriage returns and never sends a newline, which otherwise
11
+ * accumulates indefinitely. A single trailing `\r` is held back since it may
12
+ * be the first half of a `\r\n` pair split across chunks. Returns the
13
+ * remaining partial line — callers keep accumulating into it.
14
+ */
15
+ export declare function dispatchCompleteLines(buffer: string, cb: ((line: string) => void) | undefined): string;
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Line splitting for the smoke-run stream dispatch in `process.ts`. Kept as
4
+ * a sibling so the exec module stays within its size budget; the contract
5
+ * (terminators, partial-line cap) is documented on the function.
6
+ */
7
+ /**
8
+ * Cap on the partial-line tail kept between chunks. A child emitting one
9
+ * enormous line with no terminator (minified JS dumped to stderr, a raw
10
+ * binary blob) would otherwise grow the buffer without bound — the 50 MB cap
11
+ * guards the collector, not these line buffers. When the tail exceeds the
12
+ * cap it is dispatched as a synthetic (oversized) line so the matchers still
13
+ * see its content, then the buffer resets.
14
+ */
15
+ const MAX_PARTIAL_LINE_SIZE = 1024 * 1024;
16
+ /**
17
+ * Drains complete lines from `buffer`, dispatching each to `cb`. Treats
18
+ * `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
19
+ * matters for progress-bar style output (mach, cargo) that repaints a line
20
+ * with carriage returns and never sends a newline, which otherwise
21
+ * accumulates indefinitely. A single trailing `\r` is held back since it may
22
+ * be the first half of a `\r\n` pair split across chunks. Returns the
23
+ * remaining partial line — callers keep accumulating into it.
24
+ */
25
+ export function dispatchCompleteLines(buffer, cb) {
26
+ let searchFrom = 0;
27
+ for (;;) {
28
+ const nl = buffer.indexOf('\n', searchFrom);
29
+ const cr = buffer.indexOf('\r', searchFrom);
30
+ const idx = nl === -1 ? cr : cr === -1 ? nl : Math.min(nl, cr);
31
+ if (idx === -1)
32
+ break;
33
+ if (buffer[idx] === '\r' && idx === buffer.length - 1) {
34
+ // Possible first half of a chunk-split \r\n — wait for the next chunk.
35
+ break;
36
+ }
37
+ const line = buffer.slice(0, idx);
38
+ const terminatorLength = buffer[idx] === '\r' && buffer[idx + 1] === '\n' ? 2 : 1;
39
+ buffer = buffer.slice(idx + terminatorLength);
40
+ searchFrom = 0;
41
+ cb?.(line);
42
+ }
43
+ if (buffer.length > MAX_PARTIAL_LINE_SIZE) {
44
+ cb?.(buffer);
45
+ return '';
46
+ }
47
+ return buffer;
48
+ }
@@ -1,3 +1,4 @@
1
+ import type { Command } from 'commander';
1
2
  /**
2
3
  * Filters an object to only include keys whose values are not undefined.
3
4
  * Designed for use with exactOptionalPropertyTypes — the result can be
@@ -15,7 +16,6 @@
15
16
  export declare function pickDefined<T extends object>(obj: T): {
16
17
  [K in keyof T]+?: Exclude<T[K], undefined>;
17
18
  };
18
- import type { Command } from 'commander';
19
19
  /**
20
20
  * Wraps an option-argument parser so its failures surface through
21
21
  * commander's own invalid-argument channel.
@@ -88,12 +88,6 @@ export declare function resolveWaitLockSeconds(value: string | number | boolean
88
88
  * @returns The session budget in milliseconds, or undefined
89
89
  */
90
90
  export declare function sessionWaitLockMs(): number | undefined;
91
- /**
92
- * True when `command` already declares `--wait-lock` itself. Used by the
93
- * CLI wiring to add the accept-and-ignore variant only where the honoring
94
- * one is absent.
95
- */
96
- export declare function hasWaitLockOption(command: Command): boolean;
97
91
  /**
98
92
  * Recursively gives every command in the tree a `--wait-lock` flag: the
99
93
  * honoring registration where one already exists, the accept-and-ignore
@@ -1,4 +1,6 @@
1
- // SPDX-License-Identifier: EUPL-1.2
1
+ import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
2
+ import { GeneralError, InvalidArgumentError } from '../errors/base.js';
3
+ import { toError } from './errors.js';
2
4
  /**
3
5
  * Filters an object to only include keys whose values are not undefined.
4
6
  * Designed for use with exactOptionalPropertyTypes — the result can be
@@ -22,9 +24,6 @@ export function pickDefined(obj) {
22
24
  }
23
25
  return result;
24
26
  }
25
- import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
26
- import { GeneralError, InvalidArgumentError } from '../errors/base.js';
27
- import { toError } from './errors.js';
28
27
  /**
29
28
  * Wraps an option-argument parser so its failures surface through
30
29
  * commander's own invalid-argument channel.
@@ -106,7 +105,7 @@ function waitLockSecondsFromEnv() {
106
105
  }
107
106
  const parsed = parseWaitLockSeconds(raw);
108
107
  if (parsed === undefined) {
109
- throw new InvalidArgumentError(`${WAIT_LOCK_ENV_VAR} must be an integer in ${String(MIN_WAIT_LOCK_SECONDS)}..${String(MAX_WAIT_LOCK_SECONDS)} (got "${raw}")`, WAIT_LOCK_ENV_VAR);
108
+ throw new InvalidArgumentError(`${WAIT_LOCK_ENV_VAR} must be an integer in ${MIN_WAIT_LOCK_SECONDS}..${MAX_WAIT_LOCK_SECONDS} (got "${raw}")`, WAIT_LOCK_ENV_VAR);
110
109
  }
111
110
  return parsed;
112
111
  }
@@ -140,7 +139,7 @@ export function resolveWaitLockSeconds(value) {
140
139
  }
141
140
  const parsed = parseWaitLockSeconds(value);
142
141
  if (parsed === undefined) {
143
- throw new GeneralError(`--wait-lock must be an integer in ${String(MIN_WAIT_LOCK_SECONDS)}..${String(MAX_WAIT_LOCK_SECONDS)} (got "${value}")`);
142
+ throw new GeneralError(`--wait-lock must be an integer in ${MIN_WAIT_LOCK_SECONDS}..${MAX_WAIT_LOCK_SECONDS} (got "${value}")`);
144
143
  }
145
144
  return parsed;
146
145
  }
@@ -191,7 +190,7 @@ function addAcceptedWaitLockOption(command) {
191
190
  * CLI wiring to add the accept-and-ignore variant only where the honoring
192
191
  * one is absent.
193
192
  */
194
- export function hasWaitLockOption(command) {
193
+ function hasWaitLockOption(command) {
195
194
  return command.options.some((option) => option.long === '--wait-lock');
196
195
  }
197
196
  /**
@@ -3,21 +3,12 @@ import { readFileSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import { getNodeErrorCode, toError } from './errors.js';
6
+ import { parseObject } from './parse.js';
6
7
  import { isObject } from './validation.js';
7
- function validatePackageMetadata(data, filePath) {
8
- if (typeof data !== 'object' || data === null) {
9
- throw new Error(`Invalid package metadata in ${filePath}: expected an object`);
10
- }
11
- const name = 'name' in data ? data.name : undefined;
12
- const version = 'version' in data ? data.version : undefined;
13
- if (typeof name !== 'string' || typeof version !== 'string') {
14
- throw new Error(`Invalid package metadata in ${filePath}: expected string "name" and "version" fields`);
15
- }
16
- return { name, version, bin: 'bin' in data ? data.bin : undefined };
17
- }
18
8
  function readPackageMetadata(filePath) {
19
9
  const raw = readFileSync(filePath, 'utf-8');
20
- return validatePackageMetadata(JSON.parse(raw), filePath);
10
+ const parsed = parseObject(JSON.parse(raw), 'package.json');
11
+ return { name: parsed.string('name'), version: parsed.string('version'), bin: parsed.raw('bin') };
21
12
  }
22
13
  let cachedPackageRoot;
23
14
  /**
@@ -2,10 +2,6 @@
2
2
  * Supported operating system platforms.
3
3
  */
4
4
  export type Platform = 'darwin' | 'linux' | 'win32';
5
- /**
6
- * Supported CPU architectures.
7
- */
8
- export type Arch = 'x64' | 'arm64';
9
5
  /**
10
6
  * Gets the current operating system platform.
11
7
  * @throws Error if running on an unsupported platform
@@ -19,7 +19,7 @@ import { type ChildProcess } from 'node:child_process';
19
19
  */
20
20
  export declare function killProcessTree(child: ChildProcess, signal: NodeJS.Signals, usesProcessGroup: boolean): void;
21
21
  /** One process still alive in a swept group. */
22
- export interface ProcessGroupSurvivor {
22
+ interface ProcessGroupSurvivor {
23
23
  /** PID, or -1 when pgrep was unavailable and only a liveness probe ran. */
24
24
  pid: number;
25
25
  /** Command line (pgrep -lf output), best-effort. */
@@ -36,3 +36,4 @@ export interface ProcessGroupSurvivor {
36
36
  export declare function sweepProcessGroup(pgid: number, graceMs?: number): Promise<{
37
37
  survivors: ProcessGroupSurvivor[];
38
38
  }>;
39
+ export {};
@@ -8,6 +8,7 @@
8
8
  import { spawn } from 'node:child_process';
9
9
  import { getNodeErrorCode } from './errors.js';
10
10
  import { verbose, warn } from './logger.js';
11
+ import { sleep } from './sleep.js';
11
12
  /**
12
13
  * Sends `signal` to the child's whole tree: the process GROUP on POSIX
13
14
  * (negative-PID kill — reaches mach → python → firefox → content-process
@@ -61,18 +62,6 @@ export function killProcessTree(child, signal, usesProcessGroup) {
61
62
  }
62
63
  const SWEEP_GRACE_MS = 2000;
63
64
  const MULTIPROCESSING_WORKER_PATTERN = /multiprocessing\.(?:spawn|forkserver)|resource_tracker/;
64
- function sweepDelay(ms) {
65
- // Deliberately ref'd (no unref()): this promise is AWAITED between the
66
- // group SIGTERM and the post-grace re-list/SIGKILL escalation, from a
67
- // child 'close' handler after the signal forwarder is disposed — with an
68
- // unref'd timer nothing kept the event loop alive, so Node could exit
69
- // mid-grace and skip the escalation entirely. Healthy runs never reach
70
- // this function (sweepProcessGroup early-returns on zero survivors), so
71
- // the ref never holds a clean exit open.
72
- return new Promise((resolve) => {
73
- setTimeout(resolve, ms);
74
- });
75
- }
76
65
  /**
77
66
  * Minimal spawn-based pgrep runner. exitCode -1 means pgrep itself was
78
67
  * unavailable or errored (distinct from exit 1 = "no matches").
@@ -130,7 +119,7 @@ function describeSurvivors(list) {
130
119
  const tag = MULTIPROCESSING_WORKER_PATTERN.test(s.command)
131
120
  ? ' [multiprocessing worker — the known busy-spin orphan shape]'
132
121
  : '';
133
- return `PID ${String(s.pid)}: ${s.command}${tag}`;
122
+ return `PID ${s.pid}: ${s.command}${tag}`;
134
123
  })
135
124
  .join('; ');
136
125
  }
@@ -148,7 +137,7 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
148
137
  const survivors = await listGroupSurvivors(pgid);
149
138
  if (survivors.length === 0)
150
139
  return { survivors };
151
- warn(`Harness process group ${String(pgid)} left ${String(survivors.length)} surviving ` +
140
+ warn(`Harness process group ${pgid} left ${survivors.length} surviving ` +
152
141
  `process(es) after exit — reaping the group. ${describeSurvivors(survivors)}`);
153
142
  try {
154
143
  process.kill(-pgid, 'SIGTERM');
@@ -158,7 +147,13 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
158
147
  // escalate against, so report the survivors collected so far.
159
148
  return { survivors };
160
149
  }
161
- await sweepDelay(graceMs);
150
+ // Deliberately ref'd (sleep's default): this wait sits between the group
151
+ // SIGTERM and the post-grace re-list/SIGKILL escalation, awaited from a
152
+ // child 'close' handler after the signal forwarder is disposed. With an
153
+ // unref'd timer nothing keeps the event loop alive, so Node could exit
154
+ // mid-grace and skip the escalation entirely. Healthy runs never reach
155
+ // here (sweepProcessGroup early-returns on zero survivors).
156
+ await sleep(graceMs);
162
157
  let remaining = await listGroupSurvivors(pgid);
163
158
  if (remaining.length > 0) {
164
159
  try {
@@ -169,18 +164,24 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
169
164
  // nothing to signal.
170
165
  return { survivors };
171
166
  }
172
- await sweepDelay(Math.min(200, graceMs));
167
+ // Deliberately ref'd (sleep's default): this wait sits between the group
168
+ // SIGTERM and the post-grace re-list/SIGKILL escalation, awaited from a
169
+ // child 'close' handler after the signal forwarder is disposed. With an
170
+ // unref'd timer nothing keeps the event loop alive, so Node could exit
171
+ // mid-grace and skip the escalation entirely. Healthy runs never reach
172
+ // here (sweepProcessGroup early-returns on zero survivors).
173
+ await sleep(Math.min(200, graceMs));
173
174
  remaining = await listGroupSurvivors(pgid);
174
175
  if (remaining.length > 0) {
175
- warn(`Process group ${String(pgid)} still has survivors after SIGKILL: ${describeSurvivors(remaining)}. ` +
176
+ warn(`Process group ${pgid} still has survivors after SIGKILL: ${describeSurvivors(remaining)}. ` +
176
177
  'Inspect manually (ps -axo pid,ppid,time,command) and kill by PID.');
177
178
  }
178
179
  else {
179
- verbose(`Process group ${String(pgid)} reaped after SIGKILL escalation.`);
180
+ verbose(`Process group ${pgid} reaped after SIGKILL escalation.`);
180
181
  }
181
182
  }
182
183
  else {
183
- verbose(`Process group ${String(pgid)} reaped cleanly with SIGTERM.`);
184
+ verbose(`Process group ${pgid} reaped cleanly with SIGTERM.`);
184
185
  }
185
186
  return { survivors };
186
187
  }
@@ -21,7 +21,12 @@ export interface ExecResult {
21
21
  stderrTruncated?: boolean;
22
22
  }
23
23
  /**
24
- * Options for command execution.
24
+ * Options for plain `exec()` — the pipe-capturing, non-grouped, non-mirrored
25
+ * path. The other wrappers extend this with the fields they actually read:
26
+ * `processGroup` lives in {@link ProcessGroupOptions}, `mirror` in
27
+ * {@link MirrorOptions}. Neither belongs here because `exec()` reads
28
+ * neither — a field the type accepts but the function ignores is a trap
29
+ * (the caller believes it got a process group, and never did).
25
30
  */
26
31
  export interface ExecOptions {
27
32
  /** Working directory for the command */
@@ -40,18 +45,32 @@ export interface ExecOptions {
40
45
  * that must not have any.
41
46
  */
42
47
  envUnset?: readonly string[];
48
+ /** Timeout in milliseconds */
49
+ timeout?: number;
50
+ }
51
+ /**
52
+ * Output mirroring for the wrappers that capture through a collector
53
+ * ({@link execInheritCapture}, {@link execSmokeRun}).
54
+ */
55
+ export interface MirrorOptions {
43
56
  /**
44
57
  * Streams to mirror the child's output into, replacing the default
45
58
  * `process.stdout` / `process.stderr` on the stdio-inheriting capture
59
+ * path, or an operator-supplied `--capture-console` file on the smoke
46
60
  * path. Lets a caller tee the live output somewhere else (a run log)
47
- * without a second per-chunk hook.
61
+ * without a second per-chunk hook. Writes happen inline with capture and
62
+ * the stream is NOT closed here — the caller owns its lifecycle.
48
63
  */
49
64
  mirror?: {
50
65
  stdout?: NodeJS.WritableStream;
51
66
  stderr?: NodeJS.WritableStream;
52
67
  };
53
- /** Timeout in milliseconds */
54
- timeout?: number;
68
+ }
69
+ /**
70
+ * Process-group reaping for the long-lived wrappers ({@link execStream},
71
+ * {@link execInherit}, {@link execInheritCapture}).
72
+ */
73
+ export interface ProcessGroupOptions {
55
74
  /**
56
75
  * POSIX: spawn the child as a process-group leader and route every kill
57
76
  * (parent-signal forwarding, abort, escalation) to the whole GROUP, then
@@ -78,11 +97,11 @@ export declare function exec(command: string, args: string[], options?: ExecOpti
78
97
  /**
79
98
  * Callback for streaming output.
80
99
  */
81
- export type StreamCallback = (data: string) => void;
100
+ type StreamCallback = (data: string) => void;
82
101
  /**
83
102
  * Options for streaming command execution.
84
103
  */
85
- export interface StreamOptions extends ExecOptions {
104
+ interface StreamOptions extends ExecOptions, ProcessGroupOptions {
86
105
  /** Callback for stdout data */
87
106
  onStdout?: StreamCallback;
88
107
  /** Callback for stderr data */
@@ -124,6 +143,14 @@ export declare function trackChildClosure(): {
124
143
  * Resolves immediately when no children are active.
125
144
  */
126
145
  export declare function waitForActiveChildShutdown(timeoutMs: number): Promise<void>;
146
+ /** Options for {@link execInherit}. */
147
+ export interface InheritOptions extends ExecOptions, ProcessGroupOptions {
148
+ /** Grace period between the forwarded SIGTERM and the SIGKILL escalation (default 1500 ms). */
149
+ shutdownGraceMs?: number;
150
+ }
151
+ /** Options for {@link execInheritCapture}: the inherit path plus output mirroring. */
152
+ export interface InheritCaptureOptions extends InheritOptions, MirrorOptions {
153
+ }
127
154
  /**
128
155
  * Executes a command and inherits stdio (shows output directly).
129
156
  *
@@ -140,9 +167,7 @@ export declare function waitForActiveChildShutdown(timeoutMs: number): Promise<v
140
167
  * @param options - Execution options
141
168
  * @returns Exit code of the process
142
169
  */
143
- export declare function execInherit(command: string, args: string[], options?: ExecOptions & {
144
- shutdownGraceMs?: number;
145
- }): Promise<number>;
170
+ export declare function execInherit(command: string, args: string[], options?: InheritOptions): Promise<number>;
146
171
  /**
147
172
  * Wires parent-process SIGINT/SIGTERM to a child: first signal → child.kill
148
173
  * (SIGTERM) + grace timer; second matching signal → immediate SIGKILL; grace
@@ -162,9 +187,7 @@ export declare function installGracefulShutdownForwarder(child: ReturnType<typeo
162
187
  * @param options - Execution options
163
188
  * @returns Execution result with stdout, stderr, and exit code
164
189
  */
165
- export declare function execInheritCapture(command: string, args: string[], options?: ExecOptions & {
166
- shutdownGraceMs?: number;
167
- }): Promise<ExecResult>;
190
+ export declare function execInheritCapture(command: string, args: string[], options?: InheritCaptureOptions): Promise<ExecResult>;
168
191
  /** Per-line callback for smoke-run stream dispatch. */
169
192
  export type SmokeLineCallback = (line: string) => void;
170
193
  /**
@@ -175,11 +198,11 @@ export type SmokeLineCallback = (line: string) => void;
175
198
  * group. Inheriting `timeout` is a leaky trap — accepted by the type but
176
199
  * silently ignored, so a caller setting it gets no deadline at all.
177
200
  *
178
- * `processGroup` is omitted for the same reason: a smoke run is ALWAYS
179
- * detached on POSIX (`usesProcessGroup` is derived from `process.platform`
180
- * alone), so the field would be accepted and never read.
201
+ * {@link ProcessGroupOptions} is not mixed in for the same reason: a smoke
202
+ * run is ALWAYS detached on POSIX (`usesProcessGroup` is derived from
203
+ * `process.platform` alone), so the field would be accepted and never read.
181
204
  */
182
- export interface SmokeRunOptions extends Omit<ExecOptions, 'processGroup' | 'timeout'> {
205
+ interface SmokeRunOptions extends Omit<ExecOptions, 'timeout'>, MirrorOptions {
183
206
  /**
184
207
  * Hard deadline in milliseconds. When it elapses the child process
185
208
  * group is sent SIGTERM and, after `killGraceMs`, SIGKILL. The returned
@@ -199,16 +222,6 @@ export interface SmokeRunOptions extends Omit<ExecOptions, 'processGroup' | 'tim
199
222
  onStdoutLine?: SmokeLineCallback;
200
223
  /** Invoked once per complete line of stderr. Final partial line is flushed on close. */
201
224
  onStderrLine?: SmokeLineCallback;
202
- /**
203
- * Optional writable stream to mirror captured output to (e.g. an
204
- * operator-supplied `--capture-console` file). Writes happen inline
205
- * with line dispatch and the stream is NOT closed here — the caller
206
- * owns its lifecycle.
207
- */
208
- mirror?: {
209
- stdout?: NodeJS.WritableStream;
210
- stderr?: NodeJS.WritableStream;
211
- };
212
225
  }
213
226
  /** Result of {@link execSmokeRun}. */
214
227
  export interface SmokeRunResult extends ExecResult {
@@ -255,3 +268,4 @@ export declare function findExecutable(name: string): Promise<string | undefined
255
268
  * @returns True if the executable exists
256
269
  */
257
270
  export declare function executableExists(name: string): Promise<boolean>;
271
+ export {};