@smoothbricks/cli 0.4.0 → 0.4.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.
package/dist/lib/run.d.ts CHANGED
@@ -6,6 +6,7 @@ export declare function runResult(command: string, args: string[], cwd: string,
6
6
  stdout: string;
7
7
  stderr: string;
8
8
  }>;
9
+ export declare function printCommandOutput(stdout: string, stderr: string): void;
9
10
  export declare function findRepoRoot(): Promise<string>;
10
11
  export declare function decode(bytes: Uint8Array): string;
11
12
  //# sourceMappingURL=run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAMA,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,KAAK,UAAQ,EACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAY/D;AAuCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEhD"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/lib/run.ts"],"names":[],"mappings":"AAMA,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnH;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,KAAK,UAAQ,EACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAY/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOvE;AAuCD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpD;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEhD"}
package/dist/lib/run.js CHANGED
@@ -49,6 +49,14 @@ export async function runResult(command, args, cwd, env) {
49
49
  stderr: decode(result.stderr),
50
50
  };
51
51
  }
52
+ export function printCommandOutput(stdout, stderr) {
53
+ if (stdout.length > 0) {
54
+ console.log(trimTrailingNewline(stdout));
55
+ }
56
+ if (stderr.length > 0) {
57
+ console.error(trimTrailingNewline(stderr));
58
+ }
59
+ }
52
60
  function mergeEnv(env) {
53
61
  const merged = {};
54
62
  for (const [key, value] of Object.entries(process.env)) {
@@ -94,3 +102,6 @@ export async function findRepoRoot() {
94
102
  export function decode(bytes) {
95
103
  return new TextDecoder().decode(bytes);
96
104
  }
105
+ function trimTrailingNewline(value) {
106
+ return value.endsWith('\n') ? value.slice(0, -1) : value;
107
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"nx-sync.d.ts","sourceRoot":"","sources":["../../src/monorepo/nx-sync.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5E;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnF"}
1
+ {"version":3,"file":"nx-sync.d.ts","sourceRoot":"","sources":["../../src/monorepo/nx-sync.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5E;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAWnF"}
@@ -1,11 +1,25 @@
1
- import { runStatus } from '../lib/run.js';
1
+ import { printCommandOutput, runResult, runStatus } from '../lib/run.js';
2
2
  export async function fixNxSync(root, verbose = false) {
3
- const status = await runStatus('nx', ['sync'], root, !verbose);
3
+ const result = verbose
4
+ ? { exitCode: await runStatus('nx', ['sync'], root, false), stdout: '', stderr: '' }
5
+ : await runResult('nx', ['sync'], root);
6
+ const status = result.exitCode;
4
7
  if (status !== 0) {
8
+ if (!verbose) {
9
+ printCommandOutput(result.stdout, result.stderr);
10
+ }
5
11
  throw new Error(`nx sync failed with exit code ${status}`);
6
12
  }
7
13
  }
8
14
  export async function validateNxSync(root, verbose = false) {
9
- const status = await runStatus('nx', ['sync:check'], root, !verbose);
10
- return status === 0 ? 0 : 1;
15
+ const result = verbose
16
+ ? { exitCode: await runStatus('nx', ['sync:check'], root, false), stdout: '', stderr: '' }
17
+ : await runResult('nx', ['sync:check'], root);
18
+ if (result.exitCode === 0) {
19
+ return 0;
20
+ }
21
+ if (!verbose) {
22
+ printCommandOutput(result.stdout, result.stderr);
23
+ }
24
+ return 1;
11
25
  }
@@ -1,5 +1,10 @@
1
1
  export interface PackageHygieneShell {
2
2
  run(command: string, args: string[], cwd: string): Promise<void>;
3
+ runResult?(command: string, args: string[], cwd: string): Promise<{
4
+ exitCode: number;
5
+ stdout: string;
6
+ stderr: string;
7
+ }>;
3
8
  runStatus(command: string, args: string[], cwd: string, quiet?: boolean): Promise<number>;
4
9
  }
5
10
  export declare function fixPackageHygiene(root: string, verboseOrShell?: boolean | PackageHygieneShell, maybeShell?: PackageHygieneShell): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"package-hygiene.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-hygiene.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3F;AAID,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,OAAO,GAAG,mBAA2B,EACrD,UAAU,GAAE,mBAAkC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,OAAO,GAAG,mBAA2B,EACrD,UAAU,GAAE,mBAAkC,GAC7C,OAAO,CAAC,MAAM,CAAC,CASjB"}
1
+ {"version":3,"file":"package-hygiene.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-hygiene.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,SAAS,CAAC,CACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3F;AAID,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,OAAO,GAAG,mBAA2B,EACrD,UAAU,GAAE,mBAAkC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,OAAO,GAAG,mBAA2B,EACrD,UAAU,GAAE,mBAAkC,GAC7C,OAAO,CAAC,MAAM,CAAC,CAajB"}
@@ -1,20 +1,34 @@
1
- import { run, runStatus } from '../lib/run.js';
2
- const defaultShell = { run, runStatus };
1
+ import { printCommandOutput, run, runResult, runStatus } from '../lib/run.js';
2
+ const defaultShell = { run, runResult, runStatus };
3
3
  export async function fixPackageHygiene(root, verboseOrShell = false, maybeShell = defaultShell) {
4
4
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
5
5
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
6
- const status = await shell.runStatus('sherif', ['-f', '--select', 'highest'], root, !verbose);
6
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['-f', '--select', 'highest'], root, verbose);
7
+ const status = result.exitCode;
7
8
  if (status !== 0) {
9
+ if (!verbose) {
10
+ printCommandOutput(result.stdout, result.stderr);
11
+ }
8
12
  throw new Error(`sherif -f --select highest failed with exit code ${status}`);
9
13
  }
10
14
  }
11
15
  export async function validatePackageHygiene(root, verboseOrShell = false, maybeShell = defaultShell) {
12
16
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
13
17
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
14
- const status = await shell.runStatus('sherif', ['--fail-on-warnings'], root, !verbose);
18
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['--fail-on-warnings'], root, verbose);
19
+ const status = result.exitCode;
15
20
  if (status !== 0) {
21
+ if (!verbose) {
22
+ printCommandOutput(result.stdout, result.stderr);
23
+ }
16
24
  console.error('sherif package hygiene validation failed');
17
25
  return 1;
18
26
  }
19
27
  return 0;
20
28
  }
29
+ async function runPackageHygieneCommand(shell, command, args, root, verbose) {
30
+ if (!verbose && shell.runResult) {
31
+ return shell.runResult(command, args, root);
32
+ }
33
+ return { exitCode: await shell.runStatus(command, args, root, !verbose), stdout: '', stderr: '' };
34
+ }
@@ -3,7 +3,7 @@ import { join } from 'node:path';
3
3
  import { publint } from 'publint';
4
4
  import { formatMessage } from 'publint/utils';
5
5
  import { isRecord } from '../lib/json.js';
6
- import { runResult, runStatus } from '../lib/run.js';
6
+ import { printCommandOutput, runResult } from '../lib/run.js';
7
7
  import { listPublicPackages } from '../lib/workspace.js';
8
8
  import { readPackedPackageJson, validatePackedWorkspaceDependencies } from './packed-manifest.js';
9
9
  export async function validatePackedPublicPackages(root) {
@@ -116,9 +116,10 @@ async function packPackage(root, pkg) {
116
116
  const tarballName = `.smoo-${process.pid}-${Date.now()}.tgz`;
117
117
  const tarballPath = join(root, tarballName);
118
118
  try {
119
- const status = await runStatus('bun', ['pm', 'pack', '--filename', tarballName, '--ignore-scripts', '--quiet'], packageDir, true);
120
- if (status !== 0) {
121
- throw new Error(`bun pm pack failed with exit code ${status}`);
119
+ const result = await runResult('bun', ['pm', 'pack', '--filename', tarballName, '--ignore-scripts', '--quiet'], packageDir);
120
+ if (result.exitCode !== 0) {
121
+ printCommandOutput(result.stdout, result.stderr);
122
+ throw new Error(`bun pm pack failed with exit code ${result.exitCode}`);
122
123
  }
123
124
  const bytes = new Uint8Array(readFileSync(tarballPath));
124
125
  return { path: tarballPath, arrayBuffer: bytes.slice().buffer };
@@ -1,6 +1,6 @@
1
1
  import { chmodSync, existsSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { runStatus } from '../../lib/run.js';
3
+ import { printCommandOutput, runResult, runStatus } from '../../lib/run.js';
4
4
  import { readProjectTargets } from '../../nx/index.js';
5
5
  import { syncBunLockfileVersions, validateBunLockfileVersions } from '../lockfile.js';
6
6
  import { validateManagedFiles } from '../managed-files.js';
@@ -221,10 +221,14 @@ async function runBuild(ctx, options = {}) {
221
221
  if (options.verbose) {
222
222
  printCheckHeading('build', true);
223
223
  }
224
- const status = await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, options.verbose !== true);
224
+ const result = options.verbose
225
+ ? { exitCode: await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, false), stdout: '', stderr: '' }
226
+ : await runResult('nx', ['run-many', '-t', 'build'], ctx.root);
227
+ const status = result.exitCode;
225
228
  if (status !== 0) {
226
229
  if (!options.verbose) {
227
230
  printCheckHeading('build', true);
231
+ printCommandOutput(result.stdout, result.stderr);
228
232
  }
229
233
  console.error('nx run-many -t build failed');
230
234
  printCheckStatus('build', 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smoothbricks/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "SmoothBricks monorepo automation CLI",
6
6
  "bin": {
package/src/lib/run.ts CHANGED
@@ -70,6 +70,15 @@ export async function runResult(
70
70
  };
71
71
  }
72
72
 
73
+ export function printCommandOutput(stdout: string, stderr: string): void {
74
+ if (stdout.length > 0) {
75
+ console.log(trimTrailingNewline(stdout));
76
+ }
77
+ if (stderr.length > 0) {
78
+ console.error(trimTrailingNewline(stderr));
79
+ }
80
+ }
81
+
73
82
  function mergeEnv(env: Record<string, string>): Record<string, string> {
74
83
  const merged: Record<string, string> = {};
75
84
  for (const [key, value] of Object.entries(process.env)) {
@@ -118,3 +127,7 @@ export async function findRepoRoot(): Promise<string> {
118
127
  export function decode(bytes: Uint8Array): string {
119
128
  return new TextDecoder().decode(bytes);
120
129
  }
130
+
131
+ function trimTrailingNewline(value: string): string {
132
+ return value.endsWith('\n') ? value.slice(0, -1) : value;
133
+ }
@@ -1,13 +1,27 @@
1
- import { runStatus } from '../lib/run.js';
1
+ import { printCommandOutput, runResult, runStatus } from '../lib/run.js';
2
2
 
3
3
  export async function fixNxSync(root: string, verbose = false): Promise<void> {
4
- const status = await runStatus('nx', ['sync'], root, !verbose);
4
+ const result = verbose
5
+ ? { exitCode: await runStatus('nx', ['sync'], root, false), stdout: '', stderr: '' }
6
+ : await runResult('nx', ['sync'], root);
7
+ const status = result.exitCode;
5
8
  if (status !== 0) {
9
+ if (!verbose) {
10
+ printCommandOutput(result.stdout, result.stderr);
11
+ }
6
12
  throw new Error(`nx sync failed with exit code ${status}`);
7
13
  }
8
14
  }
9
15
 
10
16
  export async function validateNxSync(root: string, verbose = false): Promise<number> {
11
- const status = await runStatus('nx', ['sync:check'], root, !verbose);
12
- return status === 0 ? 0 : 1;
17
+ const result = verbose
18
+ ? { exitCode: await runStatus('nx', ['sync:check'], root, false), stdout: '', stderr: '' }
19
+ : await runResult('nx', ['sync:check'], root);
20
+ if (result.exitCode === 0) {
21
+ return 0;
22
+ }
23
+ if (!verbose) {
24
+ printCommandOutput(result.stdout, result.stderr);
25
+ }
26
+ return 1;
13
27
  }
@@ -1,7 +1,12 @@
1
- import { describe, expect, it } from 'bun:test';
1
+ import { afterEach, describe, expect, it, spyOn } from 'bun:test';
2
2
  import { fixPackageHygiene, type PackageHygieneShell, validatePackageHygiene } from './package-hygiene.js';
3
3
 
4
4
  describe('package hygiene', () => {
5
+ afterEach(() => {
6
+ console.log = originalConsoleLog;
7
+ console.error = originalConsoleError;
8
+ });
9
+
5
10
  it('runs sherif in autofix mode and selects highest dependency versions', async () => {
6
11
  const shell = new RecordingShell();
7
12
 
@@ -17,8 +22,39 @@ describe('package hygiene', () => {
17
22
 
18
23
  expect(shell.statuses).toEqual([{ command: 'sherif', args: ['--fail-on-warnings'], cwd: '/repo' }]);
19
24
  });
25
+
26
+ it('prints captured sherif output when quiet validation fails', async () => {
27
+ const shell = new FailingResultShell('sherif stdout', 'sherif stderr');
28
+ const logs = captureConsoleLogs();
29
+ const errors = captureConsoleErrors();
30
+
31
+ const failures = await validatePackageHygiene('/repo', shell);
32
+
33
+ expect(failures).toBe(1);
34
+ expect(logs).toEqual(['sherif stdout']);
35
+ expect(errors).toEqual(['sherif stderr', 'sherif package hygiene validation failed']);
36
+ });
20
37
  });
21
38
 
39
+ const originalConsoleLog = console.log;
40
+ const originalConsoleError = console.error;
41
+
42
+ function captureConsoleLogs(): string[] {
43
+ const logs: string[] = [];
44
+ spyOn(console, 'log').mockImplementation((...args: unknown[]) => {
45
+ logs.push(args.join(' '));
46
+ });
47
+ return logs;
48
+ }
49
+
50
+ function captureConsoleErrors(): string[] {
51
+ const errors: string[] = [];
52
+ spyOn(console, 'error').mockImplementation((...args: unknown[]) => {
53
+ errors.push(args.join(' '));
54
+ });
55
+ return errors;
56
+ }
57
+
22
58
  class RecordingShell implements PackageHygieneShell {
23
59
  readonly runs: { command: string; args: string[]; cwd: string }[] = [];
24
60
  readonly statuses: { command: string; args: string[]; cwd: string }[] = [];
@@ -32,3 +68,20 @@ class RecordingShell implements PackageHygieneShell {
32
68
  return 0;
33
69
  }
34
70
  }
71
+
72
+ class FailingResultShell implements PackageHygieneShell {
73
+ constructor(
74
+ private readonly stdout: string,
75
+ private readonly stderr: string,
76
+ ) {}
77
+
78
+ async run(): Promise<void> {}
79
+
80
+ async runResult(): Promise<{ exitCode: number; stdout: string; stderr: string }> {
81
+ return { exitCode: 1, stdout: this.stdout, stderr: this.stderr };
82
+ }
83
+
84
+ async runStatus(): Promise<number> {
85
+ return 1;
86
+ }
87
+ }
@@ -1,11 +1,20 @@
1
- import { run, runStatus } from '../lib/run.js';
1
+ import { printCommandOutput, run, runResult, runStatus } from '../lib/run.js';
2
2
 
3
3
  export interface PackageHygieneShell {
4
4
  run(command: string, args: string[], cwd: string): Promise<void>;
5
+ runResult?(
6
+ command: string,
7
+ args: string[],
8
+ cwd: string,
9
+ ): Promise<{
10
+ exitCode: number;
11
+ stdout: string;
12
+ stderr: string;
13
+ }>;
5
14
  runStatus(command: string, args: string[], cwd: string, quiet?: boolean): Promise<number>;
6
15
  }
7
16
 
8
- const defaultShell: PackageHygieneShell = { run, runStatus };
17
+ const defaultShell: PackageHygieneShell = { run, runResult, runStatus };
9
18
 
10
19
  export async function fixPackageHygiene(
11
20
  root: string,
@@ -14,8 +23,12 @@ export async function fixPackageHygiene(
14
23
  ): Promise<void> {
15
24
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
16
25
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
17
- const status = await shell.runStatus('sherif', ['-f', '--select', 'highest'], root, !verbose);
26
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['-f', '--select', 'highest'], root, verbose);
27
+ const status = result.exitCode;
18
28
  if (status !== 0) {
29
+ if (!verbose) {
30
+ printCommandOutput(result.stdout, result.stderr);
31
+ }
19
32
  throw new Error(`sherif -f --select highest failed with exit code ${status}`);
20
33
  }
21
34
  }
@@ -27,10 +40,27 @@ export async function validatePackageHygiene(
27
40
  ): Promise<number> {
28
41
  const verbose = typeof verboseOrShell === 'boolean' ? verboseOrShell : false;
29
42
  const shell = typeof verboseOrShell === 'boolean' ? maybeShell : verboseOrShell;
30
- const status = await shell.runStatus('sherif', ['--fail-on-warnings'], root, !verbose);
43
+ const result = await runPackageHygieneCommand(shell, 'sherif', ['--fail-on-warnings'], root, verbose);
44
+ const status = result.exitCode;
31
45
  if (status !== 0) {
46
+ if (!verbose) {
47
+ printCommandOutput(result.stdout, result.stderr);
48
+ }
32
49
  console.error('sherif package hygiene validation failed');
33
50
  return 1;
34
51
  }
35
52
  return 0;
36
53
  }
54
+
55
+ async function runPackageHygieneCommand(
56
+ shell: PackageHygieneShell,
57
+ command: string,
58
+ args: string[],
59
+ root: string,
60
+ verbose: boolean,
61
+ ): Promise<{ exitCode: number; stdout: string; stderr: string }> {
62
+ if (!verbose && shell.runResult) {
63
+ return shell.runResult(command, args, root);
64
+ }
65
+ return { exitCode: await shell.runStatus(command, args, root, !verbose), stdout: '', stderr: '' };
66
+ }
@@ -3,7 +3,7 @@ import { join } from 'node:path';
3
3
  import { publint } from 'publint';
4
4
  import { formatMessage } from 'publint/utils';
5
5
  import { isRecord } from '../lib/json.js';
6
- import { runResult, runStatus } from '../lib/run.js';
6
+ import { printCommandOutput, runResult } from '../lib/run.js';
7
7
  import type { PackageInfo } from '../lib/workspace.js';
8
8
  import { listPublicPackages } from '../lib/workspace.js';
9
9
  import { readPackedPackageJson, validatePackedWorkspaceDependencies } from './packed-manifest.js';
@@ -142,14 +142,14 @@ async function packPackage(root: string, pkg: PackageInfo): Promise<{ path: stri
142
142
  const tarballName = `.smoo-${process.pid}-${Date.now()}.tgz`;
143
143
  const tarballPath = join(root, tarballName);
144
144
  try {
145
- const status = await runStatus(
145
+ const result = await runResult(
146
146
  'bun',
147
147
  ['pm', 'pack', '--filename', tarballName, '--ignore-scripts', '--quiet'],
148
148
  packageDir,
149
- true,
150
149
  );
151
- if (status !== 0) {
152
- throw new Error(`bun pm pack failed with exit code ${status}`);
150
+ if (result.exitCode !== 0) {
151
+ printCommandOutput(result.stdout, result.stderr);
152
+ throw new Error(`bun pm pack failed with exit code ${result.exitCode}`);
153
153
  }
154
154
  const bytes = new Uint8Array(readFileSync(tarballPath));
155
155
  return { path: tarballPath, arrayBuffer: bytes.slice().buffer };
@@ -1,6 +1,6 @@
1
1
  import { chmodSync, existsSync, statSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { runStatus } from '../../lib/run.js';
3
+ import { printCommandOutput, runResult, runStatus } from '../../lib/run.js';
4
4
  import { readProjectTargets } from '../../nx/index.js';
5
5
  import { syncBunLockfileVersions, validateBunLockfileVersions } from '../lockfile.js';
6
6
  import { validateManagedFiles } from '../managed-files.js';
@@ -315,10 +315,14 @@ async function runBuild(ctx: MonorepoContext, options: ValidatePackOptions = {})
315
315
  if (options.verbose) {
316
316
  printCheckHeading('build', true);
317
317
  }
318
- const status = await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, options.verbose !== true);
318
+ const result = options.verbose
319
+ ? { exitCode: await runStatus('nx', ['run-many', '-t', 'build'], ctx.root, false), stdout: '', stderr: '' }
320
+ : await runResult('nx', ['run-many', '-t', 'build'], ctx.root);
321
+ const status = result.exitCode;
319
322
  if (status !== 0) {
320
323
  if (!options.verbose) {
321
324
  printCheckHeading('build', true);
325
+ printCommandOutput(result.stdout, result.stderr);
322
326
  }
323
327
  console.error('nx run-many -t build failed');
324
328
  printCheckStatus('build', 1);