or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

code-coverage.mdcode-formatting.mdcode-linting.mdfile-cleanup.mdindex.mdprocess-management.mdtest-execution.mdtypescript-compilation.md

process-management.mddocs/

0

# Process Management

1

2

Core utilities for running CLI commands and managing child processes with intelligent module resolution and cross-platform support.

3

4

## Capabilities

5

6

### CLI Execution

7

8

Execute CLI tools with automatic module resolution and project-first dependency lookup.

9

10

```typescript { .api }

11

/**

12

* Run a CLI command with intelligent module resolution

13

* @param cli - CLI module path (e.g., "typescript/lib/tsc", "eslint/bin/eslint")

14

* @param args - Command line arguments to pass to the CLI

15

* @param options - Execution options for process control and module resolution

16

* @returns ChildProcess when executed, string when dry run

17

*/

18

function runCLI(

19

cli: string,

20

args: string[],

21

options?: RunCLIOptions

22

): ChildProcess | string;

23

24

interface RunCLIOptions {

25

dryRun?: boolean; // Return command string instead of executing

26

cwd?: string; // Working directory for execution

27

resolveFromProjectFirst?: boolean; // Try project dependencies before @loopback/build

28

nodeArgs?: string[]; // Additional Node.js arguments

29

stdio?: string; // stdio configuration

30

env?: Record<string, string>; // Environment variables

31

}

32

```

33

34

**Usage Examples:**

35

36

```typescript

37

import { runCLI } from "@loopback/build";

38

39

// Run TypeScript compiler

40

const tscProcess = runCLI(

41

"typescript/lib/tsc",

42

["--project", "tsconfig.json"]

43

);

44

45

// Run with custom Node.js arguments

46

const eslintProcess = runCLI(

47

"eslint/bin/eslint",

48

["src/", "--fix"],

49

{ nodeArgs: ["--max-old-space-size=4096"] }

50

);

51

52

// Dry run to see command

53

const command = runCLI(

54

"prettier/bin/prettier.cjs",

55

["--write", "**/*.ts"],

56

{ dryRun: true }

57

);

58

console.log(command); // "node /path/to/prettier.cjs --write **/*.ts"

59

60

// Custom working directory

61

runCLI("mocha/bin/mocha", ["test/"], { cwd: "/path/to/project" });

62

```

63

64

### Shell Command Execution

65

66

Execute shell commands with JSON-safe argument handling and cross-platform support.

67

68

```typescript { .api }

69

/**

70

* Run a shell command with cross-platform support

71

* @param command - Command to execute (must be in PATH or absolute path)

72

* @param args - Command arguments (automatically JSON-quoted for safety)

73

* @param options - Execution options for process control

74

* @returns ChildProcess when executed, string when dry run

75

*/

76

function runShell(

77

command: string,

78

args: string[],

79

options?: RunShellOptions

80

): ChildProcess | string;

81

82

interface RunShellOptions {

83

dryRun?: boolean; // Return command string instead of executing

84

cwd?: string; // Working directory for execution

85

stdio?: string; // stdio configuration

86

env?: Record<string, string>; // Environment variables

87

shell?: boolean; // Enable shell execution (default: true)

88

}

89

```

90

91

**Usage Examples:**

92

93

```typescript

94

import { runShell } from "@loopback/build";

95

96

// Run npm commands

97

const npmProcess = runShell("npm", ["install", "--save-dev", "typescript"]);

98

99

// Run git commands

100

const gitProcess = runShell("git", ["add", "."]);

101

102

// Run with custom environment

103

const envProcess = runShell("node", ["script.js"], {

104

env: { NODE_ENV: "production", DEBUG: "myapp:*" }

105

});

106

107

// Dry run to see command

108

const command = runShell("docker", ["build", "-t", "myapp", "."], { dryRun: true });

109

console.log(command); // 'docker "build" "-t" "myapp" "."'

110

```

111

112

### Module Resolution

113

114

Intelligent module resolution that prioritizes project dependencies over bundled tools.

115

116

```typescript { .api }

117

/**

118

* Resolve CLI module path with project-first resolution

119

* @param cli - CLI module path to resolve

120

* @param options - Resolution options

121

* @returns Absolute path to the resolved CLI module

122

*/

123

function resolveCLI(

124

cli: string,

125

options?: { resolveFromProjectFirst?: boolean }

126

): string;

127

128

/**

129

* Resolve CLI from project dependencies only

130

* @param cli - CLI module path to resolve

131

* @param projectRootDir - Project root directory (defaults to process.cwd())

132

* @returns Absolute path to CLI module or undefined if not found

133

*/

134

function resolveCLIFromProject(

135

cli: string,

136

projectRootDir?: string

137

): string | undefined;

138

139

/**

140

* Extract package name from CLI module path

141

* @param cli - CLI module path (e.g., "typescript/lib/tsc", "@babel/cli/bin/babel")

142

* @returns Package name (e.g., "typescript", "@babel/cli")

143

*/

144

function getPackageName(cli: string): string;

145

```

146

147

**Resolution Examples:**

148

149

```typescript

150

import { resolveCLI, resolveCLIFromProject, getPackageName } from "@loopback/build";

151

152

// Resolve TypeScript compiler

153

const tscPath = resolveCLI("typescript/lib/tsc");

154

// Returns: "/project/node_modules/typescript/lib/tsc.js" (project version)

155

// Falls back to: "/node_modules/@loopback/build/node_modules/typescript/lib/tsc.js"

156

157

// Force resolution from project only

158

const projectTsc = resolveCLIFromProject("typescript/lib/tsc");

159

// Returns: "/project/node_modules/typescript/lib/tsc.js" or undefined

160

161

// Extract package names

162

const pkgName1 = getPackageName("typescript/lib/tsc"); // "typescript"

163

const pkgName2 = getPackageName("@babel/cli/bin/babel"); // "@babel/cli"

164

const pkgName3 = getPackageName("eslint/bin/eslint"); // "eslint"

165

166

// Skip project resolution (use bundled version)

167

const bundledEslint = resolveCLI("eslint/bin/eslint", {

168

resolveFromProjectFirst: false

169

});

170

```

171

172

### Configuration and Utility Functions

173

174

Helper functions for configuration file discovery and CLI option processing.

175

176

```typescript { .api }

177

/**

178

* Get configuration file with fallback support

179

* @param name - Preferred configuration file name

180

* @param defaultName - Default fallback file name

181

* @returns Path to discovered configuration file

182

*/

183

function getConfigFile(name: string, defaultName?: string): string;

184

185

/**

186

* Get root directory of @loopback/build module

187

* @returns Absolute path to @loopback/build root directory

188

*/

189

function getRootDir(): string;

190

191

/**

192

* Get root directory of current npm package

193

* @returns Absolute path to current working directory

194

*/

195

function getPackageDir(): string;

196

197

/**

198

* Check if CLI options contain specified option names

199

* @param opts - Array of CLI option strings

200

* @param optionNames - Option names to check for

201

* @returns True if any option name is found

202

*/

203

function isOptionSet(opts: string[], ...optionNames: string[]): boolean;

204

205

/**

206

* Check if project has Mocha configuration files

207

* @returns True if any Mocha config file exists in project

208

*/

209

function mochaConfiguredForProject(): boolean;

210

```

211

212

**Utility Examples:**

213

214

```typescript

215

import {

216

getConfigFile,

217

getRootDir,

218

getPackageDir,

219

isOptionSet,

220

mochaConfiguredForProject

221

} from "@loopback/build";

222

223

// Find configuration files

224

const tsconfigPath = getConfigFile("tsconfig.build.json", "tsconfig.json");

225

const eslintrcPath = getConfigFile(".eslintrc.js", ".eslintrc.json");

226

227

// Get directory paths

228

const buildToolsRoot = getRootDir(); // "/node_modules/@loopback/build"

229

const projectRoot = getPackageDir(); // "/current/working/directory"

230

231

// Check CLI options

232

const opts = ["--fix", "--ext", ".ts", "src/"];

233

const hasFixFlag = isOptionSet(opts, "--fix"); // true

234

const hasConfigFlag = isOptionSet(opts, "-c", "--config"); // false

235

const hasExtFlag = isOptionSet(opts, "--ext"); // true

236

237

// Check project configuration

238

const hasMochaConfig = mochaConfiguredForProject();

239

// Checks for: .mocharc.js, .mocharc.json, .mocharc.yaml, .mocharc.yml

240

```

241

242

### Process Management and Error Handling

243

244

Comprehensive process management with proper error handling and exit code propagation.

245

246

```typescript { .api }

247

/**

248

* Process management features:

249

* - Proper stdio inheritance for interactive commands

250

* - Exit code propagation to parent process

251

* - Signal handling for graceful shutdowns

252

* - Cross-platform process spawning

253

* - Environment variable inheritance and customization

254

*/

255

256

interface ProcessFeatures {

257

stdioInheritance: "inherit"; // Pass stdio to child processes

258

exitCodePropagation: boolean; // Set process.exitCode on child exit

259

signalHandling: boolean; // Handle SIGTERM, SIGINT, etc.

260

crossPlatform: boolean; // Windows and Unix compatibility

261

environmentVariables: boolean; // Custom env var support

262

}

263

```

264

265

**Error Handling Examples:**

266

267

```typescript

268

import { runCLI, runShell } from "@loopback/build";

269

270

// Error handling with callbacks

271

const child = runCLI("eslint/bin/eslint", ["src/"]);

272

273

child.on('close', (code, signal) => {

274

if (code !== 0) {

275

console.error(`ESLint exited with code ${code}`);

276

process.exit(code);

277

}

278

});

279

280

// Shell command error handling

281

const shellChild = runShell("npm", ["test"]);

282

283

shellChild.on('error', (error) => {

284

console.error('Failed to start process:', error);

285

});

286

287

shellChild.on('close', (code, signal) => {

288

if (signal === 'SIGKILL') {

289

console.warn('Process was killed');

290

}

291

});

292

```

293

294

### Advanced Usage Patterns

295

296

Advanced patterns for complex build workflows and integrations.

297

298

**Pipeline Execution:**

299

300

```typescript

301

import { runCLI, runShell } from "@loopback/build";

302

303

async function buildPipeline() {

304

// Clean build artifacts

305

await new Promise(resolve => {

306

const clean = runShell("rm", ["-rf", "dist"]);

307

clean.on('close', resolve);

308

});

309

310

// Compile TypeScript

311

await new Promise(resolve => {

312

const tsc = runCLI("typescript/lib/tsc", []);

313

tsc.on('close', resolve);

314

});

315

316

// Run tests

317

await new Promise(resolve => {

318

const mocha = runCLI("mocha/bin/mocha", ["dist/__tests__"]);

319

mocha.on('close', resolve);

320

});

321

}

322

```

323

324

**Custom Tool Integration:**

325

326

```typescript

327

import { runCLI, resolveCLI } from "@loopback/build";

328

329

// Custom TypeScript plugin workflow

330

function runWithTTypescript() {

331

try {

332

// Try to use project's ttypescript

333

const ttscPath = resolveCLI("ttypescript/lib/tsc");

334

return runCLI("ttypescript/lib/tsc", process.argv.slice(2));

335

} catch (error) {

336

// Fall back to regular TypeScript

337

console.warn("ttypescript not found, using regular tsc");

338

return runCLI("typescript/lib/tsc", process.argv.slice(2));

339

}

340

}

341

342

// Conditional tool execution

343

function runLinter(fix = false) {

344

const args = ["."];

345

if (fix) args.unshift("--fix");

346

347

return runCLI("eslint/bin/eslint", args, {

348

nodeArgs: ["--max-old-space-size=4096"] // More memory for large projects

349

});

350

}

351

```

352

353

### TypeScript Path Resolution

354

355

Special handling for TypeScript installation path discovery.

356

357

```typescript { .api }

358

/**

359

* Resolved path to TypeScript installation

360

* Points to the directory containing TypeScript package

361

*/

362

const typeScriptPath: string;

363

364

// Usage example:

365

import { typeScriptPath } from "@loopback/build";

366

import path from "path";

367

368

const tscBin = path.join(typeScriptPath, "bin", "tsc");

369

const tsLib = path.join(typeScriptPath, "lib");

370

```