@pablozaiden/terminatui 0.1.2 → 0.3.0-beta-1
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.
- package/AGENTS.md +43 -0
- package/CLAUDE.md +1 -0
- package/README.md +64 -43
- package/bun.lock +85 -0
- package/examples/tui-app/commands/config/app/get.ts +62 -0
- package/examples/tui-app/commands/config/app/index.ts +23 -0
- package/examples/tui-app/commands/config/app/set.ts +96 -0
- package/examples/tui-app/commands/config/index.ts +28 -0
- package/examples/tui-app/commands/config/user/get.ts +61 -0
- package/examples/tui-app/commands/config/user/index.ts +23 -0
- package/examples/tui-app/commands/config/user/set.ts +57 -0
- package/examples/tui-app/commands/greet.ts +14 -11
- package/examples/tui-app/commands/math.ts +6 -9
- package/examples/tui-app/commands/status.ts +24 -13
- package/examples/tui-app/index.ts +7 -3
- package/guides/01-hello-world.md +7 -2
- package/guides/02-adding-options.md +2 -2
- package/guides/03-multiple-commands.md +6 -8
- package/guides/04-subcommands.md +8 -8
- package/guides/05-interactive-tui.md +45 -30
- package/guides/06-config-validation.md +4 -12
- package/guides/07-async-cancellation.md +15 -69
- package/guides/08-complete-application.md +13 -179
- package/guides/README.md +7 -3
- package/package.json +4 -8
- package/src/__tests__/application.test.ts +87 -68
- package/src/__tests__/buildCliCommand.test.ts +99 -119
- package/src/__tests__/builtins.test.ts +27 -75
- package/src/__tests__/command.test.ts +100 -131
- package/src/__tests__/context.test.ts +1 -26
- package/src/__tests__/helpCore.test.ts +227 -0
- package/src/__tests__/parser.test.ts +98 -244
- package/src/__tests__/registry.test.ts +33 -160
- package/src/__tests__/schemaToFields.test.ts +75 -158
- package/src/builtins/help.ts +19 -4
- package/src/builtins/settings.ts +18 -32
- package/src/builtins/version.ts +4 -4
- package/src/cli/output/colors.ts +1 -1
- package/src/cli/parser.ts +26 -95
- package/src/core/application.ts +192 -110
- package/src/core/command.ts +26 -9
- package/src/core/context.ts +31 -20
- package/src/core/help.ts +24 -18
- package/src/core/knownCommands.ts +13 -0
- package/src/core/logger.ts +39 -42
- package/src/core/registry.ts +5 -12
- package/src/tui/TuiApplication.tsx +63 -120
- package/src/tui/TuiRoot.tsx +135 -0
- package/src/tui/adapters/factory.ts +19 -0
- package/src/tui/adapters/ink/InkRenderer.tsx +135 -0
- package/src/tui/adapters/ink/components/Button.tsx +12 -0
- package/src/tui/adapters/ink/components/Code.tsx +6 -0
- package/src/tui/adapters/ink/components/CodeHighlight.tsx +6 -0
- package/src/tui/adapters/ink/components/Container.tsx +5 -0
- package/src/tui/adapters/ink/components/Field.tsx +12 -0
- package/src/tui/adapters/ink/components/Label.tsx +24 -0
- package/src/tui/adapters/ink/components/MenuButton.tsx +12 -0
- package/src/tui/adapters/ink/components/MenuItem.tsx +17 -0
- package/src/tui/adapters/ink/components/Overlay.tsx +5 -0
- package/src/tui/adapters/ink/components/Panel.tsx +15 -0
- package/src/tui/adapters/ink/components/ScrollView.tsx +5 -0
- package/src/tui/adapters/ink/components/Select.tsx +44 -0
- package/src/tui/adapters/ink/components/Spacer.tsx +15 -0
- package/src/tui/adapters/ink/components/Spinner.tsx +5 -0
- package/src/tui/adapters/ink/components/TextInput.tsx +22 -0
- package/src/tui/adapters/ink/components/Value.tsx +7 -0
- package/src/tui/adapters/ink/keyboard.ts +97 -0
- package/src/tui/adapters/ink/utils.ts +16 -0
- package/src/tui/adapters/opentui/OpenTuiRenderer.tsx +115 -0
- package/src/tui/adapters/opentui/components/Button.tsx +13 -0
- package/src/tui/adapters/opentui/components/Code.tsx +12 -0
- package/src/tui/adapters/opentui/components/CodeHighlight.tsx +24 -0
- package/src/tui/adapters/opentui/components/Container.tsx +56 -0
- package/src/tui/adapters/opentui/components/Field.tsx +18 -0
- package/src/tui/adapters/opentui/components/Label.tsx +15 -0
- package/src/tui/adapters/opentui/components/MenuButton.tsx +14 -0
- package/src/tui/adapters/opentui/components/MenuItem.tsx +29 -0
- package/src/tui/adapters/opentui/components/Overlay.tsx +21 -0
- package/src/tui/adapters/opentui/components/Panel.tsx +78 -0
- package/src/tui/adapters/opentui/components/ScrollView.tsx +85 -0
- package/src/tui/adapters/opentui/components/Select.tsx +59 -0
- package/src/tui/adapters/opentui/components/Spacer.tsx +5 -0
- package/src/tui/adapters/opentui/components/Spinner.tsx +12 -0
- package/src/tui/adapters/opentui/components/TextInput.tsx +13 -0
- package/src/tui/adapters/opentui/components/Value.tsx +13 -0
- package/src/tui/{hooks → adapters/opentui/hooks}/useSpinner.ts +2 -11
- package/src/tui/adapters/opentui/keyboard.ts +61 -0
- package/src/tui/adapters/types.ts +70 -0
- package/src/tui/components/ActionButton.tsx +0 -36
- package/src/tui/components/CommandSelector.tsx +52 -92
- package/src/tui/components/ConfigForm.tsx +68 -42
- package/src/tui/components/FieldRow.tsx +0 -30
- package/src/tui/components/Header.tsx +14 -13
- package/src/tui/components/JsonHighlight.tsx +10 -17
- package/src/tui/components/ModalBase.tsx +38 -0
- package/src/tui/components/ResultsPanel.tsx +27 -36
- package/src/tui/components/StatusBar.tsx +24 -39
- package/src/tui/components/logColors.ts +12 -0
- package/src/tui/context/ClipboardContext.tsx +87 -0
- package/src/tui/context/ExecutorContext.tsx +139 -0
- package/src/tui/context/KeyboardContext.tsx +85 -71
- package/src/tui/context/LogsContext.tsx +35 -0
- package/src/tui/context/NavigationContext.tsx +194 -0
- package/src/tui/context/RendererContext.tsx +20 -0
- package/src/tui/context/TuiAppContext.tsx +58 -0
- package/src/tui/hooks/useActiveKeyHandler.ts +75 -0
- package/src/tui/hooks/useBackHandler.ts +34 -0
- package/src/tui/hooks/useClipboard.ts +40 -25
- package/src/tui/hooks/useClipboardProvider.ts +42 -0
- package/src/tui/hooks/useGlobalKeyHandler.ts +54 -0
- package/src/tui/modals/CliModal.tsx +82 -0
- package/src/tui/modals/EditorModal.tsx +207 -0
- package/src/tui/modals/LogsModal.tsx +98 -0
- package/src/tui/registry.ts +102 -0
- package/src/tui/screens/CommandSelectScreen.tsx +162 -0
- package/src/tui/screens/ConfigScreen.tsx +160 -0
- package/src/tui/screens/ErrorScreen.tsx +58 -0
- package/src/tui/screens/ResultsScreen.tsx +60 -0
- package/src/tui/screens/RunningScreen.tsx +72 -0
- package/src/tui/screens/ScreenBase.ts +6 -0
- package/src/tui/semantic/Button.tsx +7 -0
- package/src/tui/semantic/Code.tsx +7 -0
- package/src/tui/semantic/CodeHighlight.tsx +7 -0
- package/src/tui/semantic/Container.tsx +7 -0
- package/src/tui/semantic/Field.tsx +7 -0
- package/src/tui/semantic/Label.tsx +7 -0
- package/src/tui/semantic/MenuButton.tsx +7 -0
- package/src/tui/semantic/MenuItem.tsx +7 -0
- package/src/tui/semantic/Overlay.tsx +7 -0
- package/src/tui/semantic/Panel.tsx +7 -0
- package/src/tui/semantic/ScrollView.tsx +9 -0
- package/src/tui/semantic/Select.tsx +7 -0
- package/src/tui/semantic/Spacer.tsx +7 -0
- package/src/tui/semantic/Spinner.tsx +7 -0
- package/src/tui/semantic/TextInput.tsx +7 -0
- package/src/tui/semantic/Value.tsx +7 -0
- package/src/tui/semantic/types.ts +195 -0
- package/src/tui/theme.ts +25 -14
- package/src/tui/utils/buildCliCommand.ts +1 -0
- package/src/tui/utils/getEnumKeys.ts +3 -0
- package/src/tui/utils/parameterPersistence.ts +1 -0
- package/src/types/command.ts +0 -60
- package/examples/tui-app/commands/index.ts +0 -3
- package/src/__tests__/colors.test.ts +0 -127
- package/src/__tests__/commandClass.test.ts +0 -130
- package/src/__tests__/help.test.ts +0 -412
- package/src/__tests__/registryNew.test.ts +0 -160
- package/src/__tests__/table.test.ts +0 -146
- package/src/__tests__/tui.test.ts +0 -26
- package/src/builtins/index.ts +0 -4
- package/src/cli/help.ts +0 -174
- package/src/cli/index.ts +0 -3
- package/src/cli/output/index.ts +0 -2
- package/src/cli/output/table.ts +0 -141
- package/src/commands/help.ts +0 -50
- package/src/commands/index.ts +0 -1
- package/src/components/index.ts +0 -147
- package/src/core/index.ts +0 -15
- package/src/hooks/index.ts +0 -131
- package/src/index.ts +0 -137
- package/src/registry/commandRegistry.ts +0 -77
- package/src/registry/index.ts +0 -1
- package/src/tui/TuiApp.tsx +0 -582
- package/src/tui/app.ts +0 -29
- package/src/tui/components/CliModal.tsx +0 -81
- package/src/tui/components/EditorModal.tsx +0 -177
- package/src/tui/components/LogsPanel.tsx +0 -86
- package/src/tui/components/index.ts +0 -13
- package/src/tui/context/index.ts +0 -7
- package/src/tui/hooks/index.ts +0 -35
- package/src/tui/hooks/useKeyboardHandler.ts +0 -91
- package/src/tui/hooks/useLogStream.ts +0 -96
- package/src/tui/index.ts +0 -65
- package/src/tui/utils/index.ts +0 -13
- package/src/types/index.ts +0 -1
|
@@ -149,12 +149,9 @@ export class NotificationService {
|
|
|
149
149
|
Create `src/commands/add.ts`:
|
|
150
150
|
|
|
151
151
|
```typescript
|
|
152
|
-
import React from "react";
|
|
153
|
-
import { Text, Box } from "ink";
|
|
154
152
|
import {
|
|
155
153
|
Command,
|
|
156
154
|
ConfigValidationError,
|
|
157
|
-
type AppContext,
|
|
158
155
|
type OptionSchema,
|
|
159
156
|
type OptionValues,
|
|
160
157
|
type CommandResult,
|
|
@@ -192,15 +189,10 @@ export class AddCommand extends Command<typeof options, AddConfig> {
|
|
|
192
189
|
readonly options = options;
|
|
193
190
|
readonly displayName = "Add Task";
|
|
194
191
|
readonly actionLabel = "Create Task";
|
|
195
|
-
readonly group = "Tasks";
|
|
196
|
-
readonly order = 1;
|
|
197
192
|
|
|
198
193
|
private db = new Database();
|
|
199
194
|
|
|
200
|
-
override buildConfig(
|
|
201
|
-
_ctx: AppContext,
|
|
202
|
-
opts: OptionValues<typeof options>
|
|
203
|
-
): AddConfig {
|
|
195
|
+
override buildConfig(opts: OptionValues<typeof options>): AddConfig {
|
|
204
196
|
const title = (opts["title"] as string)?.trim();
|
|
205
197
|
if (!title) {
|
|
206
198
|
throw new ConfigValidationError("Task title cannot be empty", "title");
|
|
@@ -217,13 +209,11 @@ export class AddCommand extends Command<typeof options, AddConfig> {
|
|
|
217
209
|
return { title, priority };
|
|
218
210
|
}
|
|
219
211
|
|
|
220
|
-
async execute(
|
|
221
|
-
ctx.logger.debug(`Creating task: ${config.title}`);
|
|
222
|
-
|
|
212
|
+
async execute(config: AddConfig): Promise<CommandResult> {
|
|
223
213
|
const task = await this.db.addTask(config.title, config.priority);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
214
|
+
|
|
215
|
+
// (Example) optional: log to console or your own logger
|
|
216
|
+
console.log(`Created task: ${task.title}`);
|
|
227
217
|
|
|
228
218
|
return {
|
|
229
219
|
success: true,
|
|
@@ -231,52 +221,14 @@ export class AddCommand extends Command<typeof options, AddConfig> {
|
|
|
231
221
|
message: `Created task: ${task.title} (${task.id})`,
|
|
232
222
|
};
|
|
233
223
|
}
|
|
234
|
-
|
|
235
|
-
override renderResult(result: CommandResult): React.ReactNode {
|
|
236
|
-
if (!result.success) {
|
|
237
|
-
return <Text color="red">✗ {result.message}</Text>;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const task = result.data as Task;
|
|
241
|
-
const priorityColor = {
|
|
242
|
-
high: "red",
|
|
243
|
-
medium: "yellow",
|
|
244
|
-
low: "green",
|
|
245
|
-
}[task.priority] as "red" | "yellow" | "green";
|
|
246
|
-
|
|
247
|
-
return (
|
|
248
|
-
<Box flexDirection="column" gap={1}>
|
|
249
|
-
<Text color="green">✓ Task Created</Text>
|
|
250
|
-
<Box>
|
|
251
|
-
<Text dimColor>ID: </Text>
|
|
252
|
-
<Text>{task.id}</Text>
|
|
253
|
-
</Box>
|
|
254
|
-
<Box>
|
|
255
|
-
<Text dimColor>Title: </Text>
|
|
256
|
-
<Text>{task.title}</Text>
|
|
257
|
-
</Box>
|
|
258
|
-
<Box>
|
|
259
|
-
<Text dimColor>Priority: </Text>
|
|
260
|
-
<Text color={priorityColor}>{task.priority}</Text>
|
|
261
|
-
</Box>
|
|
262
|
-
</Box>
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
override getClipboardContent(result: CommandResult): string | undefined {
|
|
267
|
-
return result.data?.id;
|
|
268
|
-
}
|
|
269
224
|
}
|
|
270
225
|
```
|
|
271
226
|
|
|
272
227
|
Create `src/commands/list.ts`:
|
|
273
228
|
|
|
274
229
|
```typescript
|
|
275
|
-
import React from "react";
|
|
276
|
-
import { Text, Box } from "ink";
|
|
277
230
|
import {
|
|
278
231
|
Command,
|
|
279
|
-
type AppContext,
|
|
280
232
|
type OptionSchema,
|
|
281
233
|
type OptionValues,
|
|
282
234
|
type CommandResult,
|
|
@@ -311,27 +263,20 @@ export class ListCommand extends Command<typeof options, ListConfig> {
|
|
|
311
263
|
readonly options = options;
|
|
312
264
|
readonly displayName = "List Tasks";
|
|
313
265
|
readonly actionLabel = "Show Tasks";
|
|
314
|
-
readonly group = "Tasks";
|
|
315
|
-
readonly order = 2;
|
|
316
266
|
|
|
317
267
|
// Execute immediately when selected in TUI
|
|
318
268
|
readonly immediateExecution = true;
|
|
319
269
|
|
|
320
270
|
private db = new Database();
|
|
321
271
|
|
|
322
|
-
override buildConfig(
|
|
323
|
-
_ctx: AppContext,
|
|
324
|
-
opts: OptionValues<typeof options>
|
|
325
|
-
): ListConfig {
|
|
272
|
+
override buildConfig(opts: OptionValues<typeof options>): ListConfig {
|
|
326
273
|
return {
|
|
327
274
|
filter: (opts["filter"] as ListConfig["filter"]) ?? "all",
|
|
328
275
|
priority: opts["priority"] as Task["priority"] | undefined,
|
|
329
276
|
};
|
|
330
277
|
}
|
|
331
278
|
|
|
332
|
-
async execute(
|
|
333
|
-
ctx.logger.debug(`Listing tasks: filter=${config.filter}`);
|
|
334
|
-
|
|
279
|
+
async execute(config: ListConfig): Promise<CommandResult> {
|
|
335
280
|
let tasks = await this.db.listTasks(config.filter);
|
|
336
281
|
|
|
337
282
|
if (config.priority) {
|
|
@@ -344,49 +289,15 @@ export class ListCommand extends Command<typeof options, ListConfig> {
|
|
|
344
289
|
message: `Found ${tasks.length} tasks`,
|
|
345
290
|
};
|
|
346
291
|
}
|
|
347
|
-
|
|
348
|
-
override renderResult(result: CommandResult): React.ReactNode {
|
|
349
|
-
const tasks = (result.data as Task[]) ?? [];
|
|
350
|
-
|
|
351
|
-
if (tasks.length === 0) {
|
|
352
|
-
return <Text dimColor>No tasks found</Text>;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const priorityColor = (p: string) =>
|
|
356
|
-
({ high: "red", medium: "yellow", low: "green" })[p] as "red" | "yellow" | "green";
|
|
357
|
-
|
|
358
|
-
return (
|
|
359
|
-
<Box flexDirection="column" gap={1}>
|
|
360
|
-
<Text bold>Tasks ({tasks.length})</Text>
|
|
361
|
-
{tasks.map((task) => (
|
|
362
|
-
<Box key={task.id} gap={2}>
|
|
363
|
-
<Text dimColor>[{task.id}]</Text>
|
|
364
|
-
<Text color={task.status === "completed" ? "gray" : undefined}>
|
|
365
|
-
{task.status === "completed" ? "✓" : "○"} {task.title}
|
|
366
|
-
</Text>
|
|
367
|
-
<Text color={priorityColor(task.priority)}>{task.priority}</Text>
|
|
368
|
-
</Box>
|
|
369
|
-
))}
|
|
370
|
-
</Box>
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
override getClipboardContent(result: CommandResult): string | undefined {
|
|
375
|
-
const tasks = result.data as Task[];
|
|
376
|
-
return tasks?.map((t) => `${t.id}: ${t.title}`).join("\n");
|
|
377
|
-
}
|
|
378
292
|
}
|
|
379
293
|
```
|
|
380
294
|
|
|
381
295
|
Create `src/commands/complete.ts`:
|
|
382
296
|
|
|
383
297
|
```typescript
|
|
384
|
-
import React from "react";
|
|
385
|
-
import { Text, Box } from "ink";
|
|
386
298
|
import {
|
|
387
299
|
Command,
|
|
388
300
|
ConfigValidationError,
|
|
389
|
-
type AppContext,
|
|
390
301
|
type OptionSchema,
|
|
391
302
|
type OptionValues,
|
|
392
303
|
type CommandResult,
|
|
@@ -414,15 +325,10 @@ export class CompleteCommand extends Command<typeof options, CompleteConfig> {
|
|
|
414
325
|
readonly options = options;
|
|
415
326
|
readonly displayName = "Complete Task";
|
|
416
327
|
readonly actionLabel = "Mark Complete";
|
|
417
|
-
readonly group = "Tasks";
|
|
418
|
-
readonly order = 3;
|
|
419
328
|
|
|
420
329
|
private db = new Database();
|
|
421
330
|
|
|
422
|
-
override buildConfig(
|
|
423
|
-
_ctx: AppContext,
|
|
424
|
-
opts: OptionValues<typeof options>
|
|
425
|
-
): CompleteConfig {
|
|
331
|
+
override buildConfig(opts: OptionValues<typeof options>): CompleteConfig {
|
|
426
332
|
const id = opts["id"] as string;
|
|
427
333
|
if (!id?.trim()) {
|
|
428
334
|
throw new ConfigValidationError("Task ID is required", "id");
|
|
@@ -430,11 +336,9 @@ export class CompleteCommand extends Command<typeof options, CompleteConfig> {
|
|
|
430
336
|
return { id: id.trim() };
|
|
431
337
|
}
|
|
432
338
|
|
|
433
|
-
async execute(
|
|
434
|
-
ctx.logger.debug(`Completing task: ${config.id}`);
|
|
435
|
-
|
|
339
|
+
async execute(config: CompleteConfig): Promise<CommandResult> {
|
|
436
340
|
const task = await this.db.completeTask(config.id);
|
|
437
|
-
|
|
341
|
+
|
|
438
342
|
if (!task) {
|
|
439
343
|
return {
|
|
440
344
|
success: false,
|
|
@@ -442,8 +346,7 @@ export class CompleteCommand extends Command<typeof options, CompleteConfig> {
|
|
|
442
346
|
};
|
|
443
347
|
}
|
|
444
348
|
|
|
445
|
-
|
|
446
|
-
notifications.taskCompleted(task);
|
|
349
|
+
console.log(`Completed task: ${task.title}`);
|
|
447
350
|
|
|
448
351
|
return {
|
|
449
352
|
success: true,
|
|
@@ -451,34 +354,14 @@ export class CompleteCommand extends Command<typeof options, CompleteConfig> {
|
|
|
451
354
|
message: `Completed: ${task.title}`,
|
|
452
355
|
};
|
|
453
356
|
}
|
|
454
|
-
|
|
455
|
-
override renderResult(result: CommandResult): React.ReactNode {
|
|
456
|
-
if (!result.success) {
|
|
457
|
-
return <Text color="red">✗ {result.message}</Text>;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const task = result.data as Task;
|
|
461
|
-
return (
|
|
462
|
-
<Box flexDirection="column">
|
|
463
|
-
<Text color="green">✓ Task Completed</Text>
|
|
464
|
-
<Text>{task.title}</Text>
|
|
465
|
-
<Text dimColor>
|
|
466
|
-
Completed at: {task.completedAt?.toLocaleString()}
|
|
467
|
-
</Text>
|
|
468
|
-
</Box>
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
357
|
}
|
|
472
358
|
```
|
|
473
359
|
|
|
474
360
|
Create `src/commands/stats.ts`:
|
|
475
361
|
|
|
476
362
|
```typescript
|
|
477
|
-
import React from "react";
|
|
478
|
-
import { Text, Box } from "ink";
|
|
479
363
|
import {
|
|
480
364
|
Command,
|
|
481
|
-
type AppContext,
|
|
482
365
|
type OptionSchema,
|
|
483
366
|
type CommandResult,
|
|
484
367
|
} from "@pablozaiden/terminatui";
|
|
@@ -493,15 +376,11 @@ export class StatsCommand extends Command<typeof options> {
|
|
|
493
376
|
readonly options = options;
|
|
494
377
|
readonly displayName = "Statistics";
|
|
495
378
|
readonly actionLabel = "Show Stats";
|
|
496
|
-
readonly group = "Analytics";
|
|
497
|
-
readonly order = 1;
|
|
498
379
|
readonly immediateExecution = true;
|
|
499
380
|
|
|
500
381
|
private db = new Database();
|
|
501
382
|
|
|
502
|
-
async execute(
|
|
503
|
-
ctx.logger.debug("Fetching statistics");
|
|
504
|
-
|
|
383
|
+
async execute(): Promise<CommandResult> {
|
|
505
384
|
const stats = await this.db.getStats();
|
|
506
385
|
|
|
507
386
|
return {
|
|
@@ -510,50 +389,6 @@ export class StatsCommand extends Command<typeof options> {
|
|
|
510
389
|
message: `Total: ${stats.total}, Pending: ${stats.pending}, Completed: ${stats.completed}`,
|
|
511
390
|
};
|
|
512
391
|
}
|
|
513
|
-
|
|
514
|
-
override renderResult(result: CommandResult): React.ReactNode {
|
|
515
|
-
const stats = result.data as TaskStats;
|
|
516
|
-
|
|
517
|
-
const completionRate = stats.total > 0
|
|
518
|
-
? Math.round((stats.completed / stats.total) * 100)
|
|
519
|
-
: 0;
|
|
520
|
-
|
|
521
|
-
return (
|
|
522
|
-
<Box flexDirection="column" gap={1}>
|
|
523
|
-
<Text bold>📊 Task Statistics</Text>
|
|
524
|
-
|
|
525
|
-
<Box flexDirection="column">
|
|
526
|
-
<Box gap={2}>
|
|
527
|
-
<Text dimColor>Total:</Text>
|
|
528
|
-
<Text>{stats.total}</Text>
|
|
529
|
-
</Box>
|
|
530
|
-
<Box gap={2}>
|
|
531
|
-
<Text dimColor>Pending:</Text>
|
|
532
|
-
<Text color="yellow">{stats.pending}</Text>
|
|
533
|
-
</Box>
|
|
534
|
-
<Box gap={2}>
|
|
535
|
-
<Text dimColor>Completed:</Text>
|
|
536
|
-
<Text color="green">{stats.completed}</Text>
|
|
537
|
-
</Box>
|
|
538
|
-
<Box gap={2}>
|
|
539
|
-
<Text dimColor>Completion Rate:</Text>
|
|
540
|
-
<Text color={completionRate >= 50 ? "green" : "yellow"}>
|
|
541
|
-
{completionRate}%
|
|
542
|
-
</Text>
|
|
543
|
-
</Box>
|
|
544
|
-
</Box>
|
|
545
|
-
|
|
546
|
-
<Box flexDirection="column" marginTop={1}>
|
|
547
|
-
<Text bold>By Priority:</Text>
|
|
548
|
-
<Box gap={2}>
|
|
549
|
-
<Text color="red">High: {stats.byPriority.high}</Text>
|
|
550
|
-
<Text color="yellow">Medium: {stats.byPriority.medium}</Text>
|
|
551
|
-
<Text color="green">Low: {stats.byPriority.low}</Text>
|
|
552
|
-
</Box>
|
|
553
|
-
</Box>
|
|
554
|
-
</Box>
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
392
|
}
|
|
558
393
|
```
|
|
559
394
|
|
|
@@ -647,7 +482,6 @@ bun start --verbose add "Debug task" --priority low
|
|
|
647
482
|
| Display Names | `displayName = "Add Task"` |
|
|
648
483
|
| Action Labels | `actionLabel = "Create Task"` |
|
|
649
484
|
| Immediate Execution | `immediateExecution = true` |
|
|
650
|
-
| Custom Results | `renderResult()` |
|
|
651
485
|
| Clipboard Support | `getClipboardContent()` |
|
|
652
486
|
|
|
653
487
|
## What You Learned
|
|
@@ -655,7 +489,7 @@ bun start --verbose add "Debug task" --priority low
|
|
|
655
489
|
- **Project Structure**: Organize code into commands, services, types
|
|
656
490
|
- **Shared Services**: Database and notification services
|
|
657
491
|
- **Command Groups**: Organize commands in TUI sidebar
|
|
658
|
-
- **Full TUI Integration**:
|
|
492
|
+
- **Full TUI Integration**: Clipboard, immediate execution
|
|
659
493
|
- **Lifecycle Hooks**: `onBeforeRun` and `onAfterRun`
|
|
660
494
|
- **Production Patterns**: Error handling, validation, logging
|
|
661
495
|
|
package/guides/README.md
CHANGED
|
@@ -36,7 +36,7 @@ bun add @pablozaiden/terminatui
|
|
|
36
36
|
|
|
37
37
|
# Create your first command
|
|
38
38
|
cat > src/index.ts << 'EOF'
|
|
39
|
-
import { Command, Application, type
|
|
39
|
+
import { Command, Application, type OptionSchema } from "@pablozaiden/terminatui";
|
|
40
40
|
|
|
41
41
|
const options = {
|
|
42
42
|
name: { type: "string", description: "Your name" },
|
|
@@ -47,7 +47,7 @@ class HelloCommand extends Command<typeof options> {
|
|
|
47
47
|
readonly description = "Say hello";
|
|
48
48
|
readonly options = options;
|
|
49
49
|
|
|
50
|
-
async execute(
|
|
50
|
+
async execute(config: Record<string, unknown>) {
|
|
51
51
|
const name = config["name"] ?? "World";
|
|
52
52
|
console.log(`Hello, ${name}!`);
|
|
53
53
|
return { success: true };
|
|
@@ -60,7 +60,11 @@ class MyCLI extends Application {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// Recommended: let Terminatui read `Bun.argv.slice(2)`
|
|
63
64
|
await new MyCLI().run();
|
|
65
|
+
|
|
66
|
+
// For tests or programmatic invocation:
|
|
67
|
+
// await new MyCLI().runFromArgs(["hello", "--name", "Developer"]);
|
|
64
68
|
EOF
|
|
65
69
|
|
|
66
70
|
# Run it
|
|
@@ -69,6 +73,6 @@ bun src/index.ts hello --name "Developer"
|
|
|
69
73
|
|
|
70
74
|
## Prerequisites
|
|
71
75
|
|
|
72
|
-
- [Bun](https://bun.sh)
|
|
76
|
+
- [Bun](https://bun.sh)
|
|
73
77
|
- Basic TypeScript knowledge
|
|
74
78
|
- Terminal/command-line familiarity
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pablozaiden/terminatui",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.0-beta-1",
|
|
4
4
|
"description": "Terminal UI and Command Line Application Framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/PabloZaiden/terminatui"
|
|
@@ -8,13 +8,6 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "src/index.ts",
|
|
10
10
|
"types": "src/index.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": "./src/index.ts",
|
|
13
|
-
"./cli": "./src/cli/index.ts",
|
|
14
|
-
"./tui": "./src/tui/index.ts",
|
|
15
|
-
"./components": "./src/components/index.ts",
|
|
16
|
-
"./hooks": "./src/hooks/index.ts"
|
|
17
|
-
},
|
|
18
11
|
"scripts": {
|
|
19
12
|
"build": "bunx tsc --noEmit",
|
|
20
13
|
"test": "bun test",
|
|
@@ -22,6 +15,9 @@
|
|
|
22
15
|
},
|
|
23
16
|
"dependencies": {
|
|
24
17
|
"@opentui/react": "0.1.68",
|
|
18
|
+
"ink": "^6.6.0",
|
|
19
|
+
"ink-select-input": "^6.2.0",
|
|
20
|
+
"ink-text-input": "^6.0.0",
|
|
25
21
|
"tslog": "^4.9.3"
|
|
26
22
|
},
|
|
27
23
|
"devDependencies": {
|