or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcommands.mdexceptions.mdindex.mdio.mdstyling.mdtesting.mdui.md

commands.mddocs/

0

# Command Development System

1

2

The command development system provides the foundation for creating individual CLI commands with arguments, options, and business logic. Commands inherit from base classes and define their interface through class attributes and method implementations.

3

4

## Capabilities

5

6

### Base Command Structure

7

8

Abstract base class that defines the fundamental command interface and lifecycle.

9

10

```python { .api }

11

class BaseCommand:

12

name: str | None = None # Command name (required)

13

description: str = "" # Short description for help

14

help: str = "" # Detailed help text

15

enabled: bool = True # Whether command is enabled

16

hidden: bool = False # Whether to hide from command lists

17

18

def configure(self) -> None:

19

"""Configure the command definition. Called during initialization."""

20

21

def execute(self, io: IO) -> int:

22

"""

23

Execute the command with provided IO.

24

25

Args:

26

io (IO): Input/output interface

27

28

Returns:

29

int: Exit code (0 for success)

30

"""

31

32

def run(self, io: IO) -> int:

33

"""

34

Run the command through the full lifecycle.

35

36

Args:

37

io (IO): Input/output interface

38

39

Returns:

40

int: Exit code from execution

41

"""

42

```

43

44

### Full-Featured Command Class

45

46

Complete command implementation with UI helpers and convenience methods.

47

48

```python { .api }

49

class Command(BaseCommand):

50

arguments: ClassVar[list[Argument]] = [] # Command arguments definition

51

options: ClassVar[list[Option]] = [] # Command options definition

52

aliases: ClassVar[list[str]] = [] # Command aliases

53

usages: ClassVar[list[str]] = [] # Usage examples

54

commands: ClassVar[list[BaseCommand]] = [] # Sub-commands

55

56

def __init__(self) -> None: ...

57

58

@property

59

def io(self) -> IO:

60

"""Get the IO interface for this command."""

61

62

def handle(self) -> int:

63

"""

64

Command business logic implementation (abstract).

65

66

Returns:

67

int: Exit code (0 for success)

68

"""

69

70

# Command execution methods

71

def call(self, name: str, args: str | None = None) -> int: ...

72

def call_silent(self, name: str, args: str | None = None) -> int: ...

73

74

# User interaction methods

75

def confirm(self, question: str, default: bool = False, true_answer_regex: str = r"(?i)^y") -> bool: ...

76

def ask(self, question: str | Question, default: Any | None = None) -> Any: ...

77

def secret(self, question: str | Question, default: Any | None = None) -> Any: ...

78

def choice(self, question: str, choices: list[str], default: Any | None = None,

79

attempts: int | None = None, multiple: bool = False) -> Any: ...

80

81

# Output methods

82

def write(self, text: str, style: str | None = None) -> None: ...

83

def line_error(self, text: str, style: str | None = None, verbosity: Verbosity = Verbosity.NORMAL) -> None: ...

84

def info(self, text: str) -> None: ...

85

def comment(self, text: str) -> None: ...

86

def question(self, text: str) -> None: ...

87

def overwrite(self, text: str) -> None: ...

88

89

# Table rendering

90

def table(self, header: str | None = None, rows: Rows | None = None, style: str | None = None) -> Table: ...

91

def table_separator(self) -> TableSeparator: ...

92

def render_table(self, headers: str, rows: Rows, style: str | None = None) -> None: ...

93

94

# Progress indicators

95

def progress_bar(self, max: int = 0) -> ProgressBar: ...

96

def progress_indicator(self, fmt: str | None = None, interval: int = 100, values: list[str] | None = None) -> ProgressIndicator: ...

97

def spin(self, start_message: str, end_message: str, fmt: str | None = None,

98

interval: int = 100, values: list[str] | None = None) -> ContextManager[ProgressIndicator]: ...

99

100

# Styling

101

def add_style(self, name: str, fg: str | None = None, bg: str | None = None, options: list[str] | None = None) -> None: ...

102

103

# Utility

104

def create_question(self, question: str, type: Literal["choice", "confirmation"] | None = None, **kwargs: Any) -> Question: ...

105

```

106

107

### Argument and Option Access

108

109

Access command arguments and options provided by the user.

110

111

```python { .api }

112

def argument(self, name: str) -> Any:

113

"""

114

Get an argument value by name.

115

116

Args:

117

name (str): Argument name

118

119

Returns:

120

Any: Argument value or None if not provided

121

"""

122

123

def option(self, name: str) -> Any:

124

"""

125

Get an option value by name.

126

127

Args:

128

name (str): Option name

129

130

Returns:

131

Any: Option value, default value, or None

132

"""

133

```

134

135

### Argument and Option Definition Helpers

136

137

Helper functions to create argument and option definitions for commands.

138

139

```python { .api }

140

def argument(name: str, description: str | None = None, optional: bool = False,

141

multiple: bool = False, default: Any | None = None) -> Argument:

142

"""

143

Create an argument definition.

144

145

Args:

146

name (str): Argument name

147

description (str | None): Help description

148

optional (bool): Whether argument is optional

149

multiple (bool): Whether argument accepts multiple values

150

default (Any | None): Default value for optional arguments

151

152

Returns:

153

Argument: Configured argument definition

154

"""

155

156

def option(long_name: str, short_name: str | None = None, description: str | None = None,

157

flag: bool = True, value_required: bool = True, multiple: bool = False,

158

default: Any | None = None) -> Option:

159

"""

160

Create an option definition.

161

162

Args:

163

long_name (str): Long option name (--option)

164

short_name (str | None): Short option name (-o)

165

description (str | None): Help description

166

flag (bool): Whether this is a boolean flag

167

value_required (bool): Whether option requires a value

168

multiple (bool): Whether option accepts multiple values

169

default (Any | None): Default value

170

171

Returns:

172

Option: Configured option definition

173

"""

174

```

175

176

### Output and Interaction Methods

177

178

Methods for producing output and interacting with users.

179

180

```python { .api }

181

def line(self, text: str, style: str | None = None, verbosity: Verbosity = Verbosity.NORMAL) -> None:

182

"""

183

Write a line of text to output.

184

185

Args:

186

text (str): Text to output

187

style (str | None): Style name for formatting

188

verbosity (Verbosity | None): Minimum verbosity level

189

"""

190

191

def write(self, text: str, new_line: bool = False, verbosity: Verbosity | None = None) -> None:

192

"""

193

Write text to output.

194

195

Args:

196

text (str): Text to output

197

new_line (bool): Whether to add a newline

198

verbosity (Verbosity | None): Minimum verbosity level

199

"""

200

201

def confirm(self, question: str, default: bool = False) -> bool:

202

"""

203

Ask a yes/no confirmation question.

204

205

Args:

206

question (str): Question text

207

default (bool): Default answer

208

209

Returns:

210

bool: User's answer

211

"""

212

213

def ask(self, question: str | Question, default: Any | None = None) -> Any:

214

"""

215

Ask a question and get user input.

216

217

Args:

218

question (str | Question): Question text or Question object

219

default (Any | None): Default answer

220

221

Returns:

222

Any: User's answer

223

"""

224

225

def choice(self, question: str, choices: list[str], default: Any | None = None) -> Any:

226

"""

227

Ask a multiple choice question.

228

229

Args:

230

question (str): Question text

231

choices (list[str]): Available choices

232

default (Any | None): Default choice

233

234

Returns:

235

Any: Selected choice

236

"""

237

```

238

239

### Command Execution and Control Flow

240

241

Methods for controlling command execution and calling other commands.

242

243

```python { .api }

244

def call(self, command: str, args: str = "") -> int:

245

"""

246

Call another command from this command.

247

248

Args:

249

command (str): Command name to call

250

args (str): Arguments to pass to the command

251

252

Returns:

253

int: Exit code from called command

254

"""

255

256

def call_silent(self, command: str, args: str = "") -> int:

257

"""

258

Call another command silently (suppressing output).

259

260

Args:

261

command (str): Command name to call

262

args (str): Arguments to pass

263

264

Returns:

265

int: Exit code from called command

266

"""

267

```

268

269

### Style and Formatting Methods

270

271

Methods for adding custom styles and formatting output.

272

273

```python { .api }

274

def add_style(self, name: str, fg: str | None = None, bg: str | None = None,

275

options: list[str] | None = None) -> None:

276

"""

277

Add a custom style for text formatting.

278

279

Args:

280

name (str): Style name

281

fg (str | None): Foreground color

282

bg (str | None): Background color

283

options (list[str] | None): Formatting options (bold, underscore, etc.)

284

"""

285

```

286

287

## Input Definition Components

288

289

### Argument Class

290

291

Defines command arguments with validation and type information.

292

293

```python { .api }

294

class Argument:

295

def __init__(self, name: str, required: bool = True, is_list: bool = False,

296

description: str | None = None, default: Any | None = None): ...

297

298

@property

299

def name(self) -> str: ...

300

301

@property

302

def is_required(self) -> bool: ...

303

304

@property

305

def is_optional(self) -> bool: ...

306

307

@property

308

def is_list(self) -> bool: ...

309

310

@property

311

def description(self) -> str: ...

312

313

@property

314

def default(self) -> Any: ...

315

```

316

317

### Option Class

318

319

Defines command options with flags, values, and validation.

320

321

```python { .api }

322

class Option:

323

def __init__(self, name: str, shortcut: str | None = None, flag: bool = True,

324

requires_value: bool = True, is_list: bool = False,

325

description: str | None = None, default: Any | None = None): ...

326

327

@property

328

def name(self) -> str: ...

329

330

@property

331

def shortcut(self) -> str: ...

332

333

@property

334

def is_flag(self) -> bool: ...

335

336

@property

337

def requires_value(self) -> bool: ...

338

339

@property

340

def is_list(self) -> bool: ...

341

342

@property

343

def description(self) -> str: ...

344

345

@property

346

def default(self) -> Any: ...

347

```

348

349

## Usage Examples

350

351

### Basic Command

352

353

```python

354

from cleo.commands.command import Command

355

from cleo.helpers import argument, option

356

357

class ProcessCommand(Command):

358

name = "process"

359

description = "Process data files"

360

arguments = [

361

argument("input_file", description="Input file path"),

362

argument("output_file", description="Output file path", optional=True)

363

]

364

options = [

365

option("format", "f", description="Output format", flag=False, default="json"),

366

option("verbose", "v", description="Verbose output", flag=True)

367

]

368

369

def handle(self):

370

input_file = self.argument("input_file")

371

output_file = self.argument("output_file") or f"{input_file}.processed"

372

format = self.option("format")

373

verbose = self.option("verbose")

374

375

if verbose:

376

self.line(f"Processing <info>{input_file}</info>")

377

378

# Process the file

379

result = self.process_file(input_file, format)

380

381

# Write output

382

with open(output_file, 'w') as f:

383

f.write(result)

384

385

self.line(f"<comment>Processed data written to {output_file}</comment>")

386

387

return 0

388

389

def process_file(self, file_path, format):

390

# Implementation here

391

return "processed data"

392

```

393

394

### Interactive Command with Questions

395

396

```python

397

class ConfigCommand(Command):

398

name = "config"

399

description = "Configure application settings"

400

401

def handle(self):

402

# Get configuration values interactively

403

host = self.ask("Database host", "localhost")

404

port = self.ask("Database port", 5432)

405

406

# Confirm settings

407

if self.confirm(f"Connect to {host}:{port}?", True):

408

# Multiple choice for environment

409

env = self.choice(

410

"Environment",

411

["development", "staging", "production"],

412

"development"

413

)

414

415

self.line(f"<info>Configuration saved for {env} environment</info>")

416

else:

417

self.line("<error>Configuration cancelled</error>")

418

return 1

419

420

return 0

421

```

422

423

### Command with Sub-commands

424

425

```python

426

class DatabaseCommand(Command):

427

name = "db"

428

description = "Database management commands"

429

430

def handle(self):

431

# Show available sub-commands

432

self.line("Available database commands:")

433

self.line(" db:migrate - Run database migrations")

434

self.line(" db:seed - Seed database with test data")

435

self.line(" db:reset - Reset database")

436

437

return 0

438

439

class MigrateCommand(Command):

440

name = "db:migrate"

441

description = "Run database migrations"

442

443

def handle(self):

444

self.line("Running migrations...")

445

# Migration logic here

446

self.line("<info>Migrations completed</info>")

447

return 0

448

```

449

450

### Command Calling Other Commands

451

452

```python

453

class DeployCommand(Command):

454

name = "deploy"

455

description = "Deploy the application"

456

457

def handle(self):

458

self.line("Starting deployment...")

459

460

# Run tests first

461

if self.call("test") != 0:

462

self.line("<error>Tests failed, aborting deployment</error>")

463

return 1

464

465

# Build the application

466

self.call("build", "--production")

467

468

# Deploy silently

469

result = self.call_silent("upload", "--target production")

470

471

if result == 0:

472

self.line("<info>Deployment successful!</info>")

473

else:

474

self.line("<error>Deployment failed</error>")

475

476

return result

477

```