Skip to content

Commit df20acf

Browse files
syi0808claude
andcommitted
fix: use exit code instead of stderr to detect command failures
CLI tools (npm, git, jsr, ping) can write to stderr during normal operation, causing false errors. Replace `if (stderr) throw stderr` with `throwOnError: true` from tinyexec, which correctly uses exit codes. Update error checks for EOTP and ENEEDAUTH to use NonZeroExitError, and add regression tests for stderr tolerance. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 28b0856 commit df20acf

File tree

10 files changed

+216
-208
lines changed

10 files changed

+216
-208
lines changed

src/git.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ class GitError extends AbstractError {
88

99
export class Git {
1010
async git(args: string[]): Promise<string> {
11-
const { stdout, stderr } = await exec("git", args);
12-
13-
if (stderr) throw stderr;
11+
const { stdout } = await exec("git", args, { throwOnError: true });
1412

1513
return stdout;
1614
}

src/registry/custom-registry.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import { NpmRegistry } from "./npm.js";
44

55
export class CustomRegistry extends NpmRegistry {
66
async npm(args: string[]): Promise<string> {
7-
const { stdout, stderr } = await exec(
7+
const { stdout } = await exec(
88
"npm",
99
args.concat("--registry", this.registry),
10+
{ throwOnError: true },
1011
);
1112

12-
if (stderr) throw stderr;
13-
1413
return stdout;
1514
}
1615
}

src/registry/jsr.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ export class JsrRegisry extends Registry {
3333
}
3434

3535
protected async jsr(args: string[]): Promise<string> {
36-
const { stdout, stderr } = await exec("jsr", args);
37-
38-
if (stderr) throw stderr;
36+
const { stdout } = await exec("jsr", args, { throwOnError: true });
3937

4038
return stdout;
4139
}
@@ -56,13 +54,11 @@ export class JsrRegisry extends Registry {
5654

5755
async ping(): Promise<boolean> {
5856
try {
59-
const { stdout, stderr } = await exec("ping", [
60-
new URL(this.registry).hostname,
61-
"-c",
62-
"1",
63-
]);
64-
65-
if (stderr) throw stderr;
57+
const { stdout } = await exec(
58+
"ping",
59+
[new URL(this.registry).hostname, "-c", "1"],
60+
{ throwOnError: true },
61+
);
6662

6763
return stdout.includes("1 packets transmitted");
6864
} catch (error) {

src/registry/npm.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { exec } from "tinyexec";
1+
import { NonZeroExitError, exec } from "tinyexec";
22
import { AbstractError } from "../error.js";
33
import { getPackageJson } from "../utils/package.js";
44
import { isValidPackageName } from "../utils/package-name.js";
@@ -12,9 +12,7 @@ export class NpmRegistry extends Registry {
1212
registry = "https://registry.npmjs.org";
1313

1414
protected async npm(args: string[]): Promise<string> {
15-
const { stdout, stderr } = await exec("npm", args);
16-
17-
if (stderr) throw stderr;
15+
const { stdout } = await exec("npm", args, { throwOnError: true });
1816

1917
return stdout;
2018
}
@@ -68,7 +66,7 @@ export class NpmRegistry extends Registry {
6866

6967
return true;
7068
} catch (error) {
71-
if (`${error}`.includes("ENEEDAUTH")) {
69+
if (error instanceof NonZeroExitError && error.output?.stderr.includes("ENEEDAUTH")) {
7270
return false;
7371
}
7472

@@ -142,7 +140,7 @@ export class NpmRegistry extends Registry {
142140
try {
143141
await this.npm(["publish", "--provenance", "--access", "public"]);
144142
} catch (error) {
145-
if (`${error}`.includes("EOTP")) {
143+
if (error instanceof NonZeroExitError && error.output?.stderr.includes("EOTP")) {
146144
return false;
147145
}
148146
}
@@ -166,7 +164,7 @@ export class NpmRegistry extends Registry {
166164
try {
167165
await this.npm(args);
168166
} catch (error) {
169-
if (`${error}`.includes("EOTP")) {
167+
if (error instanceof NonZeroExitError && error.output?.stderr.includes("EOTP")) {
170168
return false;
171169
}
172170
}

src/tasks/runner.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,9 @@ export async function run(options: ResolvedOptions): Promise<void> {
8181
task: async (ctx): Promise<void> => {
8282
const packageManager = await getPackageManager();
8383

84-
const { stderr } = await exec(packageManager, [
85-
"run",
86-
ctx.testScript,
87-
]);
88-
89-
if (stderr) {
90-
throw new AbstractError(
91-
`Failed to run \`${packageManager} run ${ctx.testScript}\``,
92-
{ cause: stderr },
93-
);
94-
}
84+
await exec(packageManager, ["run", ctx.testScript], {
85+
throwOnError: true,
86+
});
9587
},
9688
},
9789
{

0 commit comments

Comments
 (0)