or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdevent-management.mdindex.mdrenderers.mdtask-configuration.mdtask-management.md
tile.json

task-configuration.mddocs/

0

# Task Configuration

1

2

Individual task definition, execution control, and lifecycle management including skip conditions, retry logic, rollback functionality, and dynamic task behavior.

3

4

## Capabilities

5

6

### ListrTask Interface

7

8

Core interface for defining individual tasks with all available configuration options.

9

10

```typescript { .api }

11

/**

12

* Configuration interface for individual tasks

13

* @template Ctx - Context type shared between tasks

14

* @template Renderer - Renderer type for this task

15

* @template FallbackRenderer - Fallback renderer type

16

*/

17

interface ListrTask<Ctx, Renderer, FallbackRenderer> {

18

/** Task display title (can be dynamic) */

19

title?: string | any[];

20

21

/** Main task execution function */

22

task: ListrTaskFn<Ctx, Renderer, FallbackRenderer>;

23

24

/** Condition to determine if task should be enabled */

25

enabled?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>);

26

27

/** Condition or message for skipping the task */

28

skip?: boolean | string | ((ctx: Ctx) => boolean | string | Promise<boolean | string>);

29

30

/** Retry configuration for failed tasks */

31

retry?: number | ListrTaskRetry;

32

33

/** Rollback function to execute if task fails */

34

rollback?: ListrTaskFn<Ctx, Renderer, FallbackRenderer>;

35

36

/** Whether to exit immediately if this task fails */

37

exitOnError?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>);

38

39

/** Renderer-specific options for primary renderer */

40

rendererOptions?: ListrGetRendererTaskOptions<ListrGetRendererClassFromValue<Renderer>>;

41

42

/** Renderer-specific options for fallback renderer */

43

fallbackRendererOptions?: ListrGetRendererTaskOptions<ListrGetRendererClassFromValue<FallbackRenderer>>;

44

}

45

```

46

47

### Task Execution Function

48

49

The main function that defines what a task does during execution.

50

51

```typescript { .api }

52

/**

53

* Task execution function signature

54

* @template Ctx - Context type

55

* @template Renderer - Renderer type

56

* @template FallbackRenderer - Fallback renderer type

57

* @param ctx - Shared context object

58

* @param task - Task wrapper for manipulation and output

59

* @returns Void, promise, string output, observable, or subtask list

60

*/

61

type ListrTaskFn<Ctx, Renderer, FallbackRenderer> = (

62

ctx: Ctx,

63

task: TaskWrapper<Ctx, Renderer, FallbackRenderer>

64

) => void | ListrTaskResult<Ctx>;

65

66

/**

67

* Valid return types from task execution functions

68

*/

69

type ListrTaskResult<Ctx> =

70

| string

71

| Promise<any>

72

| Listr<Ctx, any, any>

73

| ReadableLike

74

| ObservableLike<any>;

75

```

76

77

### Retry Configuration

78

79

Advanced retry configuration for handling task failures with customizable delays and attempt limits.

80

81

```typescript { .api }

82

/**

83

* Retry configuration for failed tasks

84

*/

85

interface ListrTaskRetry {

86

/** Number of retry attempts */

87

tries: number;

88

/** Delay between retry attempts in milliseconds */

89

delay?: number;

90

}

91

```

92

93

**Usage Examples:**

94

95

### Basic Task Configuration

96

97

```typescript

98

import { Listr } from "listr2";

99

100

const tasks = new Listr([

101

{

102

title: "Simple task",

103

task: () => {

104

console.log("Executing task...");

105

}

106

},

107

{

108

title: "Async task with output",

109

task: async (ctx, task) => {

110

task.output = "Starting async operation...";

111

await new Promise(resolve => setTimeout(resolve, 2000));

112

task.output = "Async operation completed";

113

return "Task completed successfully";

114

}

115

}

116

]);

117

```

118

119

### Conditional Task Execution

120

121

```typescript

122

import { Listr } from "listr2";

123

124

interface BuildContext {

125

environment: 'development' | 'production';

126

skipTests: boolean;

127

}

128

129

const tasks = new Listr<BuildContext>([

130

{

131

title: "Install dependencies",

132

task: () => {

133

// Always runs

134

return Promise.resolve();

135

}

136

},

137

{

138

title: "Run tests",

139

enabled: (ctx) => !ctx.skipTests,

140

task: () => {

141

return Promise.resolve();

142

}

143

},

144

{

145

title: "Production build",

146

enabled: (ctx) => ctx.environment === 'production',

147

task: () => {

148

return Promise.resolve();

149

}

150

},

151

{

152

title: "Development build",

153

enabled: (ctx) => ctx.environment === 'development',

154

task: () => {

155

return Promise.resolve();

156

}

157

}

158

]);

159

160

await tasks.run({ environment: 'production', skipTests: false });

161

```

162

163

### Skip Conditions

164

165

```typescript

166

import { Listr } from "listr2";

167

168

const tasks = new Listr([

169

{

170

title: "Check prerequisites",

171

task: (ctx) => {

172

ctx.hasPrereqs = Math.random() > 0.5;

173

}

174

},

175

{

176

title: "Main task",

177

skip: (ctx) => !ctx.hasPrereqs ? "Prerequisites not met" : false,

178

task: () => {

179

return Promise.resolve();

180

}

181

},

182

{

183

title: "Always skipped task",

184

skip: "This task is always skipped",

185

task: () => {

186

return Promise.resolve();

187

}

188

}

189

]);

190

```

191

192

### Retry Logic

193

194

```typescript

195

import { Listr } from "listr2";

196

197

const tasks = new Listr([

198

{

199

title: "Flaky network request",

200

retry: 3, // Simple retry count

201

task: async () => {

202

if (Math.random() < 0.7) {

203

throw new Error("Network request failed");

204

}

205

return "Request successful";

206

}

207

},

208

{

209

title: "API call with delay",

210

retry: {

211

tries: 5,

212

delay: 1000 // 1 second delay between retries

213

},

214

task: async () => {

215

// Simulate API call that might fail

216

const response = await fetch("https://api.example.com/data");

217

if (!response.ok) {

218

throw new Error(`API request failed: ${response.status}`);

219

}

220

return response.json();

221

}

222

}

223

]);

224

```

225

226

### Rollback Functionality

227

228

```typescript

229

import { Listr } from "listr2";

230

231

interface DeployContext {

232

backupCreated: boolean;

233

deploymentId?: string;

234

}

235

236

const tasks = new Listr<DeployContext>([

237

{

238

title: "Create backup",

239

task: (ctx) => {

240

// Create backup logic

241

ctx.backupCreated = true;

242

return Promise.resolve();

243

}

244

},

245

{

246

title: "Deploy application",

247

task: (ctx) => {

248

ctx.deploymentId = "deploy-" + Date.now();

249

// Simulate deployment that might fail

250

if (Math.random() < 0.3) {

251

throw new Error("Deployment failed");

252

}

253

return Promise.resolve();

254

},

255

rollback: (ctx, task) => {

256

if (ctx.backupCreated && ctx.deploymentId) {

257

task.output = `Rolling back deployment ${ctx.deploymentId}...`;

258

// Rollback logic here

259

return Promise.resolve();

260

}

261

}

262

}

263

]);

264

```

265

266

### Dynamic Task Titles

267

268

```typescript

269

import { Listr } from "listr2";

270

271

const files = ["file1.txt", "file2.txt", "file3.txt"];

272

273

const tasks = new Listr(

274

files.map((file, index) => ({

275

title: `Processing ${file}`,

276

task: (ctx, task) => {

277

return new Promise(resolve => {

278

setTimeout(() => {

279

task.title = `✅ Processed ${file}`;

280

resolve(undefined);

281

}, 1000);

282

});

283

}

284

}))

285

);

286

```

287

288

### Observable and Stream Integration

289

290

```typescript

291

import { Listr } from "listr2";

292

import { Observable } from "rxjs";

293

import { spawn } from "child_process";

294

295

const tasks = new Listr([

296

{

297

title: "Observable task",

298

task: () => {

299

return new Observable(observer => {

300

let count = 0;

301

const interval = setInterval(() => {

302

observer.next(`Progress: ${++count}/10`);

303

if (count >= 10) {

304

observer.complete();

305

clearInterval(interval);

306

}

307

}, 100);

308

});

309

}

310

},

311

{

312

title: "Stream from child process",

313

task: (ctx, task) => {

314

const child = spawn('npm', ['install'], { cwd: process.cwd() });

315

316

// Pipe stdout to task output

317

child.stdout.on('data', (data) => {

318

task.output = data.toString();

319

});

320

321

return new Promise((resolve, reject) => {

322

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

323

if (code === 0) {

324

resolve(undefined);

325

} else {

326

reject(new Error(`Process exited with code ${code}`));

327

}

328

});

329

});

330

}

331

}

332

]);

333

```

334

335

### Error Handling Options

336

337

```typescript

338

import { Listr } from "listr2";

339

340

const tasks = new Listr([

341

{

342

title: "Critical task",

343

exitOnError: true, // Stop entire task list if this fails

344

task: () => {

345

if (Math.random() < 0.5) {

346

throw new Error("Critical failure");

347

}

348

return Promise.resolve();

349

}

350

},

351

{

352

title: "Non-critical task",

353

exitOnError: false, // Continue even if this fails

354

task: () => {

355

throw new Error("Non-critical failure");

356

}

357

},

358

{

359

title: "Context-dependent error handling",

360

exitOnError: (ctx) => ctx.strictMode === true,

361

task: () => {

362

throw new Error("Conditional failure");

363

}

364

}

365

]);

366

367

await tasks.run({ strictMode: false });

368

```

369

370

## Types

371

372

```typescript { .api }

373

interface ListrTaskMessage {

374

/** Error message if task failed */

375

error?: string;

376

/** Skip message if task was skipped */

377

skip?: string;

378

/** Rollback message during rollback operations */

379

rollback?: string;

380

/** Retry message during retry attempts */

381

retry?: { count: number; message?: string };

382

}

383

384

interface ListrTaskPrompt {

385

/** Current prompt instance */

386

prompt?: any;

387

/** Prompt error if prompt failed */

388

error?: Error;

389

}

390

391

/**

392

* Stream-like interface for task output

393

*/

394

interface ReadableLike {

395

readable: boolean;

396

read: (size?: number) => string | Buffer;

397

on: (eventName: 'data' | 'error' | 'end', listener: (data: Buffer | string) => void) => unknown;

398

}

399

400

/**

401

* Observable-like interface for task progress

402

*/

403

interface ObservableLike<T> {

404

subscribe: (observer: ObserverLike<T>) => unknown;

405

}

406

407

interface ObserverLike<T> {

408

next?: (value: T) => void;

409

error?: (error: any) => void;

410

complete?: () => void;

411

}

412

```