or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mddevkit-core.mddevkit-files.mddevkit-tasks.mdgenerators-executors.mdindex.mdplugins.md

devkit-tasks.mddocs/

0

# Task System

1

2

Task execution, caching, and orchestration APIs for building advanced build tools and custom task runners.

3

4

## Capabilities

5

6

### Task Execution

7

8

Functions for running executors and tasks programmatically.

9

10

```typescript { .api }

11

/**

12

* Runs an executor programmatically

13

* @param targetDescription - Target to execute (project:target:configuration)

14

* @param overrides - Options to override target configuration

15

* @param context - Execution context

16

* @returns Async iterator yielding execution results

17

*/

18

function runExecutor<T = any>(

19

targetDescription: Target,

20

overrides: Partial<T>,

21

context: ExecutorContext

22

): Promise<AsyncIterableIterator<{ success: boolean; [key: string]: any }>>;

23

24

/**

25

* Parses a target string into its components

26

* @param targetString - Target in format "project:target" or "project:target:configuration"

27

* @returns Parsed target object

28

*/

29

function parseTargetString(targetString: string): Target;

30

31

/**

32

* Converts target object to string representation

33

* @param target - Target object

34

* @returns Target string in format "project:target:configuration"

35

*/

36

function targetToTargetString(target: Target): string;

37

38

interface Target {

39

project: string;

40

target: string;

41

configuration?: string;

42

}

43

44

interface ExecutorContext {

45

/** Workspace root directory */

46

root: string;

47

/** Current working directory */

48

cwd: string;

49

/** Workspace configuration */

50

workspace: WorkspaceJsonConfiguration;

51

/** Whether verbose logging is enabled */

52

isVerbose: boolean;

53

/** Name of the project being executed */

54

projectName?: string;

55

/** Name of the target being executed */

56

targetName?: string;

57

/** Name of the configuration being used */

58

configurationName?: string;

59

/** Graph of all projects */

60

projectGraph?: ProjectGraph;

61

/** Task graph for current execution */

62

taskGraph?: TaskGraph;

63

/** Hash of the current task */

64

hash?: string;

65

}

66

```

67

68

### Task Graph Operations

69

70

Functions for working with task dependency graphs and task orchestration.

71

72

```typescript { .api }

73

/**

74

* Creates a task graph from target dependencies

75

* @param projectGraph - Project dependency graph

76

* @param targets - Array of targets to execute

77

* @param nxJson - Nx configuration

78

* @param overrides - Task overrides

79

* @returns Task graph with dependencies

80

*/

81

function createTaskGraph(

82

projectGraph: ProjectGraph,

83

targets: Target[],

84

nxJson: NxJsonConfiguration,

85

overrides: { [target: string]: any }

86

): TaskGraph;

87

88

/**

89

* Maps targets to projects for task graph creation

90

* @param targets - Array of targets

91

* @param projectGraph - Project dependency graph

92

* @returns Map of project names to target arrays

93

*/

94

function groupTargetsByProject(

95

targets: Target[],

96

projectGraph: ProjectGraph

97

): Map<string, Target[]>;

98

99

interface TaskGraph {

100

/** Map of task IDs to task definitions */

101

tasks: Record<string, Task>;

102

/** Map of task IDs to their dependency task IDs */

103

dependencies: Record<string, string[]>;

104

/** Array of root task IDs (tasks with no dependencies) */

105

roots: string[];

106

}

107

108

interface Task {

109

/** Unique task identifier */

110

id: string;

111

/** Target being executed */

112

target: Target;

113

/** Project root path */

114

projectRoot: string;

115

/** Override options for this task */

116

overrides: any;

117

/** Hash representing task inputs */

118

hash?: string;

119

/** Array of output paths for this task */

120

outputs?: string[];

121

}

122

```

123

124

### Task Hashing and Caching

125

126

APIs for computing task hashes and managing task caching.

127

128

```typescript { .api }

129

/**

130

* Task hasher for computing deterministic task hashes

131

*/

132

interface TaskHasher {

133

/** Hashes a single task */

134

hashTask(task: Task): Promise<string>;

135

/** Hashes multiple tasks in batch */

136

hashTasks(tasks: Task[]): Promise<Record<string, string>>;

137

}

138

139

/**

140

* Creates a task hasher instance

141

* @param projectGraph - Project dependency graph

142

* @param nxJson - Nx configuration

143

* @returns Task hasher instance

144

*/

145

function createTaskHasher(

146

projectGraph: ProjectGraph,

147

nxJson: NxJsonConfiguration

148

): TaskHasher;

149

150

/**

151

* Hash computation utilities

152

*/

153

function hashArray(values: string[]): string;

154

function hashObject(obj: any): string;

155

156

interface FileData {

157

file: string;

158

hash: string;

159

}

160

161

/**

162

* Computes hash for workspace files

163

* @param workspaceRoot - Workspace root directory

164

* @param globs - Array of glob patterns to include

165

* @returns Promise resolving to file data with hashes

166

*/

167

function hashFiles(workspaceRoot: string, globs: string[]): Promise<FileData[]>;

168

```

169

170

### Task Runner Integration

171

172

Types and utilities for integrating with Nx task runners.

173

174

```typescript { .api }

175

/**

176

* Task runner interface for custom task execution

177

*/

178

interface TasksRunner {

179

invoke(

180

tasks: Task[],

181

options: any,

182

context?: TasksRunnerContext

183

): Promise<{ [taskId: string]: TaskResult }>;

184

}

185

186

interface TasksRunnerContext {

187

target?: string;

188

initiatingProject?: string;

189

projectGraph: ProjectGraph;

190

nxJson: NxJsonConfiguration;

191

hasher: TaskHasher;

192

}

193

194

interface TaskResult {

195

success: boolean;

196

code?: number;

197

terminalOutput?: string;

198

startTime?: number;

199

endTime?: number;

200

}

201

202

/**

203

* Default task runner options

204

*/

205

interface DefaultTasksRunnerOptions {

206

parallel?: number;

207

maxParallel?: number;

208

cacheableOperations?: string[];

209

runtimeCacheInputs?: string[];

210

cacheDirectory?: string;

211

remoteCache?: RemoteCacheOptions;

212

}

213

214

interface RemoteCacheOptions {

215

enabled?: boolean;

216

url?: string;

217

timeout?: number;

218

}

219

```

220

221

### Executor Development

222

223

Types and utilities for creating custom executors.

224

225

```typescript { .api }

226

/**

227

* Executor function signature

228

*/

229

type Executor<T = any> = (

230

options: T,

231

context: ExecutorContext

232

) => Promise<{ success: boolean; [key: string]: any }> |

233

AsyncIterableIterator<{ success: boolean; [key: string]: any }>;

234

235

/**

236

* Promise-based executor signature

237

*/

238

type PromiseExecutor<T = any> = (

239

options: T,

240

context: ExecutorContext

241

) => Promise<{ success: boolean; [key: string]: any }>;

242

243

/**

244

* Creates an executor that converts async iterators to promises

245

* @param executor - Async iterator executor

246

* @returns Promise-based executor

247

*/

248

function convertToPromiseExecutor<T>(

249

executor: Executor<T>

250

): PromiseExecutor<T>;

251

252

/**

253

* Schema validation for executor options

254

*/

255

interface ExecutorSchema {

256

version: number;

257

title: string;

258

description?: string;

259

type: 'object';

260

properties: Record<string, any>;

261

additionalProperties?: boolean;

262

required?: string[];

263

}

264

```

265

266

## Usage Examples

267

268

### Running Tasks Programmatically

269

270

```typescript

271

import {

272

runExecutor,

273

parseTargetString,

274

ExecutorContext,

275

logger

276

} from "nx/src/devkit-exports";

277

278

async function buildProject(projectName: string) {

279

const target = parseTargetString(`${projectName}:build`);

280

281

const context: ExecutorContext = {

282

root: process.cwd(),

283

cwd: process.cwd(),

284

workspace: readWorkspaceConfiguration(),

285

isVerbose: false,

286

projectName: target.project,

287

targetName: target.target

288

};

289

290

try {

291

const results = await runExecutor(target, {}, context);

292

293

for await (const result of results) {

294

if (result.success) {

295

logger.info(`✅ ${projectName}:build completed successfully`);

296

} else {

297

logger.error(`❌ ${projectName}:build failed`);

298

return false;

299

}

300

}

301

302

return true;

303

} catch (error) {

304

logger.error(`Failed to run ${projectName}:build: ${error.message}`);

305

return false;

306

}

307

}

308

```

309

310

### Custom Task Runner

311

312

```typescript

313

import {

314

Task,

315

TasksRunner,

316

TasksRunnerContext,

317

TaskResult,

318

logger

319

} from "nx/src/devkit-exports";

320

321

class CustomTasksRunner implements TasksRunner {

322

async invoke(

323

tasks: Task[],

324

options: any,

325

context?: TasksRunnerContext

326

): Promise<{ [taskId: string]: TaskResult }> {

327

const results: { [taskId: string]: TaskResult } = {};

328

329

logger.info(`Executing ${tasks.length} tasks`);

330

331

for (const task of tasks) {

332

const startTime = Date.now();

333

334

try {

335

// Execute task using runExecutor

336

const target = task.target;

337

const executorContext: ExecutorContext = {

338

root: context.projectGraph.nodes[target.project].data.root,

339

cwd: process.cwd(),

340

workspace: {} as any, // Would normally load workspace config

341

isVerbose: false,

342

projectName: target.project,

343

targetName: target.target,

344

configurationName: target.configuration,

345

projectGraph: context.projectGraph,

346

hash: task.hash

347

};

348

349

const executorResults = await runExecutor(target, task.overrides, executorContext);

350

let success = true;

351

352

for await (const result of executorResults) {

353

success = success && result.success;

354

}

355

356

results[task.id] = {

357

success,

358

startTime,

359

endTime: Date.now()

360

};

361

362

} catch (error) {

363

results[task.id] = {

364

success: false,

365

startTime,

366

endTime: Date.now(),

367

terminalOutput: error.message

368

};

369

}

370

}

371

372

return results;

373

}

374

}

375

376

export default CustomTasksRunner;

377

```

378

379

### Task Graph Analysis

380

381

```typescript

382

import {

383

createTaskGraph,

384

parseTargetString,

385

createProjectGraphAsync,

386

readNxJson,

387

logger

388

} from "nx/src/devkit-exports";

389

390

async function analyzeTaskDependencies(targetStrings: string[]) {

391

const projectGraph = await createProjectGraphAsync();

392

const nxJson = readNxJson();

393

394

// Parse target strings

395

const targets = targetStrings.map(parseTargetString);

396

397

// Create task graph

398

const taskGraph = createTaskGraph(projectGraph, targets, nxJson, {});

399

400

logger.info(`Task Graph Analysis:`);

401

logger.info(` Total tasks: ${Object.keys(taskGraph.tasks).length}`);

402

logger.info(` Root tasks: ${taskGraph.roots.length}`);

403

404

// Find task dependencies

405

for (const [taskId, task] of Object.entries(taskGraph.tasks)) {

406

const dependencies = taskGraph.dependencies[taskId] || [];

407

logger.info(` ${task.target.project}:${task.target.target} depends on: ${dependencies.length} tasks`);

408

}

409

410

return taskGraph;

411

}

412

```

413

414

### Custom Executor Implementation

415

416

```typescript

417

import { ExecutorContext, logger } from "nx/src/devkit-exports";

418

419

interface CustomBuildOptions {

420

command: string;

421

args?: string[];

422

cwd?: string;

423

env?: Record<string, string>;

424

}

425

426

export default async function customBuildExecutor(

427

options: CustomBuildOptions,

428

context: ExecutorContext

429

): Promise<{ success: boolean }> {

430

logger.info(`Running custom build for ${context.projectName}`);

431

432

const { spawn } = await import('child_process');

433

434

return new Promise((resolve) => {

435

const child = spawn(options.command, options.args || [], {

436

cwd: options.cwd || context.root,

437

env: { ...process.env, ...options.env },

438

stdio: 'inherit'

439

});

440

441

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

442

const success = code === 0;

443

444

if (success) {

445

logger.info(`✅ Custom build completed successfully`);

446

} else {

447

logger.error(`❌ Custom build failed with code ${code}`);

448

}

449

450

resolve({ success });

451

});

452

453

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

454

logger.error(`Failed to start custom build: ${error.message}`);

455

resolve({ success: false });

456

});

457

});

458

}

459

460

// Executor schema (schema.json)

461

export const schema: ExecutorSchema = {

462

version: 1,

463

title: 'Custom Build Executor',

464

description: 'Runs a custom build command',

465

type: 'object',

466

properties: {

467

command: {

468

type: 'string',

469

description: 'Command to execute'

470

},

471

args: {

472

type: 'array',

473

description: 'Command arguments',

474

items: { type: 'string' }

475

},

476

cwd: {

477

type: 'string',

478

description: 'Working directory'

479

},

480

env: {

481

type: 'object',

482

description: 'Environment variables'

483

}

484

},

485

required: ['command']

486

};

487

```

488

489

### Task Caching

490

491

```typescript

492

import {

493

createTaskHasher,

494

createProjectGraphAsync,

495

readNxJson,

496

Task,

497

logger

498

} from "nx/src/devkit-exports";

499

500

async function computeTaskHashes(tasks: Task[]) {

501

const projectGraph = await createProjectGraphAsync();

502

const nxJson = readNxJson();

503

504

const hasher = createTaskHasher(projectGraph, nxJson);

505

506

logger.info('Computing task hashes...');

507

508

const hashes = await hasher.hashTasks(tasks);

509

510

for (const [taskId, hash] of Object.entries(hashes)) {

511

const task = tasks.find(t => t.id === taskId);

512

logger.info(`${task.target.project}:${task.target.target} -> ${hash}`);

513

}

514

515

return hashes;

516

}

517

```