diff --git a/package-lock.json b/package-lock.json index a77ea0d..6dcce60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@studiorack/cli", - "version": "3.0.5", + "version": "3.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@studiorack/cli", - "version": "3.0.5", + "version": "3.0.6", "license": "MIT", "dependencies": { - "@open-audio-stack/core": "^0.1.45", + "@open-audio-stack/core": "^0.1.47", "cli-table3": "^0.6.5", "commander": "^12.1.0", "ora": "^9.0.0" @@ -1291,9 +1291,9 @@ } }, "node_modules/@open-audio-stack/core": { - "version": "0.1.45", - "resolved": "https://registry.npmjs.org/@open-audio-stack/core/-/core-0.1.45.tgz", - "integrity": "sha512-4wXmURbj/B03e6EDzOjoZJUe1kVGQQvFis9BmyY7ZykjDwe1PzMZLI2cp1Uv5nbsKmdDQXn684/8iw62FaTmPA==", + "version": "0.1.47", + "resolved": "https://registry.npmjs.org/@open-audio-stack/core/-/core-0.1.47.tgz", + "integrity": "sha512-XrUpZFFVdAudjSa9E3cfWlDZlTXU7GWNGNxo2n/+aKwHmlgStLHvNPRm2pr1uxJBQWloSILFLQgIcWd2VBB+ig==", "license": "cc0-1.0", "dependencies": { "@vscode/sudo-prompt": "^9.3.1", @@ -1304,6 +1304,7 @@ "glob": "^11.0.0", "inquirer": "^12.4.1", "js-yaml": "^4.1.0", + "mime-types": "^3.0.2", "semver": "^7.6.3", "slugify": "^1.6.6", "tar": "^7.4.3", @@ -3625,6 +3626,31 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", diff --git a/package.json b/package.json index ac9c51c..12bed8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@studiorack/cli", - "version": "3.0.5", + "version": "3.0.6", "description": "Audio project manager tool", "type": "module", "main": "./build/index.js", @@ -39,7 +39,7 @@ "node": ">=18" }, "dependencies": { - "@open-audio-stack/core": "^0.1.45", + "@open-audio-stack/core": "^0.1.47", "cli-table3": "^0.6.5", "commander": "^12.1.0", "ora": "^9.0.0" diff --git a/src/commands/config.ts b/src/commands/config.ts index 324e907..ee1b9a9 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -2,6 +2,7 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ConfigInterface, ConfigLocal, isTests } from '@open-audio-stack/core'; import { CONFIG_LOCAL_TEST } from '../data/Config.js'; +import { output, OutputType } from '../utils.js'; const config: ConfigLocal = new ConfigLocal(isTests() ? CONFIG_LOCAL_TEST : undefined); const program = new Command(); @@ -13,13 +14,16 @@ configCmd .option('-l, --log', 'Enable logging') .description('Get a config setting by key') .action((key: keyof ConfigInterface, options: CliOptions) => { - if (options.log) config.logEnable(); - if (options.json) { - const obj: any = {}; - obj[key] = config.get(key); - console.log({ key }); - } else { - console.log(config.get(key)); + { + const message = `Get config ${String(key)}`; + output(OutputType.START, message, options, config); + try { + const payload = options && options.json ? { key, value: config.get(key) } : String(config.get(key)); + output(OutputType.SUCCESS, payload, options, config); + } catch (err: any) { + output(OutputType.ERROR, err, options, config); + process.exit(1); + } } }); @@ -29,12 +33,16 @@ configCmd .option('-l, --log', 'Enable logging') .description('Set a config setting by key and value') .action((key: keyof ConfigInterface, val: any, options: CliOptions) => { - // if (options.log) config.logEnable(); - if (options.json) { - const obj: any = {}; - obj[key] = config.set(key, val); - console.log(obj); - } else { - console.log(config.set(key, val)); + { + const message = `Set config ${String(key)}`; + output(OutputType.START, message, options, config); + try { + const res = config.set(key, val); + const payload = options && options.json ? { key, value: res } : String(res); + output(OutputType.SUCCESS, payload, options, config); + } catch (err: any) { + output(OutputType.ERROR, err, options, config); + process.exit(1); + } } }); diff --git a/src/commands/create.ts b/src/commands/create.ts index 00efb84..bc22d9e 100644 --- a/src/commands/create.ts +++ b/src/commands/create.ts @@ -1,16 +1,26 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function create(command: Command, manager: ManagerLocal) { command - .command('create ') + .command('create') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Create a new package locally') - .action(async (path: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - console.log(await manager.create()); - console.log(path); + .action(async (options: CliOptions) => { + const message = `Create package`; + output(OutputType.START, message, options, manager); + try { + const result = await manager.create(); + // For JSON mode return the object; for textual mode, stringify objects + const payload = + options && options.json ? result : typeof result === 'string' ? result : JSON.stringify(result, null, 2); + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/filter.ts b/src/commands/filter.ts index 646782d..5232605 100644 --- a/src/commands/filter.ts +++ b/src/commands/filter.ts @@ -1,16 +1,35 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal, PackageVersion } from '@open-audio-stack/core'; -import { formatOutput } from '../utils.js'; +import { formatOutput, output, OutputType } from '../utils.js'; export function filter(command: Command, manager: ManagerLocal) { command .command('filter ') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Filter the by field and matching value') - .action((field: keyof PackageVersion, value: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - console.log(formatOutput(manager.filter(pkgVersion => pkgVersion[field] === value))); + .action(async (field: keyof PackageVersion, value: string, options: CliOptions) => { + const message = `Filter ${manager.type} by ${String(field)}=${value}`; + output(OutputType.START, message, options, manager); + try { + const predicate = (pkgVersion: PackageVersion) => { + const fieldVal: any = pkgVersion[field]; + if (Array.isArray(fieldVal)) { + return fieldVal.some((v: any) => String(v).toLowerCase() === value.toLowerCase()); + } + if (typeof fieldVal === 'string') { + return fieldVal.toLowerCase().includes(value.toLowerCase()); + } + if (fieldVal === undefined || fieldVal === null) return false; + return String(fieldVal) === value; + }; + const result = await manager.filter(predicate); + const payload = options && options.json ? result : formatOutput(result); + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/get.ts b/src/commands/get.ts index 73fcc99..e22ab5e 100644 --- a/src/commands/get.ts +++ b/src/commands/get.ts @@ -1,19 +1,29 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { inputGetParts, ManagerLocal } from '@open-audio-stack/core'; -import { formatOutput } from '../utils.js'; +import { formatOutput, output, OutputType } from '../utils.js'; export function get(command: Command, manager: ManagerLocal) { command .command('get ') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Get package metadata from registry') .action((input: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - const [slug, version] = inputGetParts(input); - const pkg = manager.getPackage(slug); - const versions = version ? [version] : Array.from(pkg?.versions.keys() || new Map().keys()); - console.log(formatOutput(pkg, versions)); + const message = `Get package ${input}`; + output(OutputType.START, message, options, manager); + try { + const [slug, version] = inputGetParts(input); + const pkg = manager.getPackage(slug); + if (!pkg) throw new Error(`No package found with slug: ${slug}`); + const payload = + options && options.json + ? { pkg, version } + : formatOutput(pkg, version ? [version] : Array.from(pkg.versions.keys()), false); + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/install.ts b/src/commands/install.ts index 45707c0..76d822f 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -1,26 +1,28 @@ import { Command } from 'commander'; -import ora from 'ora'; import { CliOptions } from '../types/options.js'; -import { inputGetParts, ManagerLocal, isTests } from '@open-audio-stack/core'; +import { inputGetParts, ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function install(command: Command, manager: ManagerLocal) { command .command('install ') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Install a package locally by slug/version') .action(async (input: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); const [slug, version] = inputGetParts(input); - const spinner = ora(`Installing ${slug}${version ? `@${version}` : ''}...`).start(); + const message = `Install ${slug}${version ? `@${version}` : ''}`; + output(OutputType.START, message, options, manager); try { await manager.install(slug, version); - spinner.succeed(`Installed ${slug}${version ? `@${version}` : ''}`); - if (isTests()) console.log(`Installed ${slug}${version ? `@${version}` : ''}`); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - spinner.fail(errorMessage); - if (isTests()) console.log(errorMessage); + const payload = + options && options.json + ? { slug, version: version || null, installed: true } + : `Installed ${slug}${version ? `@${version}` : ''}`; + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); } }); } diff --git a/src/commands/list.ts b/src/commands/list.ts index 60d83d2..a389000 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -1,7 +1,7 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal } from '@open-audio-stack/core'; -import { formatOutput } from '../utils.js'; +import { formatOutput, output, OutputType } from '../utils.js'; interface ListOptions extends CliOptions { incompatible: boolean; @@ -13,11 +13,19 @@ export function list(command: Command, manager: ManagerLocal) { .command('list') .option('-c, --incompatible', 'List incompatible packages') .option('-i, --installed', 'Only list installed packages') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('List packages') .action(async (options: ListOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - console.log(formatOutput(manager.listPackages(options.installed, options.incompatible))); + const message = `List ${manager.type}`; + output(OutputType.START, message, options, manager); + try { + const result = await manager.listPackages(options.installed, options.incompatible); + const payload = options && options.json ? result : formatOutput(result); + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/open.ts b/src/commands/open.ts index c6d620d..8d5af3c 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -1,6 +1,7 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { inputGetParts, ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function open(command: Command, manager: ManagerLocal) { command @@ -8,14 +9,14 @@ export function open(command: Command, manager: ManagerLocal) { .option('-l, --log', 'Enable logging') .description('Open a package by slug/version') .action(async (input: string, options: string[], cliOptions: CliOptions) => { - if (cliOptions.log) manager.logEnable(); - else manager.logDisable(); - const [slug, version] = inputGetParts(input); + const message = `Open ${input}`; + output(OutputType.START, message, cliOptions, manager); try { + const [slug, version] = inputGetParts(input); await manager.open(slug, version, options); - } catch (error: any) { - const errorMessage = error instanceof Error ? error.message : String(error); - console.error(errorMessage); + output(OutputType.SUCCESS, `Opened ${input}`, cliOptions, manager); + } catch (err: any) { + output(OutputType.ERROR, err, cliOptions, manager); process.exit(1); } }); diff --git a/src/commands/reset.ts b/src/commands/reset.ts index 339875c..9ed7da5 100644 --- a/src/commands/reset.ts +++ b/src/commands/reset.ts @@ -1,6 +1,7 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function reset(command: Command, manager: ManagerLocal) { command @@ -8,9 +9,16 @@ export function reset(command: Command, manager: ManagerLocal) { .option('-l, --log', 'Enable logging') .description('Reset the synced package cache') .action((options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - manager.reset(); - console.log(`${manager.type} cache has been reset`); + const message = `Reset ${manager.type}`; + output(OutputType.START, message, options, manager); + try { + manager.reset(); + const payload = + options && options.json ? { type: manager.type, status: 'reset' } : `Reset complete ${manager.type}`; + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/scan.ts b/src/commands/scan.ts index 614f6c4..8702e01 100644 --- a/src/commands/scan.ts +++ b/src/commands/scan.ts @@ -1,16 +1,25 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function scan(command: Command, manager: ManagerLocal) { command .command('scan') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Scan local packages into cache') .action(async (options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - manager.scan(); - console.log(`${manager.type} scan completed`); + const message = `Scan ${manager.type}`; + output(OutputType.START, message, options, manager); + try { + await manager.scan(); + // pass an object for JSON output, or a string for textual output + const payload = options && options.json ? { type: manager.type, status: 'scanned' } : `Scanned ${manager.type}`; + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/search.ts b/src/commands/search.ts index 95ec2d7..e836ba0 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -1,16 +1,24 @@ import { Command } from 'commander'; import { CliOptions } from '../types/options.js'; import { ManagerLocal } from '@open-audio-stack/core'; -import { formatOutput } from '../utils.js'; +import { formatOutput, output, OutputType } from '../utils.js'; export function search(command: Command, manager: ManagerLocal) { command .command('search ') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Search using a lazy matching query') .action(async (query: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - console.log(formatOutput(manager.search(query))); + const message = `Search ${manager.type}`; + output(OutputType.START, message, options, manager); + try { + const result = await manager.search(query); + const payload = options && options.json ? result : formatOutput(result); + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); + } }); } diff --git a/src/commands/sync.ts b/src/commands/sync.ts index f9ed680..13968b2 100644 --- a/src/commands/sync.ts +++ b/src/commands/sync.ts @@ -1,25 +1,24 @@ import { Command } from 'commander'; -import ora from 'ora'; import { CliOptions } from '../types/options.js'; -import { ManagerLocal, isTests } from '@open-audio-stack/core'; +import { ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function sync(command: Command, manager: ManagerLocal) { command .command('sync') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Sync remote packages into cache') .action(async (options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); - const spinner = ora(`Syncing ${manager.type}...`).start(); + const message = `Sync ${manager.type}`; + output(OutputType.START, message, options, manager); try { await manager.sync(); - spinner.succeed(`${manager.type} sync completed`); - if (isTests()) console.log(`${manager.type} sync completed`); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - spinner.fail(errorMessage); - if (isTests()) console.log(errorMessage); + const payload = options && options.json ? { type: manager.type, status: 'synced' } : `Synced ${manager.type}`; + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); } }); } diff --git a/src/commands/uninstall.ts b/src/commands/uninstall.ts index b2a1fc5..beb548b 100644 --- a/src/commands/uninstall.ts +++ b/src/commands/uninstall.ts @@ -1,26 +1,28 @@ import { Command } from 'commander'; -import ora from 'ora'; import { CliOptions } from '../types/options.js'; -import { inputGetParts, ManagerLocal, isTests } from '@open-audio-stack/core'; +import { inputGetParts, ManagerLocal } from '@open-audio-stack/core'; +import { output, OutputType } from '../utils.js'; export function uninstall(command: Command, manager: ManagerLocal) { command .command('uninstall ') + .option('-j, --json', 'Output results as json') .option('-l, --log', 'Enable logging') .description('Uninstall a package locally by slug/version') .action(async (input: string, options: CliOptions) => { - if (options.log) manager.logEnable(); - else manager.logDisable(); const [slug, version] = inputGetParts(input); - const spinner = ora(`Uninstalling ${slug}${version ? `@${version}` : ''}...`).start(); + const message = `Uninstall ${slug}${version ? `@${version}` : ''}`; + output(OutputType.START, message, options, manager); try { await manager.uninstall(slug, version); - spinner.succeed(`Uninstalled ${slug}${version ? `@${version}` : ''}`); - if (isTests()) console.log(`Uninstalled ${slug}${version ? `@${version}` : ''}`); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - spinner.fail(errorMessage); - if (isTests()) console.log(errorMessage); + const payload = + options && options.json + ? { slug, version: version || null, installed: false } + : `Uninstalled ${slug}${version ? `@${version}` : ''}`; + output(OutputType.SUCCESS, payload, options, manager); + } catch (err: any) { + output(OutputType.ERROR, err, options, manager); + process.exit(1); } }); } diff --git a/src/index.ts b/src/index.ts index af7855e..83370bb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,4 +40,18 @@ for (const type of types) { uninstall(command, manager); } -program.version('3.0.1').parse(process.argv); +import fs from 'fs'; +import path from 'path'; + +let version = '0.0.0'; +try { + const pkgPath = path.resolve(process.cwd(), 'package.json'); + const pkgRaw = fs.readFileSync(pkgPath, 'utf8'); + const pkg = JSON.parse(pkgRaw); + if (pkg && pkg.version) version = pkg.version; +} catch (e) { + console.error(e); + // ignore and fallback to default +} + +program.version(version).parse(process.argv); diff --git a/src/utils.ts b/src/utils.ts index 78f4448..eb74d7b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,7 @@ -import { Package } from '@open-audio-stack/core'; +import { Base, isTests, Package } from '@open-audio-stack/core'; import CliTable3 from 'cli-table3'; +import ora, { Ora } from 'ora'; +import type { CliOptions } from './types/options.js'; export function formatOutput(result: Package[] | Package | undefined, versions?: string[], json?: boolean): string { if (!result) return `No results found`; @@ -59,3 +61,47 @@ export function truncateString(str: string, num: number) { return str; } } + +export enum OutputType { + START = 'start', + SUCCESS = 'success', + ERROR = 'error', +} + +let spinner: Ora | undefined; + +export function output(type: OutputType, message: any, options?: CliOptions, base?: Base) { + // console.log('\n output', type, message, options); + const useJson = Boolean(options && options.json); + if (message.message) message = message.message; + + // If logging, ensure core package logging is enabled. + if (base) { + if (options && options.log) base.logEnable(); + else base.logDisable(); + } + + // If json, output json only. + if (useJson) { + console.log(JSON.stringify({ type, message }, null, 2)); + return; + } + + // If test, output text only. + if (isTests()) { + console.log(message); + return; + } + + // If interactive run, use spinners. + if (type === OutputType.START) { + spinner = ora(message).start(); + return; + } else if (type === OutputType.SUCCESS) { + spinner?.succeed(message); + return; + } else { + spinner?.fail(message); + return; + } +} diff --git a/tests/__snapshots__/index.test.ts.snap b/tests/__snapshots__/index.test.ts.snap index 4f6edb8..72cbf80 100644 --- a/tests/__snapshots__/index.test.ts.snap +++ b/tests/__snapshots__/index.test.ts.snap @@ -1,7 +1,9 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Root command 1`] = ` -Usage: index [options] [command] +{ + code: 1, + err: Usage: index [options] [command] Options: -V, --version output the version number @@ -13,17 +15,21 @@ Commands: plugins presets projects - help [command] display help for command + help [command] display help for command, + out: , +} `; exports[`Root command plugins 1`] = ` -Usage: index plugins [options] [command] +{ + code: 1, + err: Usage: index plugins [options] [command] Options: -h, --help display help for command Commands: - create [options] Create a new package locally + create [options] Create a new package locally filter [options] Filter the by field and matching value get [options] Get package metadata from registry install [options] Install a package locally by @@ -36,17 +42,21 @@ Commands: sync [options] Sync remote packages into cache uninstall [options] Uninstall a package locally by slug/version - help [command] display help for command + help [command] display help for command, + out: , +} `; exports[`Root command presets 1`] = ` -Usage: index presets [options] [command] +{ + code: 1, + err: Usage: index presets [options] [command] Options: -h, --help display help for command Commands: - create [options] Create a new package locally + create [options] Create a new package locally filter [options] Filter the by field and matching value get [options] Get package metadata from registry install [options] Install a package locally by @@ -59,17 +69,21 @@ Commands: sync [options] Sync remote packages into cache uninstall [options] Uninstall a package locally by slug/version - help [command] display help for command + help [command] display help for command, + out: , +} `; exports[`Root command projects 1`] = ` -Usage: index projects [options] [command] +{ + code: 1, + err: Usage: index projects [options] [command] Options: -h, --help display help for command Commands: - create [options] Create a new package locally + create [options] Create a new package locally filter [options] Filter the by field and matching value get [options] Get package metadata from registry install [options] Install a package locally by @@ -82,5 +96,7 @@ Commands: sync [options] Sync remote packages into cache uninstall [options] Uninstall a package locally by slug/version - help [command] display help for command + help [command] display help for command, + out: , +} `; diff --git a/tests/commands/__snapshots__/config.test.ts.snap b/tests/commands/__snapshots__/config.test.ts.snap index 2ccf5c1..6e3d6ee 100644 --- a/tests/commands/__snapshots__/config.test.ts.snap +++ b/tests/commands/__snapshots__/config.test.ts.snap @@ -1,24 +1,73 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Config get 1`] = `test`; +exports[`Config get 1`] = ` +{ + code: 0, + err: , + out: Get config appDir +test, +} +`; -exports[`Config get 2`] = `test/installed/plugins`; +exports[`Config get 2`] = ` +{ + code: 0, + err: , + out: Get config pluginsDir +test/installed/plugins, +} +`; -exports[`Config get 3`] = `test/installed/presets`; +exports[`Config get 3`] = ` +{ + code: 0, + err: , + out: Get config presetsDir +test/installed/presets, +} +`; -exports[`Config get 4`] = `test/installed/projects`; +exports[`Config get 4`] = ` +{ + code: 0, + err: , + out: Get config projectsDir +test/installed/projects, +} +`; exports[`Config get 5`] = ` -[ - { - name: 'Open Audio Registry', - url: 'https://open-audio-stack.github.io/open-audio-stack-registry' - } -] +{ + code: 0, + err: , + out: Get config registries +[object Object], +} `; -exports[`Config get 6`] = `1.0.0`; +exports[`Config get 6`] = ` +{ + code: 0, + err: , + out: Get config version +1.0.0, +} +`; -exports[`Config set 1`] = `test2`; +exports[`Config set 1`] = ` +{ + code: 0, + err: , + out: Get config appDir +test2, +} +`; -exports[`Config set 2`] = `test`; +exports[`Config set 2`] = ` +{ + code: 0, + err: , + out: Get config appDir +test, +} +`; diff --git a/tests/commands/__snapshots__/create.test.ts.snap b/tests/commands/__snapshots__/create.test.ts.snap index 7c1af1a..a99b0f0 100644 --- a/tests/commands/__snapshots__/create.test.ts.snap +++ b/tests/commands/__snapshots__/create.test.ts.snap @@ -1,6 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Create package 1`] = ` +{ + code: 1, + err: , + out: Create package ? Org id (org-name) - +User force closed the prompt with 0 null, +} `; diff --git a/tests/commands/__snapshots__/filter.test.ts.snap b/tests/commands/__snapshots__/filter.test.ts.snap index a8d19b1..51aaa63 100644 --- a/tests/commands/__snapshots__/filter.test.ts.snap +++ b/tests/commands/__snapshots__/filter.test.ts.snap @@ -1,16 +1,32 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Filter packages 1`] = ` +{ + code: 0, + err: , + out: Filter plugins by name=Surge XT ┌─────────────────────────┬──────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.4 │ - │ 2024-08-11 │ gpl-3.0 │ Instrument, Synth, Modulation │ -└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘ +└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘, +} `; -exports[`Filter packages 2`] = `No results found`; +exports[`Filter packages 2`] = ` +{ + code: 0, + err: , + out: Filter plugins by name=Surge XU +No results found, +} +`; exports[`Filter packages 3`] = ` +{ + code: 0, + err: , + out: Filter plugins by license=cc0-1.0 ┌────────────────────────────────────────┬──────────────────────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├────────────────────────────────────────┼──────────────────────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────────┤ @@ -37,5 +53,6 @@ exports[`Filter packages 3`] = ` │ freepats/hang-d-minor │ Hang D Minor │ 1.0.0 │ - │ 2022-03-30 │ cc0-1.0 │ Instrument, Orchestra, Hang, s... │ ├────────────────────────────────────────┼──────────────────────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────────┤ │ freepats/glasses-of-water │ Glasses Of Water │ 1.0.0 │ - │ 2019-12-27 │ cc0-1.0 │ Instrument, Orchestra, Glass, ... │ -└────────────────────────────────────────┴──────────────────────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────────┘ +└────────────────────────────────────────┴──────────────────────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────────┘, +} `; diff --git a/tests/commands/__snapshots__/get.test.ts.snap b/tests/commands/__snapshots__/get.test.ts.snap index 740c441..4866676 100644 --- a/tests/commands/__snapshots__/get.test.ts.snap +++ b/tests/commands/__snapshots__/get.test.ts.snap @@ -1,21 +1,38 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Get package 1`] = ` +{ + code: 0, + err: , + out: Get package surge-synthesizer/surge ┌─────────────────────────┬──────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.4 │ ✓ │ 2024-08-11 │ gpl-3.0 │ Instrument, Synth, Modulation │ ├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.1 │ ✓ │ 2024-03-02 │ gpl-3.0 │ Instrument, Synth, Modulation │ -└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘ +└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘, +} `; exports[`Get package 2`] = ` +{ + code: 0, + err: , + out: Get package surge-synthesizer/surge@1.3.1 ┌─────────────────────────┬──────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.1 │ ✓ │ 2024-03-02 │ gpl-3.0 │ Instrument, Synth, Modulation │ -└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘ +└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘, +} `; -exports[`Get package 3`] = `No results found`; +exports[`Get package 3`] = ` +{ + code: 0, + err: , + out: Get package surge-synthesizer/surge@0.0.0 +No results found, +} +`; diff --git a/tests/commands/__snapshots__/install.test.ts.snap b/tests/commands/__snapshots__/install.test.ts.snap index 013f072..4a9260d 100644 --- a/tests/commands/__snapshots__/install.test.ts.snap +++ b/tests/commands/__snapshots__/install.test.ts.snap @@ -1,7 +1,28 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Install package 1`] = `Installed surge-synthesizer/surge`; +exports[`Install package 1`] = ` +{ + code: 0, + err: , + out: Install surge-synthesizer/surge +Installed surge-synthesizer/surge, +} +`; -exports[`Install package 2`] = `Installed surge-synthesizer/surge@1.3.1`; +exports[`Install package 2`] = ` +{ + code: 0, + err: , + out: Install surge-synthesizer/surge@1.3.1 +Installed surge-synthesizer/surge@1.3.1, +} +`; -exports[`Install package 3`] = `Package surge-synthesizer/surge version 0.0.0 not found in registry`; +exports[`Install package 3`] = ` +{ + code: 1, + err: , + out: Install surge-synthesizer/surge@0.0.0 +Package surge-synthesizer/surge version 0.0.0 not found in registry, +} +`; diff --git a/tests/commands/__snapshots__/list.test.ts.snap b/tests/commands/__snapshots__/list.test.ts.snap index 43613f3..400c071 100644 --- a/tests/commands/__snapshots__/list.test.ts.snap +++ b/tests/commands/__snapshots__/list.test.ts.snap @@ -1,13 +1,15 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`List packages 1`] = ` +{ + code: 0, + err: , + out: List plugins ┌───────────────────────────────────────────┬───────────────────────────┬─────────┬───────────┬────────────┬───────────────┬───────────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├───────────────────────────────────────────┼───────────────────────────┼─────────┼───────────┼────────────┼───────────────┼───────────────────────────────────┤ │ aaronaanderson/terrain │ Terrain │ 1.2.2 │ - │ 2024-11-01 │ gpl-3.0 │ Instrument, Synthesizer, Wavet... │ ├───────────────────────────────────────────┼───────────────────────────┼─────────┼───────────┼────────────┼───────────────┼───────────────────────────────────┤ -│ airwindows/airwindows │ Airwindows │ 1.0.0 │ - │ 2020-02-20 │ mit │ Effect, Chorus, Distortion, EQ... │ -├───────────────────────────────────────────┼───────────────────────────┼─────────┼───────────┼────────────┼───────────────┼───────────────────────────────────┤ │ antonok-edm/ampli-fe │ ampli-Fe │ 0.1.1 │ - │ 2021-11-02 │ mit │ Effect, Amplifier, Volume │ ├───────────────────────────────────────────┼───────────────────────────┼─────────┼───────────┼────────────┼───────────────┼───────────────────────────────────┤ │ ardenbutterfield/maim │ Maim │ 1.1.1 │ - │ 2025-05-20 │ gpl-3.0 │ Instrument, Modulation, Distor... │ @@ -181,13 +183,19 @@ exports[`List packages 1`] = ` │ wolf-plugins/wolf-shaper │ Wolf Shaper │ 1.0.2 │ - │ 2023-05-14 │ gpl-3.0 │ Effect, Distortion, Editor │ ├───────────────────────────────────────────┼───────────────────────────┼─────────┼───────────┼────────────┼───────────────┼───────────────────────────────────┤ │ wolf-plugins/wolf-spectrum │ Wolf Spectrum │ 1.0.0 │ - │ 2019-04-14 │ gpl-3.0 │ Effect, Spectrogram, Frequency │ -└───────────────────────────────────────────┴───────────────────────────┴─────────┴───────────┴────────────┴───────────────┴───────────────────────────────────┘ +└───────────────────────────────────────────┴───────────────────────────┴─────────┴───────────┴────────────┴───────────────┴───────────────────────────────────┘, +} `; exports[`List packages 2`] = ` +{ + code: 0, + err: , + out: List plugins ┌─────────────────────────┬──────────┬─────────┬───────────┬────────────┬─────────┬───────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├─────────────────────────┼──────────┼─────────┼───────────┼────────────┼─────────┼───────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.4 │ ✓ │ 2024-08-11 │ gpl-3.0 │ Instrument, Synth, Modulation │ -└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘ +└─────────────────────────┴──────────┴─────────┴───────────┴────────────┴─────────┴───────────────────────────────┘, +} `; diff --git a/tests/commands/__snapshots__/open.test.ts.snap b/tests/commands/__snapshots__/open.test.ts.snap index 54e6a04..b371d0c 100644 --- a/tests/commands/__snapshots__/open.test.ts.snap +++ b/tests/commands/__snapshots__/open.test.ts.snap @@ -1,16 +1,34 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Open command help 1`] = ` -Usage: index apps open [options] [options...] +{ + code: 0, + err: , + out: Usage: index apps open [options] [options...] Open a package by slug/version Options: -l, --log Enable logging - -h, --help display help for command + -h, --help display help for command, +} `; -exports[`Open command install and run steinberg/validator mac 1`] = ` +exports[`Open command install and run steinberg/validator 1`] = ` +{ + code: 0, + err: , + out: Install steinberg/validator +Installed steinberg/validator, +} +`; + +exports[`Open command install and run steinberg/validator 2`] = ` +{ + code: 0, + err: , + out: Open steinberg/validator +Opened steinberg/validator VST 3.6.14 Plug-in Validator: -help | Print help @@ -24,7 +42,15 @@ VST 3.6.14 Plug-in Validator: -snapshots | List snapshots from all installed Plug-Ins Usage: vstvalidator [options] vst3module - +, +} `; -exports[`Open command with non-existent package 1`] = `Package non-existent/package not found`; +exports[`Open command with non-existent package 1`] = ` +{ + code: 1, + err: , + out: Open non-existent/package +Package non-existent/package not found, +} +`; diff --git a/tests/commands/__snapshots__/reset.test.ts.snap b/tests/commands/__snapshots__/reset.test.ts.snap index c2b05ea..2eef743 100644 --- a/tests/commands/__snapshots__/reset.test.ts.snap +++ b/tests/commands/__snapshots__/reset.test.ts.snap @@ -1,3 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Reset packages 1`] = `plugins cache has been reset`; +exports[`Reset packages 1`] = ` +{ + code: 0, + err: , + out: Reset plugins +Reset complete plugins, +} +`; diff --git a/tests/commands/__snapshots__/scan.test.ts.snap b/tests/commands/__snapshots__/scan.test.ts.snap index 06becf3..90857a7 100644 --- a/tests/commands/__snapshots__/scan.test.ts.snap +++ b/tests/commands/__snapshots__/scan.test.ts.snap @@ -1,3 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Scan packages 1`] = `plugins scan completed`; +exports[`Scan packages 1`] = ` +{ + code: 0, + err: , + out: Scan plugins +Scanned plugins, +} +`; diff --git a/tests/commands/__snapshots__/search.test.ts.snap b/tests/commands/__snapshots__/search.test.ts.snap index c961d3b..388a187 100644 --- a/tests/commands/__snapshots__/search.test.ts.snap +++ b/tests/commands/__snapshots__/search.test.ts.snap @@ -1,6 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Search packages 1`] = ` +{ + code: 0, + err: , + out: Search plugins ┌─────────────────────────┬─────────────┬─────────┬───────────┬────────────┬─────────┬────────────────────────────────┐ │ Id │ Name │ Version │ Installed │ Date │ License │ Tags │ ├─────────────────────────┼─────────────┼─────────┼───────────┼────────────┼─────────┼────────────────────────────────┤ @@ -9,7 +13,15 @@ exports[`Search packages 1`] = ` │ tesselode/flutterbird │ Flutterbird │ 1.0.1 │ - │ 2018-09-06 │ mit │ Effect, Pitch, Modulation │ ├─────────────────────────┼─────────────┼─────────┼───────────┼────────────┼─────────┼────────────────────────────────┤ │ surge-synthesizer/surge │ Surge XT │ 1.3.4 │ ✓ │ 2024-08-11 │ gpl-3.0 │ Instrument, Synth, Modulation │ -└─────────────────────────┴─────────────┴─────────┴───────────┴────────────┴─────────┴────────────────────────────────┘ +└─────────────────────────┴─────────────┴─────────┴───────────┴────────────┴─────────┴────────────────────────────────┘, +} `; -exports[`Search packages 2`] = `No results found`; +exports[`Search packages 2`] = ` +{ + code: 0, + err: , + out: Search plugins +No results found, +} +`; diff --git a/tests/commands/__snapshots__/sync.test.ts.snap b/tests/commands/__snapshots__/sync.test.ts.snap index 39a8441..3572b6d 100644 --- a/tests/commands/__snapshots__/sync.test.ts.snap +++ b/tests/commands/__snapshots__/sync.test.ts.snap @@ -1,3 +1,10 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Sync packages 1`] = `plugins sync completed`; +exports[`Sync packages 1`] = ` +{ + code: 0, + err: , + out: Sync plugins +Synced plugins, +} +`; diff --git a/tests/commands/__snapshots__/uninstall.test.ts.snap b/tests/commands/__snapshots__/uninstall.test.ts.snap index 97dd24c..c35beb4 100644 --- a/tests/commands/__snapshots__/uninstall.test.ts.snap +++ b/tests/commands/__snapshots__/uninstall.test.ts.snap @@ -1,7 +1,28 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Uninstall package 1`] = `Uninstalled surge-synthesizer/surge`; +exports[`Uninstall package 1`] = ` +{ + code: 0, + err: , + out: Uninstall surge-synthesizer/surge +Uninstalled surge-synthesizer/surge, +} +`; -exports[`Uninstall package 2`] = `Uninstalled surge-synthesizer/surge@1.3.1`; +exports[`Uninstall package 2`] = ` +{ + code: 0, + err: , + out: Uninstall surge-synthesizer/surge@1.3.1 +Uninstalled surge-synthesizer/surge@1.3.1, +} +`; -exports[`Uninstall package 3`] = `Package surge-synthesizer/surge version 0.0.0 not found in registry`; +exports[`Uninstall package 3`] = ` +{ + code: 1, + err: , + out: Uninstall surge-synthesizer/surge@0.0.0 +Package surge-synthesizer/surge version 0.0.0 not found in registry, +} +`; diff --git a/tests/commands/filter.test.ts b/tests/commands/filter.test.ts index 2de1d42..37a70a9 100644 --- a/tests/commands/filter.test.ts +++ b/tests/commands/filter.test.ts @@ -4,6 +4,6 @@ import { License, RegistryType } from '@open-audio-stack/core'; test('Filter packages', async () => { expect(cli(RegistryType.Plugins, 'filter', 'name', 'Surge XT')).toMatchSnapshot(); - expect(cli(RegistryType.Plugins, 'filter', 'name', 'Surge X')).toMatchSnapshot(); + expect(cli(RegistryType.Plugins, 'filter', 'name', 'Surge XU')).toMatchSnapshot(); expect(cli(RegistryType.Plugins, 'filter', 'license', License.CreativeCommonsZerov1Universal)).toMatchSnapshot(); }); diff --git a/tests/commands/open.test.ts b/tests/commands/open.test.ts index 26e1a1e..b71dc43 100644 --- a/tests/commands/open.test.ts +++ b/tests/commands/open.test.ts @@ -1,23 +1,15 @@ import { expect, test } from 'vitest'; -import { cli, cliCatch, cleanOutput } from '../shared'; +import { cli } from '../shared'; test('Open command help', () => { - const result = cli('apps', 'open', '--help'); - expect(cleanOutput(result)).toMatchSnapshot(); + expect(cli('apps', 'open', '--help')).toMatchSnapshot(); }); -// Comment out test until it can be fixed -// test(`Open command install and run steinberg/validator ${getSystem()}`, () => { -// // First install the app -// const installResult = cli('apps', 'install', 'steinberg/validator'); -// expect(installResult).toContain('Installed steinberg/validator'); - -// const openResult = cli('apps', 'open', 'steinberg/validator', '--', '--help'); -// expect(cleanOutput(openResult)).toMatchSnapshot(); -// }); +test('Open command install and run steinberg/validator', () => { + expect(cli('apps', 'install', 'steinberg/validator')).toMatchSnapshot(); + // expect(cli('apps', 'open', 'steinberg/validator', '--', '--help')).toMatchSnapshot(); +}); test('Open command with non-existent package', () => { - const error = cliCatch('apps', 'open', 'non-existent/package'); - expect(error.exitCode).toBe(1); - expect(cleanOutput(error.stderr)).toMatchSnapshot(); + expect(cli('apps', 'open', 'non-existent/package')).toMatchSnapshot(); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index 4762817..2acd5e9 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,27 +1,19 @@ import { expect, test } from 'vitest'; -import { cleanOutput, cliCatch } from './shared'; +import { cli } from './shared'; import { RegistryType } from '@open-audio-stack/core'; test('Root command', async () => { - const error = cliCatch(); - expect(error.exitCode).toBe(1); - expect(cleanOutput(error.stderr)).toMatchSnapshot(); + expect(cli()).toMatchSnapshot(); }); test('Root command plugins', async () => { - const error = cliCatch(RegistryType.Plugins); - expect(error.exitCode).toBe(1); - expect(cleanOutput(error.stderr)).toMatchSnapshot(); + expect(cli(RegistryType.Plugins)).toMatchSnapshot(); }); test('Root command presets', async () => { - const error = cliCatch(RegistryType.Presets); - expect(error.exitCode).toBe(1); - expect(cleanOutput(error.stderr)).toMatchSnapshot(); + expect(cli(RegistryType.Presets)).toMatchSnapshot(); }); test('Root command projects', async () => { - const error = cliCatch(RegistryType.Projects); - expect(error.exitCode).toBe(1); - expect(cleanOutput(error.stderr)).toMatchSnapshot(); + expect(cli(RegistryType.Projects)).toMatchSnapshot(); }); diff --git a/tests/shared.ts b/tests/shared.ts index a17fbe5..7f22f22 100644 --- a/tests/shared.ts +++ b/tests/shared.ts @@ -7,24 +7,34 @@ import { getSystem, SystemType } from '@open-audio-stack/core'; const CLI_PATH: string = path.resolve('./', 'build', 'index.js'); // ANSI escape codes for colors and formatting vary across systems -// Sanitize output for snapshot testing +// Sanitize output for snapshot testing (only apply to strings) expect.addSnapshotSerializer({ - serialize: val => stripVTControlCharacters(val), - test: () => true, + serialize: val => stripVTControlCharacters(val as string), + test: val => typeof val === 'string', }); -export function cli(...args: string[]): string { - const result: SyncResult = execaSync('node', [CLI_PATH, ...args], { - env: { ...process.env, NODE_OPTIONS: '--no-warnings=ExperimentalWarning' }, - }); - return cleanOutput(result.stdout as string); -} +export type CliResult = { + code: number | null; + out: string; + err: string; +}; -export function cliCatch(...args: string[]) { +export function cli(...args: string[]): CliResult { try { - cli(...args); + const result: SyncResult = execaSync('node', [CLI_PATH, ...args], { + env: { ...process.env, NODE_OPTIONS: '--no-warnings=ExperimentalWarning' }, + }); + return { + code: result.exitCode ?? 0, + out: cleanOutput(String(result.stdout ?? '')), + err: cleanOutput(String(result.stderr ?? '')), + }; } catch (error: any) { - return error; + return { + code: error.exitCode ?? 1, + out: cleanOutput(String(error.stdout ?? '')), + err: cleanOutput(String(error.stderr ?? error.message ?? '')), + }; } }