@pablozaiden/terminatui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +64 -43
  2. package/package.json +11 -8
  3. package/src/__tests__/application.test.ts +87 -68
  4. package/src/__tests__/buildCliCommand.test.ts +99 -119
  5. package/src/__tests__/builtins.test.ts +27 -75
  6. package/src/__tests__/command.test.ts +100 -131
  7. package/src/__tests__/configOnChange.test.ts +63 -0
  8. package/src/__tests__/context.test.ts +1 -26
  9. package/src/__tests__/helpCore.test.ts +227 -0
  10. package/src/__tests__/parser.test.ts +98 -244
  11. package/src/__tests__/registry.test.ts +33 -160
  12. package/src/__tests__/schemaToFields.test.ts +75 -158
  13. package/src/builtins/help.ts +12 -4
  14. package/src/builtins/settings.ts +18 -32
  15. package/src/builtins/version.ts +3 -3
  16. package/src/cli/output/colors.ts +1 -1
  17. package/src/cli/parser.ts +26 -95
  18. package/src/core/application.ts +192 -110
  19. package/src/core/command.ts +26 -9
  20. package/src/core/context.ts +31 -20
  21. package/src/core/help.ts +24 -18
  22. package/src/core/knownCommands.ts +13 -0
  23. package/src/core/logger.ts +39 -42
  24. package/src/core/registry.ts +5 -12
  25. package/src/index.ts +22 -137
  26. package/src/tui/TuiApplication.tsx +63 -120
  27. package/src/tui/TuiRoot.tsx +135 -0
  28. package/src/tui/adapters/factory.ts +19 -0
  29. package/src/tui/adapters/ink/InkRenderer.tsx +139 -0
  30. package/src/tui/adapters/ink/components/Button.tsx +12 -0
  31. package/src/tui/adapters/ink/components/Code.tsx +6 -0
  32. package/src/tui/adapters/ink/components/CodeHighlight.tsx +6 -0
  33. package/src/tui/adapters/ink/components/Container.tsx +5 -0
  34. package/src/tui/adapters/ink/components/Field.tsx +12 -0
  35. package/src/tui/adapters/ink/components/Label.tsx +24 -0
  36. package/src/tui/adapters/ink/components/MenuButton.tsx +12 -0
  37. package/src/tui/adapters/ink/components/MenuItem.tsx +17 -0
  38. package/src/tui/adapters/ink/components/Overlay.tsx +5 -0
  39. package/src/tui/adapters/ink/components/Panel.tsx +15 -0
  40. package/src/tui/adapters/ink/components/ScrollView.tsx +5 -0
  41. package/src/tui/adapters/ink/components/Select.tsx +44 -0
  42. package/src/tui/adapters/ink/components/Spacer.tsx +15 -0
  43. package/src/tui/adapters/ink/components/Spinner.tsx +5 -0
  44. package/src/tui/adapters/ink/components/TextInput.tsx +22 -0
  45. package/src/tui/adapters/ink/components/Value.tsx +7 -0
  46. package/src/tui/adapters/ink/keyboard.ts +97 -0
  47. package/src/tui/adapters/ink/utils.ts +16 -0
  48. package/src/tui/adapters/opentui/OpenTuiRenderer.tsx +119 -0
  49. package/src/tui/adapters/opentui/components/Button.tsx +13 -0
  50. package/src/tui/adapters/opentui/components/Code.tsx +12 -0
  51. package/src/tui/adapters/opentui/components/CodeHighlight.tsx +24 -0
  52. package/src/tui/adapters/opentui/components/Container.tsx +56 -0
  53. package/src/tui/adapters/opentui/components/Field.tsx +18 -0
  54. package/src/tui/adapters/opentui/components/Label.tsx +15 -0
  55. package/src/tui/adapters/opentui/components/MenuButton.tsx +14 -0
  56. package/src/tui/adapters/opentui/components/MenuItem.tsx +29 -0
  57. package/src/tui/adapters/opentui/components/Overlay.tsx +21 -0
  58. package/src/tui/adapters/opentui/components/Panel.tsx +78 -0
  59. package/src/tui/adapters/opentui/components/ScrollView.tsx +85 -0
  60. package/src/tui/adapters/opentui/components/Select.tsx +59 -0
  61. package/src/tui/adapters/opentui/components/Spacer.tsx +5 -0
  62. package/src/tui/adapters/opentui/components/Spinner.tsx +12 -0
  63. package/src/tui/adapters/opentui/components/TextInput.tsx +13 -0
  64. package/src/tui/adapters/opentui/components/Value.tsx +13 -0
  65. package/src/tui/{hooks → adapters/opentui/hooks}/useSpinner.ts +2 -11
  66. package/src/tui/adapters/opentui/keyboard.ts +61 -0
  67. package/src/tui/adapters/types.ts +71 -0
  68. package/src/tui/components/ActionButton.tsx +0 -36
  69. package/src/tui/components/CommandSelector.tsx +45 -92
  70. package/src/tui/components/ConfigForm.tsx +68 -42
  71. package/src/tui/components/FieldRow.tsx +0 -30
  72. package/src/tui/components/Header.tsx +14 -13
  73. package/src/tui/components/JsonHighlight.tsx +10 -17
  74. package/src/tui/components/ModalBase.tsx +38 -0
  75. package/src/tui/components/ResultsPanel.tsx +27 -36
  76. package/src/tui/components/StatusBar.tsx +24 -39
  77. package/src/tui/components/logColors.ts +12 -0
  78. package/src/tui/context/ClipboardContext.tsx +87 -0
  79. package/src/tui/context/ExecutorContext.tsx +139 -0
  80. package/src/tui/context/KeyboardContext.tsx +85 -71
  81. package/src/tui/context/LogsContext.tsx +35 -0
  82. package/src/tui/context/NavigationContext.tsx +194 -0
  83. package/src/tui/context/RendererContext.tsx +20 -0
  84. package/src/tui/context/TuiAppContext.tsx +58 -0
  85. package/src/tui/hooks/useActiveKeyHandler.ts +75 -0
  86. package/src/tui/hooks/useBackHandler.ts +34 -0
  87. package/src/tui/hooks/useClipboard.ts +40 -25
  88. package/src/tui/hooks/useClipboardProvider.ts +42 -0
  89. package/src/tui/hooks/useGlobalKeyHandler.ts +54 -0
  90. package/src/tui/modals/CliModal.tsx +82 -0
  91. package/src/tui/modals/EditorModal.tsx +207 -0
  92. package/src/tui/modals/LogsModal.tsx +98 -0
  93. package/src/tui/registry.ts +102 -0
  94. package/src/tui/screens/CommandSelectScreen.tsx +162 -0
  95. package/src/tui/screens/ConfigScreen.tsx +165 -0
  96. package/src/tui/screens/ErrorScreen.tsx +58 -0
  97. package/src/tui/screens/ResultsScreen.tsx +68 -0
  98. package/src/tui/screens/RunningScreen.tsx +72 -0
  99. package/src/tui/screens/ScreenBase.ts +6 -0
  100. package/src/tui/semantic/Button.tsx +7 -0
  101. package/src/tui/semantic/Code.tsx +7 -0
  102. package/src/tui/semantic/CodeHighlight.tsx +7 -0
  103. package/src/tui/semantic/Container.tsx +7 -0
  104. package/src/tui/semantic/Field.tsx +7 -0
  105. package/src/tui/semantic/Label.tsx +7 -0
  106. package/src/tui/semantic/MenuButton.tsx +7 -0
  107. package/src/tui/semantic/MenuItem.tsx +7 -0
  108. package/src/tui/semantic/Overlay.tsx +7 -0
  109. package/src/tui/semantic/Panel.tsx +7 -0
  110. package/src/tui/semantic/ScrollView.tsx +9 -0
  111. package/src/tui/semantic/Select.tsx +7 -0
  112. package/src/tui/semantic/Spacer.tsx +7 -0
  113. package/src/tui/semantic/Spinner.tsx +7 -0
  114. package/src/tui/semantic/TextInput.tsx +7 -0
  115. package/src/tui/semantic/Value.tsx +7 -0
  116. package/src/tui/semantic/types.ts +195 -0
  117. package/src/tui/theme.ts +25 -14
  118. package/src/tui/utils/buildCliCommand.ts +1 -0
  119. package/src/tui/utils/getEnumKeys.ts +3 -0
  120. package/src/tui/utils/parameterPersistence.ts +1 -0
  121. package/src/types/command.ts +0 -60
  122. package/.devcontainer/devcontainer.json +0 -19
  123. package/.devcontainer/install-prerequisites.sh +0 -49
  124. package/.github/workflows/copilot-setup-steps.yml +0 -32
  125. package/.github/workflows/pull-request.yml +0 -27
  126. package/.github/workflows/release-npm-package.yml +0 -81
  127. package/AGENTS.md +0 -31
  128. package/bun.lock +0 -236
  129. package/examples/tui-app/commands/config/app/get.ts +0 -66
  130. package/examples/tui-app/commands/config/app/index.ts +0 -27
  131. package/examples/tui-app/commands/config/app/set.ts +0 -86
  132. package/examples/tui-app/commands/config/index.ts +0 -32
  133. package/examples/tui-app/commands/config/user/get.ts +0 -65
  134. package/examples/tui-app/commands/config/user/index.ts +0 -27
  135. package/examples/tui-app/commands/config/user/set.ts +0 -61
  136. package/examples/tui-app/commands/greet.ts +0 -76
  137. package/examples/tui-app/commands/index.ts +0 -4
  138. package/examples/tui-app/commands/math.ts +0 -115
  139. package/examples/tui-app/commands/status.ts +0 -77
  140. package/examples/tui-app/index.ts +0 -35
  141. package/guides/01-hello-world.md +0 -96
  142. package/guides/02-adding-options.md +0 -103
  143. package/guides/03-multiple-commands.md +0 -163
  144. package/guides/04-subcommands.md +0 -206
  145. package/guides/05-interactive-tui.md +0 -194
  146. package/guides/06-config-validation.md +0 -264
  147. package/guides/07-async-cancellation.md +0 -336
  148. package/guides/08-complete-application.md +0 -537
  149. package/guides/README.md +0 -74
  150. package/src/__tests__/colors.test.ts +0 -127
  151. package/src/__tests__/commandClass.test.ts +0 -130
  152. package/src/__tests__/help.test.ts +0 -412
  153. package/src/__tests__/registryNew.test.ts +0 -160
  154. package/src/__tests__/table.test.ts +0 -146
  155. package/src/__tests__/tui.test.ts +0 -26
  156. package/src/builtins/index.ts +0 -4
  157. package/src/cli/help.ts +0 -174
  158. package/src/cli/index.ts +0 -3
  159. package/src/cli/output/index.ts +0 -2
  160. package/src/cli/output/table.ts +0 -141
  161. package/src/commands/help.ts +0 -50
  162. package/src/commands/index.ts +0 -1
  163. package/src/components/index.ts +0 -147
  164. package/src/core/index.ts +0 -15
  165. package/src/hooks/index.ts +0 -131
  166. package/src/registry/commandRegistry.ts +0 -77
  167. package/src/registry/index.ts +0 -1
  168. package/src/tui/TuiApp.tsx +0 -619
  169. package/src/tui/app.ts +0 -29
  170. package/src/tui/components/CliModal.tsx +0 -81
  171. package/src/tui/components/EditorModal.tsx +0 -177
  172. package/src/tui/components/LogsPanel.tsx +0 -86
  173. package/src/tui/components/index.ts +0 -13
  174. package/src/tui/context/index.ts +0 -7
  175. package/src/tui/hooks/index.ts +0 -35
  176. package/src/tui/hooks/useKeyboardHandler.ts +0 -91
  177. package/src/tui/hooks/useLogStream.ts +0 -96
  178. package/src/tui/index.ts +0 -65
  179. package/src/tui/utils/index.ts +0 -13
  180. package/src/types/index.ts +0 -1
  181. package/tsconfig.json +0 -25
@@ -1,537 +0,0 @@
1
- # Guide 8: Building a Complete Application (Complex)
2
-
3
- Bring together everything to build a production-ready CLI application with multiple commands, services, logging, and a polished TUI.
4
-
5
- ## What You'll Build
6
-
7
- A task management CLI with:
8
- - Multiple commands: list, add, complete, stats
9
- - Shared services (database, notifications)
10
- - Logging with configurable verbosity
11
- - Full TUI support with custom result rendering
12
- - Config validation and type safety
13
-
14
- ```bash
15
- tasks add "Write documentation" --priority high
16
- tasks list --filter pending
17
- tasks complete abc123
18
- tasks stats
19
- tasks --tui # Interactive mode
20
- ```
21
-
22
- ## Project Structure
23
-
24
- ```
25
- src/
26
- ├── index.ts # Application entry
27
- ├── services/
28
- │ ├── database.ts # Task storage
29
- │ └── notifications.ts # Task notifications
30
- ├── commands/
31
- │ ├── add.ts
32
- │ ├── list.ts
33
- │ ├── complete.ts
34
- │ └── stats.ts
35
- └── types.ts # Shared types
36
- ```
37
-
38
- ## Step 1: Define Shared Types
39
-
40
- Create `src/types.ts`:
41
-
42
- ```typescript
43
- export interface Task {
44
- id: string;
45
- title: string;
46
- priority: "low" | "medium" | "high";
47
- status: "pending" | "completed";
48
- createdAt: Date;
49
- completedAt?: Date;
50
- }
51
-
52
- export interface TaskStats {
53
- total: number;
54
- pending: number;
55
- completed: number;
56
- byPriority: Record<string, number>;
57
- }
58
- ```
59
-
60
- ## Step 2: Create Services
61
-
62
- Create `src/services/database.ts`:
63
-
64
- ```typescript
65
- import type { Task, TaskStats } from "../types";
66
-
67
- // In-memory database (replace with real DB in production)
68
- const tasks: Map<string, Task> = new Map();
69
-
70
- export class Database {
71
- async addTask(title: string, priority: Task["priority"]): Promise<Task> {
72
- const id = Math.random().toString(36).substring(7);
73
- const task: Task = {
74
- id,
75
- title,
76
- priority,
77
- status: "pending",
78
- createdAt: new Date(),
79
- };
80
- tasks.set(id, task);
81
- return task;
82
- }
83
-
84
- async getTask(id: string): Promise<Task | undefined> {
85
- return tasks.get(id);
86
- }
87
-
88
- async listTasks(filter?: "pending" | "completed" | "all"): Promise<Task[]> {
89
- const all = Array.from(tasks.values());
90
- if (!filter || filter === "all") return all;
91
- return all.filter((t) => t.status === filter);
92
- }
93
-
94
- async completeTask(id: string): Promise<Task | undefined> {
95
- const task = tasks.get(id);
96
- if (task) {
97
- task.status = "completed";
98
- task.completedAt = new Date();
99
- tasks.set(id, task);
100
- }
101
- return task;
102
- }
103
-
104
- async getStats(): Promise<TaskStats> {
105
- const all = Array.from(tasks.values());
106
- return {
107
- total: all.length,
108
- pending: all.filter((t) => t.status === "pending").length,
109
- completed: all.filter((t) => t.status === "completed").length,
110
- byPriority: {
111
- high: all.filter((t) => t.priority === "high").length,
112
- medium: all.filter((t) => t.priority === "medium").length,
113
- low: all.filter((t) => t.priority === "low").length,
114
- },
115
- };
116
- }
117
- }
118
- ```
119
-
120
- Create `src/services/notifications.ts`:
121
-
122
- ```typescript
123
- import type { Task } from "../types";
124
- import type { Logger } from "@pablozaiden/terminatui";
125
-
126
- export class NotificationService {
127
- constructor(private logger: Logger) {}
128
-
129
- taskAdded(task: Task): void {
130
- this.logger.info(`📝 Task added: ${task.title} [${task.priority}]`);
131
- if (task.priority === "high") {
132
- this.logger.warn(`⚠️ High priority task created!`);
133
- }
134
- }
135
-
136
- taskCompleted(task: Task): void {
137
- this.logger.info(`✅ Task completed: ${task.title}`);
138
- const duration = task.completedAt!.getTime() - task.createdAt.getTime();
139
- const hours = Math.floor(duration / 3600000);
140
- if (hours > 24) {
141
- this.logger.debug(`Task took ${hours} hours to complete`);
142
- }
143
- }
144
- }
145
- ```
146
-
147
- ## Step 3: Create Commands
148
-
149
- Create `src/commands/add.ts`:
150
-
151
- ```typescript
152
- import {
153
- Command,
154
- ConfigValidationError,
155
- type AppContext,
156
- type OptionSchema,
157
- type OptionValues,
158
- type CommandResult,
159
- } from "@pablozaiden/terminatui";
160
- import { Database } from "../services/database";
161
- import { NotificationService } from "../services/notifications";
162
- import type { Task } from "../types";
163
-
164
- const options = {
165
- title: {
166
- type: "string",
167
- description: "Task title",
168
- required: true,
169
- label: "Task Title",
170
- order: 1,
171
- },
172
- priority: {
173
- type: "string",
174
- description: "Task priority",
175
- default: "medium",
176
- enum: ["low", "medium", "high"],
177
- label: "Priority",
178
- order: 2,
179
- },
180
- } satisfies OptionSchema;
181
-
182
- interface AddConfig {
183
- title: string;
184
- priority: Task["priority"];
185
- }
186
-
187
- export class AddCommand extends Command<typeof options, AddConfig> {
188
- readonly name = "add";
189
- readonly description = "Add a new task";
190
- readonly options = options;
191
- readonly displayName = "Add Task";
192
- readonly actionLabel = "Create Task";
193
- readonly group = "Tasks";
194
- readonly order = 1;
195
-
196
- private db = new Database();
197
-
198
- override buildConfig(
199
- _ctx: AppContext,
200
- opts: OptionValues<typeof options>
201
- ): AddConfig {
202
- const title = (opts["title"] as string)?.trim();
203
- if (!title) {
204
- throw new ConfigValidationError("Task title cannot be empty", "title");
205
- }
206
- if (title.length > 200) {
207
- throw new ConfigValidationError(
208
- "Task title must be 200 characters or less",
209
- "title"
210
- );
211
- }
212
-
213
- const priority = opts["priority"] as Task["priority"] ?? "medium";
214
-
215
- return { title, priority };
216
- }
217
-
218
- async execute(ctx: AppContext, config: AddConfig): Promise<CommandResult> {
219
- ctx.logger.debug(`Creating task: ${config.title}`);
220
-
221
- const task = await this.db.addTask(config.title, config.priority);
222
-
223
- const notifications = new NotificationService(ctx.logger);
224
- notifications.taskAdded(task);
225
-
226
- return {
227
- success: true,
228
- data: task,
229
- message: `Created task: ${task.title} (${task.id})`,
230
- };
231
- }
232
- }
233
- ```
234
-
235
- Create `src/commands/list.ts`:
236
-
237
- ```typescript
238
- import {
239
- Command,
240
- type AppContext,
241
- type OptionSchema,
242
- type OptionValues,
243
- type CommandResult,
244
- } from "@pablozaiden/terminatui";
245
- import { Database } from "../services/database";
246
- import type { Task } from "../types";
247
-
248
- const options = {
249
- filter: {
250
- type: "string",
251
- description: "Filter by status",
252
- default: "all",
253
- enum: ["all", "pending", "completed"],
254
- label: "Status Filter",
255
- },
256
- priority: {
257
- type: "string",
258
- description: "Filter by priority",
259
- enum: ["low", "medium", "high"],
260
- label: "Priority Filter",
261
- },
262
- } satisfies OptionSchema;
263
-
264
- interface ListConfig {
265
- filter: "all" | "pending" | "completed";
266
- priority?: Task["priority"];
267
- }
268
-
269
- export class ListCommand extends Command<typeof options, ListConfig> {
270
- readonly name = "list";
271
- readonly description = "List tasks";
272
- readonly options = options;
273
- readonly displayName = "List Tasks";
274
- readonly actionLabel = "Show Tasks";
275
- readonly group = "Tasks";
276
- readonly order = 2;
277
-
278
- // Execute immediately when selected in TUI
279
- readonly immediateExecution = true;
280
-
281
- private db = new Database();
282
-
283
- override buildConfig(
284
- _ctx: AppContext,
285
- opts: OptionValues<typeof options>
286
- ): ListConfig {
287
- return {
288
- filter: (opts["filter"] as ListConfig["filter"]) ?? "all",
289
- priority: opts["priority"] as Task["priority"] | undefined,
290
- };
291
- }
292
-
293
- async execute(ctx: AppContext, config: ListConfig): Promise<CommandResult> {
294
- ctx.logger.debug(`Listing tasks: filter=${config.filter}`);
295
-
296
- let tasks = await this.db.listTasks(config.filter);
297
-
298
- if (config.priority) {
299
- tasks = tasks.filter((t) => t.priority === config.priority);
300
- }
301
-
302
- return {
303
- success: true,
304
- data: tasks,
305
- message: `Found ${tasks.length} tasks`,
306
- };
307
- }
308
- }
309
- ```
310
-
311
- Create `src/commands/complete.ts`:
312
-
313
- ```typescript
314
- import {
315
- Command,
316
- ConfigValidationError,
317
- type AppContext,
318
- type OptionSchema,
319
- type OptionValues,
320
- type CommandResult,
321
- } from "@pablozaiden/terminatui";
322
- import { Database } from "../services/database";
323
- import { NotificationService } from "../services/notifications";
324
- import type { Task } from "../types";
325
-
326
- const options = {
327
- id: {
328
- type: "string",
329
- description: "Task ID to complete",
330
- required: true,
331
- label: "Task ID",
332
- },
333
- } satisfies OptionSchema;
334
-
335
- interface CompleteConfig {
336
- id: string;
337
- }
338
-
339
- export class CompleteCommand extends Command<typeof options, CompleteConfig> {
340
- readonly name = "complete";
341
- readonly description = "Mark a task as complete";
342
- readonly options = options;
343
- readonly displayName = "Complete Task";
344
- readonly actionLabel = "Mark Complete";
345
- readonly group = "Tasks";
346
- readonly order = 3;
347
-
348
- private db = new Database();
349
-
350
- override buildConfig(
351
- _ctx: AppContext,
352
- opts: OptionValues<typeof options>
353
- ): CompleteConfig {
354
- const id = opts["id"] as string;
355
- if (!id?.trim()) {
356
- throw new ConfigValidationError("Task ID is required", "id");
357
- }
358
- return { id: id.trim() };
359
- }
360
-
361
- async execute(ctx: AppContext, config: CompleteConfig): Promise<CommandResult> {
362
- ctx.logger.debug(`Completing task: ${config.id}`);
363
-
364
- const task = await this.db.completeTask(config.id);
365
-
366
- if (!task) {
367
- return {
368
- success: false,
369
- message: `Task not found: ${config.id}`,
370
- };
371
- }
372
-
373
- const notifications = new NotificationService(ctx.logger);
374
- notifications.taskCompleted(task);
375
-
376
- return {
377
- success: true,
378
- data: task,
379
- message: `Completed: ${task.title}`,
380
- };
381
- }
382
- }
383
- ```
384
-
385
- Create `src/commands/stats.ts`:
386
-
387
- ```typescript
388
- import {
389
- Command,
390
- type AppContext,
391
- type OptionSchema,
392
- type CommandResult,
393
- } from "@pablozaiden/terminatui";
394
- import { Database } from "../services/database";
395
- import type { TaskStats } from "../types";
396
-
397
- const options = {} satisfies OptionSchema;
398
-
399
- export class StatsCommand extends Command<typeof options> {
400
- readonly name = "stats";
401
- readonly description = "Show task statistics";
402
- readonly options = options;
403
- readonly displayName = "Statistics";
404
- readonly actionLabel = "Show Stats";
405
- readonly group = "Analytics";
406
- readonly order = 1;
407
- readonly immediateExecution = true;
408
-
409
- private db = new Database();
410
-
411
- async execute(ctx: AppContext): Promise<CommandResult> {
412
- ctx.logger.debug("Fetching statistics");
413
-
414
- const stats = await this.db.getStats();
415
-
416
- return {
417
- success: true,
418
- data: stats,
419
- message: `Total: ${stats.total}, Pending: ${stats.pending}, Completed: ${stats.completed}`,
420
- };
421
- }
422
- }
423
- ```
424
-
425
- ## Step 4: Create the Application
426
-
427
- Create `src/index.ts`:
428
-
429
- ```typescript
430
- import { TuiApplication } from "@pablozaiden/terminatui";
431
- import { AddCommand } from "./commands/add";
432
- import { ListCommand } from "./commands/list";
433
- import { CompleteCommand } from "./commands/complete";
434
- import { StatsCommand } from "./commands/stats";
435
-
436
- class TasksCLI extends TuiApplication {
437
- constructor() {
438
- super({
439
- name: "tasks",
440
- version: "1.0.0",
441
- description: "A simple task management CLI",
442
- commands: [
443
- new AddCommand(),
444
- new ListCommand(),
445
- new CompleteCommand(),
446
- new StatsCommand(),
447
- ],
448
- });
449
- }
450
-
451
- // Optional: Override onBeforeRun for setup
452
- protected override async onBeforeRun(): Promise<void> {
453
- this.logger.debug("Tasks CLI starting...");
454
- // Initialize database connections, load config, etc.
455
- }
456
-
457
- // Optional: Override onAfterRun for cleanup
458
- protected override async onAfterRun(): Promise<void> {
459
- this.logger.debug("Tasks CLI shutting down...");
460
- // Close database connections, save state, etc.
461
- }
462
- }
463
-
464
- await new TasksCLI().run();
465
- ```
466
-
467
- ## Step 5: Configure Package
468
-
469
- Update `package.json`:
470
-
471
- ```json
472
- {
473
- "name": "tasks-cli",
474
- "version": "1.0.0",
475
- "type": "module",
476
- "bin": {
477
- "tasks": "./src/index.ts"
478
- },
479
- "scripts": {
480
- "start": "bun src/index.ts",
481
- "tui": "bun src/index.ts --tui",
482
- "build": "bun build src/index.ts --outdir dist --target bun"
483
- },
484
- "dependencies": {
485
- "@pablozaiden/terminatui": "^1.0.0"
486
- }
487
- }
488
- ```
489
-
490
- ## Step 6: Run the Application
491
-
492
- ```bash
493
- # CLI Mode
494
- bun start add "Write documentation" --priority high
495
- bun start list --filter pending
496
- bun start complete abc123
497
- bun start stats
498
-
499
- # TUI Mode
500
- bun tui
501
-
502
- # With verbose logging
503
- bun start --verbose add "Debug task" --priority low
504
- ```
505
-
506
- ## TUI Feature Summary
507
-
508
- | Feature | Implementation |
509
- |---------|----------------|
510
- | Command Groups | `group = "Tasks"` or `"Analytics"` |
511
- | Command Order | `order = 1, 2, 3` |
512
- | Display Names | `displayName = "Add Task"` |
513
- | Action Labels | `actionLabel = "Create Task"` |
514
- | Immediate Execution | `immediateExecution = true` |
515
- | Clipboard Support | `getClipboardContent()` |
516
-
517
- ## What You Learned
518
-
519
- - **Project Structure**: Organize code into commands, services, types
520
- - **Shared Services**: Database and notification services
521
- - **Command Groups**: Organize commands in TUI sidebar
522
- - **Full TUI Integration**: Clipboard, immediate execution
523
- - **Lifecycle Hooks**: `onBeforeRun` and `onAfterRun`
524
- - **Production Patterns**: Error handling, validation, logging
525
-
526
- ## Complete Series Summary
527
-
528
- 1. **Hello World** - Basic command structure
529
- 2. **Adding Options** - Option types and defaults
530
- 3. **Multiple Commands** - Command organization
531
- 4. **Subcommands** - Nested command hierarchies
532
- 5. **Interactive TUI** - TuiApplication basics
533
- 6. **Config Validation** - buildConfig and validation
534
- 7. **Async Cancellation** - Cancellable operations
535
- 8. **Complete Application** - Full production app
536
-
537
- You now have all the tools to build powerful CLI applications with terminatui! 🎉
package/guides/README.md DELETED
@@ -1,74 +0,0 @@
1
- # Terminatui Framework Guides
2
-
3
- Step-by-step tutorials for building CLI applications with the terminatui framework.
4
-
5
- ## Guide Overview
6
-
7
- | # | Guide | Level | Topics |
8
- |---|-------|-------|--------|
9
- | 1 | [Hello World](01-hello-world.md) | Super Simple | Basic Command, Application |
10
- | 2 | [Adding Options](02-adding-options.md) | Super Simple | Option types, defaults, aliases |
11
- | 3 | [Multiple Commands](03-multiple-commands.md) | Basic | Multiple commands, project structure |
12
- | 4 | [Subcommands](04-subcommands.md) | Basic | Nested subcommands, hierarchies |
13
- | 5 | [Interactive TUI](05-interactive-tui.md) | Normal | TuiApplication, metadata, keyboard |
14
- | 6 | [Config Validation](06-config-validation.md) | Normal | buildConfig, ConfigValidationError |
15
- | 7 | [Async Cancellation](07-async-cancellation.md) | Complex | AbortSignal, cancellation, cleanup |
16
- | 8 | [Complete Application](08-complete-application.md) | Complex | Full app, services, best practices |
17
-
18
- ## Learning Path
19
-
20
- ### Beginners
21
- Start with guides 1-2 to understand the basics of commands and options.
22
-
23
- ### Intermediate
24
- Continue with guides 3-4 to learn about organizing larger applications.
25
-
26
- ### Advanced
27
- Work through guides 5-8 to master TUI features, validation, and production patterns.
28
-
29
- ## Quick Start
30
-
31
- ```bash
32
- # Create a new project
33
- mkdir my-cli && cd my-cli
34
- bun init -y
35
- bun add @pablozaiden/terminatui
36
-
37
- # Create your first command
38
- cat > src/index.ts << 'EOF'
39
- import { Command, Application, type AppContext, type OptionSchema } from "@pablozaiden/terminatui";
40
-
41
- const options = {
42
- name: { type: "string", description: "Your name" },
43
- } satisfies OptionSchema;
44
-
45
- class HelloCommand extends Command<typeof options> {
46
- readonly name = "hello";
47
- readonly description = "Say hello";
48
- readonly options = options;
49
-
50
- async execute(ctx: AppContext, config: Record<string, unknown>) {
51
- const name = config["name"] ?? "World";
52
- console.log(`Hello, ${name}!`);
53
- return { success: true };
54
- }
55
- }
56
-
57
- class MyCLI extends Application {
58
- constructor() {
59
- super({ name: "my-cli", version: "1.0.0", commands: [new HelloCommand()] });
60
- }
61
- }
62
-
63
- await new MyCLI().run();
64
- EOF
65
-
66
- # Run it
67
- bun src/index.ts hello --name "Developer"
68
- ```
69
-
70
- ## Prerequisites
71
-
72
- - [Bun](https://bun.sh) or Node.js 18+
73
- - Basic TypeScript knowledge
74
- - Terminal/command-line familiarity