@vlandoss/clibuddy 0.4.1-git-e0772c7.0 → 0.5.1-git-87ebfca.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.
package/dist/index.d.mts CHANGED
@@ -1,8 +1,7 @@
1
1
  import * as _$ansis from "ansis";
2
2
  import { hasTTY, isCI } from "std-env";
3
3
  import { PackageJson } from "pkg-types";
4
- import * as _$zx from "zx";
5
- import { Options, ProcessOutput, Shell as Shell$1 } from "zx";
4
+ import { NonZeroExitError, Output } from "tinyexec";
6
5
  import { Project } from "@pnpm/types";
7
6
 
8
7
  //#region src/colors.d.ts
@@ -48,35 +47,43 @@ declare function run(fn: () => Promise<void>, logger: {
48
47
  }): Promise<void>;
49
48
  //#endregion
50
49
  //#region src/shell/types.d.ts
51
- type Shell = Shell$1;
52
- type ShellOptions = Partial<Options>;
53
- type CreateOptions = ShellOptions & {
54
- localBaseBinPath?: string | Array<string>;
50
+ type ShellOptions = {
51
+ cwd?: string;
52
+ env?: NodeJS.ProcessEnv;
53
+ verbose?: boolean;
54
+ };
55
+ type RunOptions = ShellOptions & {
56
+ throwOnError?: boolean;
57
+ shell?: boolean;
58
+ stdin?: string;
59
+ display?: string;
55
60
  };
56
61
  //#endregion
57
62
  //#region src/shell/shell.d.ts
58
63
  declare class ShellService {
59
64
  #private;
60
- constructor(options: ShellOptions);
61
- get options(): Partial<_$zx.Options>;
62
- get $(): Shell;
65
+ constructor(options?: ShellOptions);
66
+ get options(): ShellOptions;
67
+ at(cwd: string): ShellService;
63
68
  child(options: ShellOptions): ShellService;
64
- quiet(options?: ShellOptions): ShellService;
65
- mute(options?: ShellOptions): ShellService;
66
- at(cwd: string, options?: ShellOptions): ShellService;
69
+ quiet(): ShellService;
70
+ run(cmd: string, args?: string[], opts?: RunOptions): Promise<Output>;
71
+ runCaptured(cmd: string, args?: string[], opts?: RunOptions): Promise<Output>;
67
72
  }
68
73
  //#endregion
69
74
  //#region src/shell/create.d.ts
70
75
  declare const cwd: string;
71
- declare function quote(arg: string): string;
72
- declare const isRaw: (arg: unknown) => arg is {
73
- stdout: string;
74
- };
75
- declare function createShellService(options?: CreateOptions): ShellService;
76
+ declare function createShellService(options?: ShellOptions): ShellService;
77
+ //#endregion
78
+ //#region src/shell/resolve-bin.d.ts
79
+ declare function resolveBinPath(pkg: string, options: {
80
+ from: string;
81
+ binPath?: string;
82
+ binName?: string;
83
+ }): string;
76
84
  //#endregion
77
85
  //#region src/shell/utils.d.ts
78
- declare function isProcessOutput(value: unknown): value is ProcessOutput;
79
- declare function getPreferLocal(localBaseBinPath: string | Array<string> | undefined): string[] | undefined;
86
+ declare function isNonZeroExitError(value: unknown): value is NonZeroExitError;
80
87
  //#endregion
81
88
  //#region src/text.d.ts
82
89
  declare const text: {
@@ -84,4 +91,4 @@ declare const text: {
84
91
  version: (version: string) => string;
85
92
  };
86
93
  //#endregion
87
- export { CreateOptions, Pkg, type Project, Shell, ShellOptions, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, getPreferLocal, hasTTY, isCI, isProcessOutput, isRaw, palette, quote, run, text };
94
+ export { NonZeroExitError, Pkg, type Project, RunOptions, ShellOptions, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette, resolveBinPath, run, text };
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { createRequire } from "node:module";
1
2
  import ansis, { bold, cyan, dim, green, italic, underline } from "ansis";
2
3
  import { hasTTY, isCI } from "std-env";
3
4
  import path, { dirname } from "node:path";
@@ -7,7 +8,7 @@ import { readFile } from "node:fs/promises";
7
8
  import { findPackages } from "@pnpm/fs.find-packages";
8
9
  import { readPackageJSON, resolvePackageJSON, writePackageJSON } from "pkg-types";
9
10
  import { parse } from "yaml";
10
- import { $, ProcessOutput } from "zx";
11
+ import { NonZeroExitError, x } from "tinyexec";
11
12
  //#region src/colors.ts
12
13
  const colorize = (hex) => ansis.hex(hex);
13
14
  const palette = {
@@ -101,12 +102,8 @@ async function createPkg(cwd) {
101
102
  }
102
103
  //#endregion
103
104
  //#region src/shell/utils.ts
104
- function isProcessOutput(value) {
105
- return value instanceof ProcessOutput;
106
- }
107
- const getLocalBinPath = (dirPath) => path.join(dirPath, "node_modules", ".bin");
108
- function getPreferLocal(localBaseBinPath) {
109
- return !localBaseBinPath ? void 0 : Array.isArray(localBaseBinPath) ? localBaseBinPath.map(getLocalBinPath) : [localBaseBinPath].map(getLocalBinPath);
105
+ function isNonZeroExitError(value) {
106
+ return value instanceof NonZeroExitError;
110
107
  }
111
108
  //#endregion
112
109
  //#region src/run.ts
@@ -121,85 +118,124 @@ async function run(fn, logger) {
121
118
  try {
122
119
  await fn();
123
120
  } catch (error) {
124
- if (!isProcessOutput(error)) logger.error(formatError(error));
121
+ if (!isNonZeroExitError(error)) logger.error(formatError(error));
125
122
  process.exit(1);
126
123
  }
127
124
  }
128
125
  //#endregion
129
126
  //#region src/shell/shell.ts
130
127
  var ShellService = class ShellService {
131
- #shell;
132
128
  #options;
133
- constructor(options) {
134
- this.#options = Object.freeze(options);
135
- this.#shell = $(options);
129
+ constructor(options = {}) {
130
+ this.#options = Object.freeze({
131
+ cwd: options.cwd ?? process.cwd(),
132
+ env: options.env,
133
+ verbose: options.verbose ?? true
134
+ });
136
135
  }
137
136
  get options() {
138
137
  return this.#options;
139
138
  }
140
- get $() {
141
- return this.#shell;
139
+ at(cwd) {
140
+ return this.child({ cwd });
142
141
  }
143
142
  child(options) {
144
143
  return new ShellService({
145
144
  ...this.#options,
146
- ...options
147
- });
148
- }
149
- quiet(options) {
150
- return this.child({
151
145
  ...options,
152
- verbose: false
146
+ env: options.env ? {
147
+ ...this.#options.env,
148
+ ...options.env
149
+ } : this.#options.env
153
150
  });
154
151
  }
155
- mute(options) {
156
- return this.quiet({
157
- ...options,
158
- stdio: "pipe"
152
+ quiet() {
153
+ return this.child({ verbose: false });
154
+ }
155
+ async run(cmd, args = [], opts = {}) {
156
+ const merged = this.#mergeRunOpts(opts);
157
+ if (merged.verbose) printCmdLine(opts.display ?? cmd, args);
158
+ return x(cmd, args, {
159
+ throwOnError: opts.throwOnError ?? true,
160
+ ...opts.stdin !== void 0 && { stdin: opts.stdin },
161
+ nodeOptions: {
162
+ cwd: merged.cwd,
163
+ ...merged.env && { env: merged.env },
164
+ stdio: "inherit",
165
+ ...opts.shell && { shell: true }
166
+ }
159
167
  });
160
168
  }
161
- at(cwd, options) {
162
- const getLocals = (locals) => typeof locals === "boolean" ? [] : typeof locals === "undefined" ? [] : Array.isArray(locals) ? locals : [locals];
163
- const cwdPreferLocal = getPreferLocal(cwd);
164
- const preferLocal = options?.preferLocal === false ? false : [
165
- ...getLocals(this.#options.preferLocal),
166
- ...getLocals(options?.preferLocal),
167
- ...cwdPreferLocal ? cwdPreferLocal : []
168
- ];
169
- return this.child({
170
- ...options,
171
- cwd,
172
- preferLocal
169
+ async runCaptured(cmd, args = [], opts = {}) {
170
+ const merged = this.#mergeRunOpts(opts);
171
+ return x(cmd, args, {
172
+ throwOnError: opts.throwOnError ?? true,
173
+ ...opts.stdin !== void 0 && { stdin: opts.stdin },
174
+ nodeOptions: {
175
+ cwd: merged.cwd,
176
+ ...merged.env && { env: merged.env },
177
+ ...opts.shell && { shell: true }
178
+ }
173
179
  });
174
180
  }
181
+ #mergeRunOpts(opts) {
182
+ return {
183
+ cwd: opts.cwd ?? this.#options.cwd ?? process.cwd(),
184
+ env: opts.env ? {
185
+ ...this.#options.env,
186
+ ...opts.env
187
+ } : this.#options.env,
188
+ verbose: opts.verbose ?? this.#options.verbose ?? true
189
+ };
190
+ }
175
191
  };
192
+ function printCmdLine(cmd, args) {
193
+ const tail = args.length === 0 ? "" : ` ${args.join(" ")}`;
194
+ process.stderr.write(`${palette.muted("$")} ${palette.highlight(cmd)}${tail}\n`);
195
+ }
176
196
  //#endregion
177
197
  //#region src/shell/create.ts
178
198
  const cwd = fs.realpathSync(process.cwd());
179
- function quote(arg) {
180
- if (/^[\w./:=@-]+$/i.test(arg) || arg === "") return arg;
181
- return arg.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\f/g, "\\f").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\v/g, "\\v").replace(/\0/g, "\\0");
182
- }
183
- const isRaw = (arg) => typeof arg === "object" && arg !== null && "stdout" in arg && typeof arg.stdout === "string";
184
- function defaultQuote(arg) {
185
- if (typeof arg === "string") return quote(arg);
186
- if (isRaw(arg)) return arg.stdout;
187
- throw TypeError(`Unsupported argument type: ${typeof arg}`);
188
- }
189
199
  function createShellService(options = {}) {
190
200
  return new ShellService({
191
- verbose: true,
192
201
  cwd,
193
- preferLocal: getPreferLocal(options.localBaseBinPath),
194
- quote: defaultQuote,
195
202
  ...options
196
203
  });
197
204
  }
198
205
  //#endregion
206
+ //#region src/shell/resolve-bin.ts
207
+ function resolveBinPath(pkg, options) {
208
+ const pkgRoot = findPackageRoot(createRequire(options.from), pkg);
209
+ if (options.binPath) return path.join(pkgRoot, options.binPath);
210
+ const bin = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8")).bin;
211
+ if (!bin) throw new Error(`Package ${pkg} has no "bin" field`);
212
+ if (typeof bin === "string") return path.join(pkgRoot, bin);
213
+ const wantName = options.binName ?? pkg.replace(/^@[^/]+\//, "");
214
+ const rel = bin[wantName] ?? Object.values(bin)[0];
215
+ if (!rel) throw new Error(`No bin entry found for ${pkg} (asked for ${wantName})`);
216
+ return path.join(pkgRoot, rel);
217
+ }
218
+ function findPackageRoot(require, pkg) {
219
+ try {
220
+ return path.dirname(require.resolve(`${pkg}/package.json`));
221
+ } catch {}
222
+ const mainPath = require.resolve(pkg);
223
+ let dir = path.dirname(mainPath);
224
+ const fsRoot = path.parse(dir).root;
225
+ while (dir !== fsRoot) {
226
+ const pkgJsonPath = path.join(dir, "package.json");
227
+ if (fs.existsSync(pkgJsonPath)) try {
228
+ if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")).name === pkg) return dir;
229
+ } catch {}
230
+ dir = path.dirname(dir);
231
+ }
232
+ throw new Error(`Could not find package root for ${pkg} from ${mainPath}`);
233
+ }
234
+ //#endregion
199
235
  //#region src/text.ts
200
236
  const text = {
201
237
  vland: `${palette.link(palette.primary("https://variable.land"))} 👊`,
202
238
  version: (version) => palette.muted(`v${version}`)
203
239
  };
204
240
  //#endregion
205
- export { Pkg, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, getPreferLocal, hasTTY, isCI, isProcessOutput, isRaw, palette, quote, run, text };
241
+ export { NonZeroExitError, Pkg, ShellService, colorize, createPkg, createShellService, cwd, dirnameOf, filenameOf, hasTTY, isCI, isNonZeroExitError, palette, resolveBinPath, run, text };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vlandoss/clibuddy",
3
- "version": "0.4.1-git-e0772c7.0",
3
+ "version": "0.5.1-git-87ebfca.0",
4
4
  "description": "A helper library to create CLIs in Variable Land",
5
5
  "homepage": "https://github.com/variableland/dx/tree/main/packages/clibuddy#readme",
6
6
  "bugs": {
@@ -32,8 +32,8 @@
32
32
  "ansis": "4.2.0",
33
33
  "pkg-types": "2.3.0",
34
34
  "std-env": "3.9.0",
35
- "yaml": "2.8.4",
36
- "zx": "8.8.5"
35
+ "tinyexec": "1.1.2",
36
+ "yaml": "2.8.4"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
package/src/run.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { isProcessOutput } from "./shell/utils.ts";
1
+ import { isNonZeroExitError } from "./shell/utils.ts";
2
2
 
3
3
  function hasMessage(error: unknown): error is { message: string } {
4
4
  return (
@@ -18,7 +18,8 @@ export async function run(fn: () => Promise<void>, logger: { error: (...args: un
18
18
  try {
19
19
  await fn();
20
20
  } catch (error) {
21
- if (!isProcessOutput(error)) {
21
+ // The subprocess already streamed its own stderr; don't double-print.
22
+ if (!isNonZeroExitError(error)) {
22
23
  logger.error(formatError(error));
23
24
  }
24
25
  process.exit(1);
@@ -1,50 +1,9 @@
1
1
  import fs from "node:fs";
2
2
  import { ShellService } from "./shell.ts";
3
- import type { CreateOptions } from "./types.ts";
4
- import { getPreferLocal } from "./utils.ts";
3
+ import type { ShellOptions } from "./types.ts";
5
4
 
6
5
  export const cwd = fs.realpathSync(process.cwd());
7
6
 
8
- // Inspired by https://dub.sh/6tiHVgn
9
- export function quote(arg: string) {
10
- if (/^[\w./:=@-]+$/i.test(arg) || arg === "") {
11
- return arg;
12
- }
13
-
14
- return arg
15
- .replace(/\\/g, "\\\\")
16
- .replace(/'/g, "\\'")
17
- .replace(/\f/g, "\\f")
18
- .replace(/\n/g, "\\n")
19
- .replace(/\r/g, "\\r")
20
- .replace(/\t/g, "\\t")
21
- .replace(/\v/g, "\\v")
22
- .replace(/\0/g, "\\0");
23
- }
24
-
25
- export const isRaw = (arg: unknown): arg is { stdout: string } =>
26
- typeof arg === "object" && arg !== null && "stdout" in arg && typeof arg.stdout === "string";
27
-
28
- function defaultQuote(arg: unknown) {
29
- if (typeof arg === "string") {
30
- return quote(arg);
31
- }
32
-
33
- if (isRaw(arg)) {
34
- return arg.stdout;
35
- }
36
-
37
- throw TypeError(`Unsupported argument type: ${typeof arg}`);
38
- }
39
-
40
- export function createShellService(options: CreateOptions = {}) {
41
- const preferLocal = getPreferLocal(options.localBaseBinPath);
42
-
43
- return new ShellService({
44
- verbose: true,
45
- cwd,
46
- preferLocal,
47
- quote: defaultQuote,
48
- ...options,
49
- });
7
+ export function createShellService(options: ShellOptions = {}): ShellService {
8
+ return new ShellService({ cwd, ...options });
50
9
  }
@@ -1,4 +1,5 @@
1
1
  export * from "./create.ts";
2
+ export * from "./resolve-bin.ts";
2
3
  export * from "./shell.ts";
3
4
  export * from "./types.ts";
4
5
  export * from "./utils.ts";
@@ -0,0 +1,53 @@
1
+ import fs from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import path from "node:path";
4
+
5
+ export function resolveBinPath(pkg: string, options: { from: string; binPath?: string; binName?: string }): string {
6
+ const require = createRequire(options.from);
7
+ const pkgRoot = findPackageRoot(require, pkg);
8
+
9
+ if (options.binPath) {
10
+ return path.join(pkgRoot, options.binPath);
11
+ }
12
+
13
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8")) as {
14
+ bin?: string | Record<string, string>;
15
+ };
16
+ const bin = pkgJson.bin;
17
+ if (!bin) throw new Error(`Package ${pkg} has no "bin" field`);
18
+
19
+ if (typeof bin === "string") return path.join(pkgRoot, bin);
20
+
21
+ const wantName = options.binName ?? pkg.replace(/^@[^/]+\//, "");
22
+ const rel = bin[wantName] ?? Object.values(bin)[0];
23
+ if (!rel) throw new Error(`No bin entry found for ${pkg} (asked for ${wantName})`);
24
+ return path.join(pkgRoot, rel);
25
+ }
26
+
27
+ // Two-step lookup tolerates packages that don't expose `./package.json` in
28
+ // their `exports` map (e.g. oxlint) and packages with no `main`/`exports` at
29
+ // all (e.g. @biomejs/biome) — `require.resolve(pkg)` fails for the latter.
30
+ function findPackageRoot(require: NodeJS.Require, pkg: string): string {
31
+ try {
32
+ return path.dirname(require.resolve(`${pkg}/package.json`));
33
+ } catch {
34
+ // fall through to manual walk
35
+ }
36
+
37
+ const mainPath = require.resolve(pkg);
38
+ let dir = path.dirname(mainPath);
39
+ const fsRoot = path.parse(dir).root;
40
+ while (dir !== fsRoot) {
41
+ const pkgJsonPath = path.join(dir, "package.json");
42
+ if (fs.existsSync(pkgJsonPath)) {
43
+ try {
44
+ const data = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8")) as { name?: string };
45
+ if (data.name === pkg) return dir;
46
+ } catch {
47
+ // not a valid package.json — keep walking
48
+ }
49
+ }
50
+ dir = path.dirname(dir);
51
+ }
52
+ throw new Error(`Could not find package root for ${pkg} from ${mainPath}`);
53
+ }
@@ -1,65 +1,76 @@
1
- import { $ as make$ } from "zx";
2
- import type { Shell, ShellOptions } from "./types.ts";
3
- import { getPreferLocal } from "./utils.ts";
1
+ import { type Output, x as tinyexec } from "tinyexec";
2
+ import { palette } from "../colors.ts";
3
+ import type { RunOptions, ShellOptions } from "./types.ts";
4
4
 
5
5
  export class ShellService {
6
- #shell: Shell;
7
6
  #options: ShellOptions;
8
7
 
9
- constructor(options: ShellOptions) {
10
- this.#options = Object.freeze(options);
11
- this.#shell = make$(options);
8
+ constructor(options: ShellOptions = {}) {
9
+ this.#options = Object.freeze({
10
+ cwd: options.cwd ?? process.cwd(),
11
+ env: options.env,
12
+ verbose: options.verbose ?? true,
13
+ });
12
14
  }
13
15
 
14
- get options() {
16
+ get options(): ShellOptions {
15
17
  return this.#options;
16
18
  }
17
19
 
18
- get $() {
19
- return this.#shell;
20
+ at(cwd: string): ShellService {
21
+ return this.child({ cwd });
20
22
  }
21
23
 
22
- child(options: ShellOptions) {
24
+ child(options: ShellOptions): ShellService {
23
25
  return new ShellService({
24
26
  ...this.#options,
25
27
  ...options,
28
+ env: options.env ? { ...this.#options.env, ...options.env } : this.#options.env,
26
29
  });
27
30
  }
28
31
 
29
- quiet(options?: ShellOptions) {
30
- return this.child({
31
- ...options,
32
- verbose: false,
33
- });
32
+ quiet(): ShellService {
33
+ return this.child({ verbose: false });
34
34
  }
35
35
 
36
- mute(options?: ShellOptions) {
37
- return this.quiet({
38
- ...options,
39
- stdio: "pipe",
36
+ async run(cmd: string, args: string[] = [], opts: RunOptions = {}): Promise<Output> {
37
+ const merged = this.#mergeRunOpts(opts);
38
+ if (merged.verbose) printCmdLine(opts.display ?? cmd, args);
39
+ return tinyexec(cmd, args, {
40
+ throwOnError: opts.throwOnError ?? true,
41
+ ...(opts.stdin !== undefined && { stdin: opts.stdin }),
42
+ nodeOptions: {
43
+ cwd: merged.cwd,
44
+ ...(merged.env && { env: merged.env }),
45
+ stdio: "inherit",
46
+ ...(opts.shell && { shell: true }),
47
+ },
40
48
  });
41
49
  }
42
50
 
43
- at(cwd: string, options?: ShellOptions) {
44
- const getLocals = (locals: boolean | string | string[] | undefined) =>
45
- // NOTE: the boolean handling is done outside when determining preferLocal
46
- typeof locals === "boolean" ? [] : typeof locals === "undefined" ? [] : Array.isArray(locals) ? locals : [locals];
47
-
48
- const cwdPreferLocal = getPreferLocal(cwd);
49
-
50
- const preferLocal =
51
- options?.preferLocal === false
52
- ? false
53
- : [
54
- ...getLocals(this.#options.preferLocal),
55
- ...getLocals(options?.preferLocal),
56
- ...(cwdPreferLocal ? cwdPreferLocal : []),
57
- ];
58
-
59
- return this.child({
60
- ...options,
61
- cwd,
62
- preferLocal,
51
+ async runCaptured(cmd: string, args: string[] = [], opts: RunOptions = {}): Promise<Output> {
52
+ const merged = this.#mergeRunOpts(opts);
53
+ return tinyexec(cmd, args, {
54
+ throwOnError: opts.throwOnError ?? true,
55
+ ...(opts.stdin !== undefined && { stdin: opts.stdin }),
56
+ nodeOptions: {
57
+ cwd: merged.cwd,
58
+ ...(merged.env && { env: merged.env }),
59
+ ...(opts.shell && { shell: true }),
60
+ },
63
61
  });
64
62
  }
63
+
64
+ #mergeRunOpts(opts: RunOptions) {
65
+ return {
66
+ cwd: opts.cwd ?? this.#options.cwd ?? process.cwd(),
67
+ env: opts.env ? { ...this.#options.env, ...opts.env } : this.#options.env,
68
+ verbose: opts.verbose ?? this.#options.verbose ?? true,
69
+ };
70
+ }
71
+ }
72
+
73
+ function printCmdLine(cmd: string, args: string[]): void {
74
+ const tail = args.length === 0 ? "" : ` ${args.join(" ")}`;
75
+ process.stderr.write(`${palette.muted("$")} ${palette.highlight(cmd)}${tail}\n`);
65
76
  }
@@ -1,9 +1,12 @@
1
- import type { Options as ZxOptions, Shell as ZxShell } from "zx";
2
-
3
- export type Shell = ZxShell;
4
-
5
- export type ShellOptions = Partial<ZxOptions>;
1
+ export type ShellOptions = {
2
+ cwd?: string;
3
+ env?: NodeJS.ProcessEnv;
4
+ verbose?: boolean;
5
+ };
6
6
 
7
- export type CreateOptions = ShellOptions & {
8
- localBaseBinPath?: string | Array<string>;
7
+ export type RunOptions = ShellOptions & {
8
+ throwOnError?: boolean;
9
+ shell?: boolean;
10
+ stdin?: string;
11
+ display?: string;
9
12
  };
@@ -1,16 +1,7 @@
1
- import path from "node:path";
2
- import { ProcessOutput } from "zx";
1
+ import { NonZeroExitError } from "tinyexec";
3
2
 
4
- export function isProcessOutput(value: unknown): value is ProcessOutput {
5
- return value instanceof ProcessOutput;
6
- }
7
-
8
- const getLocalBinPath = (dirPath: string) => path.join(dirPath, "node_modules", ".bin");
3
+ export { NonZeroExitError };
9
4
 
10
- export function getPreferLocal(localBaseBinPath: string | Array<string> | undefined) {
11
- return !localBaseBinPath
12
- ? undefined
13
- : Array.isArray(localBaseBinPath)
14
- ? localBaseBinPath.map(getLocalBinPath)
15
- : [localBaseBinPath].map(getLocalBinPath);
5
+ export function isNonZeroExitError(value: unknown): value is NonZeroExitError {
6
+ return value instanceof NonZeroExitError;
16
7
  }