@bensandee/tooling 0.59.0 → 0.59.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 (2) hide show
  1. package/dist/bin.mjs +93 -112
  2. package/package.json +1 -1
package/dist/bin.mjs CHANGED
@@ -1330,6 +1330,11 @@ function buildWorkflowYaml(options) {
1330
1330
  function actionsExpr(expr) {
1331
1331
  return `\${{ ${expr} }}`;
1332
1332
  }
1333
+ const MAIN_BRANCH_REF = "refs/heads/main";
1334
+ /** `if:` condition that gates a step to push events on the default branch. */
1335
+ const IS_MAIN_BRANCH = `github.ref == '${MAIN_BRANCH_REF}'`;
1336
+ /** Negated form for concurrency `cancel-in-progress` and similar uses. */
1337
+ const IS_NOT_MAIN_BRANCH = `github.ref != '${MAIN_BRANCH_REF}'`;
1333
1338
  function hasEnginesNode(ctx) {
1334
1339
  const raw = ctx.read("package.json");
1335
1340
  if (!raw) return false;
@@ -1473,7 +1478,7 @@ function hasReleaseAssets(ctx) {
1473
1478
  return false;
1474
1479
  }
1475
1480
  }
1476
- const ARCHIVE_DIR$1 = ".tooling-archived";
1481
+ const ARCHIVE_DIR$2 = ".tooling-archived";
1477
1482
  async function generateDeployCi(ctx) {
1478
1483
  const filePath = "deploy-ci";
1479
1484
  if (!ctx.config.publishDocker || ctx.config.ci === "none") return {
@@ -1486,12 +1491,12 @@ async function generateDeployCi(ctx) {
1486
1491
  if (ctx.config.releaseStrategy === "simple") {
1487
1492
  const existing = ctx.read(workflowPath);
1488
1493
  if (existing !== void 0) {
1489
- ctx.write(`${ARCHIVE_DIR$1}/${workflowPath}`, existing);
1494
+ ctx.write(`${ARCHIVE_DIR$2}/${workflowPath}`, existing);
1490
1495
  ctx.remove(workflowPath);
1491
1496
  return {
1492
1497
  filePath: workflowPath,
1493
1498
  action: "archived",
1494
- description: `Moved to ${ARCHIVE_DIR$1}/${workflowPath} (docker publish runs in release.yml for simple strategy)`
1499
+ description: `Moved to ${ARCHIVE_DIR$2}/${workflowPath} (docker publish runs in release.yml for simple strategy)`
1495
1500
  };
1496
1501
  }
1497
1502
  return {
@@ -1593,7 +1598,7 @@ const PER_PACKAGE_DEV_DEPS = {
1593
1598
  "tsdown": "0.22.0",
1594
1599
  "typescript": "6.0.3",
1595
1600
  "vitest": "4.1.5",
1596
- "pnpm": "11.1.1"
1601
+ "pnpm": "11.1.2"
1597
1602
  }["@types/node"],
1598
1603
  tsdown: {
1599
1604
  "@changesets/cli": "2.31.0",
@@ -1609,7 +1614,7 @@ const PER_PACKAGE_DEV_DEPS = {
1609
1614
  "tsdown": "0.22.0",
1610
1615
  "typescript": "6.0.3",
1611
1616
  "vitest": "4.1.5",
1612
- "pnpm": "11.1.1"
1617
+ "pnpm": "11.1.2"
1613
1618
  }["tsdown"],
1614
1619
  typescript: {
1615
1620
  "@changesets/cli": "2.31.0",
@@ -1625,7 +1630,7 @@ const PER_PACKAGE_DEV_DEPS = {
1625
1630
  "tsdown": "0.22.0",
1626
1631
  "typescript": "6.0.3",
1627
1632
  "vitest": "4.1.5",
1628
- "pnpm": "11.1.1"
1633
+ "pnpm": "11.1.2"
1629
1634
  }["typescript"],
1630
1635
  vitest: {
1631
1636
  "@changesets/cli": "2.31.0",
@@ -1641,7 +1646,7 @@ const PER_PACKAGE_DEV_DEPS = {
1641
1646
  "tsdown": "0.22.0",
1642
1647
  "typescript": "6.0.3",
1643
1648
  "vitest": "4.1.5",
1644
- "pnpm": "11.1.1"
1649
+ "pnpm": "11.1.2"
1645
1650
  }["vitest"]
1646
1651
  };
1647
1652
  /** DevDeps that belong at the root regardless of structure. */
@@ -1660,7 +1665,7 @@ const ROOT_DEV_DEPS = {
1660
1665
  "tsdown": "0.22.0",
1661
1666
  "typescript": "6.0.3",
1662
1667
  "vitest": "4.1.5",
1663
- "pnpm": "11.1.1"
1668
+ "pnpm": "11.1.2"
1664
1669
  }["knip"],
1665
1670
  lefthook: {
1666
1671
  "@changesets/cli": "2.31.0",
@@ -1676,7 +1681,7 @@ const ROOT_DEV_DEPS = {
1676
1681
  "tsdown": "0.22.0",
1677
1682
  "typescript": "6.0.3",
1678
1683
  "vitest": "4.1.5",
1679
- "pnpm": "11.1.1"
1684
+ "pnpm": "11.1.2"
1680
1685
  }["lefthook"],
1681
1686
  oxlint: {
1682
1687
  "@changesets/cli": "2.31.0",
@@ -1692,7 +1697,7 @@ const ROOT_DEV_DEPS = {
1692
1697
  "tsdown": "0.22.0",
1693
1698
  "typescript": "6.0.3",
1694
1699
  "vitest": "4.1.5",
1695
- "pnpm": "11.1.1"
1700
+ "pnpm": "11.1.2"
1696
1701
  }["oxlint"]
1697
1702
  };
1698
1703
  /**
@@ -1733,7 +1738,7 @@ function addReleaseDeps(deps, config) {
1733
1738
  "tsdown": "0.22.0",
1734
1739
  "typescript": "6.0.3",
1735
1740
  "vitest": "4.1.5",
1736
- "pnpm": "11.1.1"
1741
+ "pnpm": "11.1.2"
1737
1742
  }["release-it"];
1738
1743
  if (config.structure === "monorepo") deps["@release-it/bumper"] = {
1739
1744
  "@changesets/cli": "2.31.0",
@@ -1749,7 +1754,7 @@ function addReleaseDeps(deps, config) {
1749
1754
  "tsdown": "0.22.0",
1750
1755
  "typescript": "6.0.3",
1751
1756
  "vitest": "4.1.5",
1752
- "pnpm": "11.1.1"
1757
+ "pnpm": "11.1.2"
1753
1758
  }["@release-it/bumper"];
1754
1759
  break;
1755
1760
  case "simple":
@@ -1767,7 +1772,7 @@ function addReleaseDeps(deps, config) {
1767
1772
  "tsdown": "0.22.0",
1768
1773
  "typescript": "6.0.3",
1769
1774
  "vitest": "4.1.5",
1770
- "pnpm": "11.1.1"
1775
+ "pnpm": "11.1.2"
1771
1776
  }["commit-and-tag-version"];
1772
1777
  break;
1773
1778
  case "changesets":
@@ -1785,7 +1790,7 @@ function addReleaseDeps(deps, config) {
1785
1790
  "tsdown": "0.22.0",
1786
1791
  "typescript": "6.0.3",
1787
1792
  "vitest": "4.1.5",
1788
- "pnpm": "11.1.1"
1793
+ "pnpm": "11.1.2"
1789
1794
  }["@changesets/cli"];
1790
1795
  break;
1791
1796
  }
@@ -1809,7 +1814,7 @@ async function generatePackageJson(ctx) {
1809
1814
  const devDeps = { ...ROOT_DEV_DEPS };
1810
1815
  if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
1811
1816
  devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.11.2";
1812
- devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.59.0";
1817
+ devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.59.1";
1813
1818
  if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.13.0";
1814
1819
  if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
1815
1820
  "@changesets/cli": "2.31.0",
@@ -1825,7 +1830,7 @@ async function generatePackageJson(ctx) {
1825
1830
  "tsdown": "0.22.0",
1826
1831
  "typescript": "6.0.3",
1827
1832
  "vitest": "4.1.5",
1828
- "pnpm": "11.1.1"
1833
+ "pnpm": "11.1.2"
1829
1834
  }["oxfmt"];
1830
1835
  if (ctx.config.formatter === "prettier") devDeps["prettier"] = {
1831
1836
  "@changesets/cli": "2.31.0",
@@ -1841,7 +1846,7 @@ async function generatePackageJson(ctx) {
1841
1846
  "tsdown": "0.22.0",
1842
1847
  "typescript": "6.0.3",
1843
1848
  "vitest": "4.1.5",
1844
- "pnpm": "11.1.1"
1849
+ "pnpm": "11.1.2"
1845
1850
  }["prettier"];
1846
1851
  addReleaseDeps(devDeps, ctx.config);
1847
1852
  if (existing) {
@@ -1913,7 +1918,7 @@ async function generatePackageJson(ctx) {
1913
1918
  "tsdown": "0.22.0",
1914
1919
  "typescript": "6.0.3",
1915
1920
  "vitest": "4.1.5",
1916
- "pnpm": "11.1.1"
1921
+ "pnpm": "11.1.2"
1917
1922
  }["pnpm"];
1918
1923
  const desiredPm = pinnedPnpm ? `pnpm@${pinnedPnpm}` : void 0;
1919
1924
  if (desiredPm) {
@@ -1965,7 +1970,7 @@ async function generatePackageJson(ctx) {
1965
1970
  "tsdown": "0.22.0",
1966
1971
  "typescript": "6.0.3",
1967
1972
  "vitest": "4.1.5",
1968
- "pnpm": "11.1.1"
1973
+ "pnpm": "11.1.2"
1969
1974
  }["pnpm"]}`
1970
1975
  };
1971
1976
  ctx.write(filePath, JSON.stringify(pkg, null, 2) + "\n");
@@ -3385,7 +3390,7 @@ function hookSecretEnv(secrets) {
3385
3390
  }
3386
3391
  /** Step that runs after release with post-release webhook env wired up. */
3387
3392
  function postReleaseHookStep(opts) {
3388
- const ifCondition = opts?.condition ?? (opts?.guardMain ? "github.ref == 'refs/heads/main'" : void 0);
3393
+ const ifCondition = opts?.condition ?? (opts?.guardMain ? IS_MAIN_BRANCH : void 0);
3389
3394
  return { step: {
3390
3395
  name: "Post-release hook",
3391
3396
  ...ifCondition && { if: ifCondition },
@@ -3566,12 +3571,31 @@ async function generateReleaseCi(ctx) {
3566
3571
  }
3567
3572
  //#endregion
3568
3573
  //#region src/generators/ci.ts
3574
+ function coverageHistorySteps() {
3575
+ return [
3576
+ { step: {
3577
+ name: "Print coverage summary",
3578
+ if: IS_MAIN_BRANCH,
3579
+ run: "pnpm exec bst coverage:summary"
3580
+ } },
3581
+ { step: {
3582
+ name: "Append record to bst/coverage-metrics branch",
3583
+ if: IS_MAIN_BRANCH,
3584
+ run: "pnpm exec bst coverage:record"
3585
+ } },
3586
+ { step: {
3587
+ name: "Show recent coverage trend",
3588
+ if: IS_MAIN_BRANCH,
3589
+ run: "pnpm exec bst coverage:status --limit 10"
3590
+ } }
3591
+ ];
3592
+ }
3569
3593
  /** Build the release step for the check job (changesets strategy). */
3570
3594
  function changesetsReleaseStep(ci, publishesNpm) {
3571
3595
  if (ci === "github") return { step: {
3572
3596
  id: "release",
3573
3597
  uses: "changesets/action@v1",
3574
- if: "github.ref == 'refs/heads/main'",
3598
+ if: IS_MAIN_BRANCH,
3575
3599
  with: {
3576
3600
  publish: "pnpm changeset publish",
3577
3601
  version: "pnpm changeset version"
@@ -3596,9 +3620,11 @@ function changesetsReleaseStep(ci, publishesNpm) {
3596
3620
  }
3597
3621
  const CI_CONCURRENCY = {
3598
3622
  group: `ci-${actionsExpr("github.ref")}`,
3599
- "cancel-in-progress": actionsExpr("github.ref != 'refs/heads/main'")
3623
+ "cancel-in-progress": actionsExpr(IS_NOT_MAIN_BRANCH)
3600
3624
  };
3601
- function checkSteps(nodeVersionYaml, publishesNpm) {
3625
+ function checkSteps(nodeVersionYaml, publishesNpm, withCoverage) {
3626
+ const isNodeVersionFile = nodeVersionYaml.startsWith("node-version-file");
3627
+ const checkCommand = withCoverage ? "pnpm ci:check --with-coverage" : "pnpm ci:check";
3602
3628
  return [
3603
3629
  { step: {
3604
3630
  uses: "actions/checkout@v6",
@@ -3608,7 +3634,7 @@ function checkSteps(nodeVersionYaml, publishesNpm) {
3608
3634
  { step: {
3609
3635
  uses: "actions/setup-node@v6",
3610
3636
  with: {
3611
- ...nodeVersionYaml.startsWith("node-version-file") ? { "node-version-file": "package.json" } : { "node-version": "24" },
3637
+ ...isNodeVersionFile ? { "node-version-file": "package.json" } : { "node-version": "24" },
3612
3638
  cache: "pnpm",
3613
3639
  ...publishesNpm && { "registry-url": actionsExpr("vars.NPM_REGISTRY_URL || 'https://registry.npmjs.org'") }
3614
3640
  }
@@ -3616,7 +3642,7 @@ function checkSteps(nodeVersionYaml, publishesNpm) {
3616
3642
  { step: { run: "pnpm install --frozen-lockfile" } },
3617
3643
  { step: {
3618
3644
  name: "Run all checks",
3619
- run: "pnpm ci:check"
3645
+ run: checkCommand
3620
3646
  } }
3621
3647
  ];
3622
3648
  }
@@ -3637,6 +3663,8 @@ async function generateCi(ctx) {
3637
3663
  const publishesNpm = ctx.config.publishNpm === true;
3638
3664
  const hookCommand = getPostReleaseHookCommand(ctx);
3639
3665
  const hookSecrets = getPostReleaseHookSecrets(ctx);
3666
+ const coverage = resolveCoverageConfigFromContext(ctx, ctx.config.setupVitest);
3667
+ const emitCoverageSteps = coverage.historyEnabled;
3640
3668
  const hasDocker = isChangesets && hasDockerPackages(ctx);
3641
3669
  const hasAssets = isChangesets && hasReleaseAssets(ctx);
3642
3670
  const registryDerivable = hasDocker && hasRepositoryUrl(ctx);
@@ -3649,7 +3677,8 @@ async function generateCi(ctx) {
3649
3677
  releaseEnv["RELEASE_TOKEN"] = actionsExpr("secrets.RELEASE_TOKEN");
3650
3678
  }
3651
3679
  const steps = [
3652
- ...checkSteps(nodeVersionYaml, isChangesets && publishesNpm),
3680
+ ...checkSteps(nodeVersionYaml, isChangesets && publishesNpm, coverage.enabled),
3681
+ ...emitCoverageSteps ? coverageHistorySteps() : [],
3653
3682
  ...isChangesets ? [changesetsReleaseStep(ctx.config.ci, publishesNpm)] : [],
3654
3683
  ...hasAssets ? [{ step: {
3655
3684
  name: "Upload Release Assets",
@@ -3679,6 +3708,7 @@ async function generateCi(ctx) {
3679
3708
  },
3680
3709
  pull_request: null
3681
3710
  },
3711
+ ...emitCoverageSteps && { permissions: { contents: "write" } },
3682
3712
  enableEmailNotifications: isForgejo,
3683
3713
  ...isChangesets && { concurrency: CI_CONCURRENCY },
3684
3714
  jobName: "check",
@@ -4301,7 +4331,7 @@ function buildConfig$1(formatter) {
4301
4331
  ""
4302
4332
  ].join("\n");
4303
4333
  }
4304
- const ARCHIVE_DIR = ".tooling-archived";
4334
+ const ARCHIVE_DIR$1 = ".tooling-archived";
4305
4335
  /** Common client-side git hooks that husky may have configured. */
4306
4336
  const HUSKY_HOOK_NAMES = [
4307
4337
  "pre-commit",
@@ -4332,12 +4362,12 @@ function archiveHuskyHooks(ctx, results) {
4332
4362
  const huskyPath = `.husky/${hook}`;
4333
4363
  const existing = ctx.read(huskyPath);
4334
4364
  if (existing !== void 0) {
4335
- ctx.write(`${ARCHIVE_DIR}/${huskyPath}`, existing);
4365
+ ctx.write(`${ARCHIVE_DIR$1}/${huskyPath}`, existing);
4336
4366
  ctx.remove(huskyPath);
4337
4367
  results.push({
4338
4368
  filePath: huskyPath,
4339
4369
  action: "archived",
4340
- description: `Moved to ${ARCHIVE_DIR}/${huskyPath}`
4370
+ description: `Moved to ${ARCHIVE_DIR$1}/${huskyPath}`
4341
4371
  });
4342
4372
  found = true;
4343
4373
  }
@@ -4350,12 +4380,12 @@ function archiveLintStagedConfigs(ctx, results) {
4350
4380
  for (const lsPath of LINT_STAGED_CONFIG_PATHS) {
4351
4381
  const existing = ctx.read(lsPath);
4352
4382
  if (existing !== void 0) {
4353
- ctx.write(`${ARCHIVE_DIR}/${lsPath}`, existing);
4383
+ ctx.write(`${ARCHIVE_DIR$1}/${lsPath}`, existing);
4354
4384
  ctx.remove(lsPath);
4355
4385
  results.push({
4356
4386
  filePath: lsPath,
4357
4387
  action: "archived",
4358
- description: `Moved to ${ARCHIVE_DIR}/${lsPath}`
4388
+ description: `Moved to ${ARCHIVE_DIR$1}/${lsPath}`
4359
4389
  });
4360
4390
  found = true;
4361
4391
  }
@@ -4535,43 +4565,12 @@ async function generateVscodeSettings(ctx) {
4535
4565
  }
4536
4566
  //#endregion
4537
4567
  //#region src/generators/coverage-ci.ts
4538
- function coverageSteps(nodeVersionYaml) {
4539
- return [
4540
- { step: {
4541
- uses: "actions/checkout@v6",
4542
- with: { "fetch-depth": 0 }
4543
- } },
4544
- { step: { uses: "pnpm/action-setup@v5" } },
4545
- { step: {
4546
- uses: "actions/setup-node@v6",
4547
- with: {
4548
- ...nodeVersionYaml.startsWith("node-version-file") ? { "node-version-file": "package.json" } : { "node-version": "24" },
4549
- cache: "pnpm"
4550
- }
4551
- } },
4552
- { step: { run: "pnpm install --frozen-lockfile" } },
4553
- { step: {
4554
- name: "Build",
4555
- run: "pnpm build"
4556
- } },
4557
- { step: {
4558
- name: "Run tests with coverage",
4559
- run: "pnpm test:coverage"
4560
- } },
4561
- { step: {
4562
- name: "Print coverage summary",
4563
- run: "pnpm exec bst coverage:summary"
4564
- } },
4565
- { step: {
4566
- name: "Append record to bst/coverage-metrics branch",
4567
- run: "pnpm exec bst coverage:record"
4568
- } },
4569
- { step: {
4570
- name: "Show recent coverage trend",
4571
- run: "pnpm exec bst coverage:status --limit 10"
4572
- } }
4573
- ];
4574
- }
4568
+ const ARCHIVE_DIR = ".tooling-archived";
4569
+ /**
4570
+ * Cleanup-only generator: coverage steps now run inline in ci.yml (see
4571
+ * generateCi). Any legacy coverage.yml left over from a previous version is
4572
+ * archived to .tooling-archived/ on the next repo:sync.
4573
+ */
4575
4574
  async function generateCoverageCi(ctx) {
4576
4575
  const filePath = "coverage-ci";
4577
4576
  if (ctx.config.ci === "none") return {
@@ -4579,49 +4578,21 @@ async function generateCoverageCi(ctx) {
4579
4578
  action: "skipped",
4580
4579
  description: "CI workflow not requested"
4581
4580
  };
4582
- const config = resolveCoverageConfigFromContext(ctx, ctx.config.setupVitest);
4583
- if (!config.enabled || !config.historyEnabled) return {
4584
- filePath,
4585
- action: "skipped",
4586
- description: "Coverage tracking disabled"
4587
- };
4588
- const isGitHub = ctx.config.ci === "github";
4589
- const isForgejo = !isGitHub;
4590
- const workflowPath = isGitHub ? ".github/workflows/coverage.yml" : ".forgejo/workflows/coverage.yml";
4591
- const nodeVersionYaml = computeNodeVersionYaml(ctx);
4592
- const content = buildWorkflowYaml({
4593
- ci: ctx.config.ci,
4594
- name: "Coverage",
4595
- on: { push: {
4596
- branches: ["main"],
4597
- "tags-ignore": ["**"]
4598
- } },
4599
- permissions: { contents: "write" },
4600
- enableEmailNotifications: isForgejo,
4601
- jobName: "coverage",
4602
- steps: coverageSteps(nodeVersionYaml)
4603
- });
4604
- const alreadyExists = ctx.exists(workflowPath);
4605
- const existing = alreadyExists ? ctx.read(workflowPath) : void 0;
4606
- if (existing) {
4607
- if (isToolingIgnored(existing)) return {
4608
- filePath: workflowPath,
4609
- action: "skipped",
4610
- description: "Coverage workflow has ignore comment"
4611
- };
4612
- if (normalizeWorkflow(existing) === normalizeWorkflow(content)) return {
4581
+ const workflowPath = ctx.config.ci === "github" ? ".github/workflows/coverage.yml" : ".forgejo/workflows/coverage.yml";
4582
+ const existing = ctx.read(workflowPath);
4583
+ if (existing !== void 0) {
4584
+ ctx.write(`${ARCHIVE_DIR}/${workflowPath}`, existing);
4585
+ ctx.remove(workflowPath);
4586
+ return {
4613
4587
  filePath: workflowPath,
4614
- action: "skipped",
4615
- description: "Coverage workflow already up to date"
4588
+ action: "archived",
4589
+ description: `Moved to ${ARCHIVE_DIR}/${workflowPath} (coverage now runs inline in ci.yml)`
4616
4590
  };
4617
4591
  }
4618
- const withPinnedActions = preservePinnedActions(preserveDevBinaryPath(content, existing), existing);
4619
- const final = existing ? insertCustomBlocks(withPinnedActions, extractCustomBlocks(existing)) : withPinnedActions;
4620
- ctx.write(workflowPath, final);
4621
4592
  return {
4622
- filePath: workflowPath,
4623
- action: alreadyExists ? "updated" : "created",
4624
- description: `Generated ${isGitHub ? "GitHub" : "Forgejo"} Actions coverage workflow`
4593
+ filePath,
4594
+ action: "skipped",
4595
+ description: "Coverage runs inline in ci.yml"
4625
4596
  };
4626
4597
  }
4627
4598
  //#endregion
@@ -4849,7 +4820,7 @@ async function runGenerators(ctx) {
4849
4820
  function generateMigratePrompt(results, config, detected) {
4850
4821
  const sections = [];
4851
4822
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4852
- sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.59.0 repo:sync\` on ${timestamp}_\n`);
4823
+ sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.59.1 repo:sync\` on ${timestamp}_\n`);
4853
4824
  const changed = results.filter((r) => r.action === "created" || r.action === "updated" || r.action === "archived");
4854
4825
  if (changed.length > 0) {
4855
4826
  const items = changed.map((r) => {
@@ -6440,6 +6411,9 @@ function runRunChecks(targetDir, options = {}) {
6440
6411
  const allChecks = [...CHECKS, ...add.map((name) => ({ name }))];
6441
6412
  const failures = [];
6442
6413
  const notDefined = [];
6414
+ const withCoverage = options.withCoverage ?? false;
6415
+ const useCoverageScript = withCoverage && definedScripts.has("test:coverage");
6416
+ if (withCoverage && !useCoverageScript) log.warn("--with-coverage requested but test:coverage script is not defined; falling back to test");
6443
6417
  for (const check of allChecks) {
6444
6418
  if (shouldSkip(check.name, skip)) continue;
6445
6419
  if (!definedScripts.has(check.name)) {
@@ -6449,7 +6423,8 @@ function runRunChecks(targetDir, options = {}) {
6449
6423
  } else notDefined.push(check.name);
6450
6424
  continue;
6451
6425
  }
6452
- const cmd = check.args ? `pnpm run ${check.name} ${check.args}` : `pnpm run ${check.name}`;
6426
+ const scriptName = check.name === "test" && useCoverageScript ? "test:coverage" : check.name;
6427
+ const cmd = check.args ? `pnpm run ${scriptName} ${check.args}` : `pnpm run ${scriptName}`;
6453
6428
  debug(vc, `Running: ${cmd} (in ${targetDir})`);
6454
6429
  reporter.groupStart(check.name);
6455
6430
  const start = Date.now();
@@ -6502,6 +6477,11 @@ const runChecksCommand = defineCommand({
6502
6477
  type: "boolean",
6503
6478
  description: "Emit detailed debug logging",
6504
6479
  required: false
6480
+ },
6481
+ "with-coverage": {
6482
+ type: "boolean",
6483
+ description: "Run the test step with coverage (uses pnpm run test:coverage when defined)",
6484
+ required: false
6505
6485
  }
6506
6486
  },
6507
6487
  run({ args }) {
@@ -6509,7 +6489,8 @@ const runChecksCommand = defineCommand({
6509
6489
  skip: args.skip ? new Set(args.skip.split(",").map((s) => s.trim())) : void 0,
6510
6490
  add: args.add ? args.add.split(",").map((s) => s.trim()) : void 0,
6511
6491
  failFast: args["fail-fast"] ? true : void 0,
6512
- verbose: args.verbose === true || isEnvVerbose()
6492
+ verbose: args.verbose === true || isEnvVerbose(),
6493
+ withCoverage: args["with-coverage"] === true
6513
6494
  });
6514
6495
  process.exitCode = exitCode;
6515
6496
  }
@@ -8319,7 +8300,7 @@ const out = (msg) => console.log(msg);
8319
8300
  const main = defineCommand({
8320
8301
  meta: {
8321
8302
  name: "bst",
8322
- version: "0.59.0",
8303
+ version: "0.59.1",
8323
8304
  description: "Bootstrap and maintain standardized TypeScript project tooling"
8324
8305
  },
8325
8306
  subCommands: {
@@ -8391,7 +8372,7 @@ const main = defineCommand({
8391
8372
  })
8392
8373
  }
8393
8374
  });
8394
- console.log(`@bensandee/tooling v0.59.0`);
8375
+ console.log(`@bensandee/tooling v0.59.1`);
8395
8376
  async function run() {
8396
8377
  await runMain(main);
8397
8378
  process.exit(process.exitCode ?? 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bensandee/tooling",
3
- "version": "0.59.0",
3
+ "version": "0.59.1",
4
4
  "description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
5
5
  "license": "MIT",
6
6
  "repository": {