project-roadmap-tracking 0.1.0 → 0.2.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.
- package/README.md +291 -24
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +39 -31
- package/dist/commands/complete.d.ts +2 -0
- package/dist/commands/complete.js +35 -12
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +63 -46
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +65 -62
- package/dist/commands/pass-test.d.ts +4 -1
- package/dist/commands/pass-test.js +36 -13
- package/dist/commands/show.d.ts +4 -1
- package/dist/commands/show.js +38 -59
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +54 -31
- package/dist/commands/validate.d.ts +4 -1
- package/dist/commands/validate.js +74 -32
- package/dist/errors/base.error.d.ts +21 -0
- package/dist/errors/base.error.js +35 -0
- package/dist/errors/circular-dependency.error.d.ts +8 -0
- package/dist/errors/circular-dependency.error.js +13 -0
- package/dist/errors/config-not-found.error.d.ts +7 -0
- package/dist/errors/config-not-found.error.js +12 -0
- package/dist/errors/index.d.ts +16 -0
- package/dist/errors/index.js +26 -0
- package/dist/errors/invalid-task.error.d.ts +7 -0
- package/dist/errors/invalid-task.error.js +12 -0
- package/dist/errors/roadmap-not-found.error.d.ts +7 -0
- package/dist/errors/roadmap-not-found.error.js +12 -0
- package/dist/errors/task-not-found.error.d.ts +7 -0
- package/dist/errors/task-not-found.error.js +12 -0
- package/dist/errors/validation.error.d.ts +16 -0
- package/dist/errors/validation.error.js +16 -0
- package/dist/repositories/config.repository.d.ts +76 -0
- package/dist/repositories/config.repository.js +282 -0
- package/dist/repositories/index.d.ts +2 -0
- package/dist/repositories/index.js +2 -0
- package/dist/repositories/roadmap.repository.d.ts +82 -0
- package/dist/repositories/roadmap.repository.js +201 -0
- package/dist/services/display.service.d.ts +182 -0
- package/dist/services/display.service.js +320 -0
- package/dist/services/error-handler.service.d.ts +114 -0
- package/dist/services/error-handler.service.js +169 -0
- package/dist/services/roadmap.service.d.ts +142 -0
- package/dist/services/roadmap.service.js +269 -0
- package/dist/services/task-dependency.service.d.ts +210 -0
- package/dist/services/task-dependency.service.js +371 -0
- package/dist/services/task-query.service.d.ts +123 -0
- package/dist/services/task-query.service.js +259 -0
- package/dist/services/task.service.d.ts +132 -0
- package/dist/services/task.service.js +173 -0
- package/dist/util/read-config.js +12 -2
- package/dist/util/read-roadmap.js +12 -2
- package/dist/util/types.d.ts +5 -0
- package/dist/util/update-task.js +2 -1
- package/dist/util/validate-task.js +6 -5
- package/oclif.manifest.json +114 -5
- package/package.json +19 -3
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { PRIORITY, STATUS, Task } from '../util/types.js';
|
|
2
|
+
import { RoadmapStats } from './roadmap.service.js';
|
|
3
|
+
import { DependencyValidationError } from './task-dependency.service.js';
|
|
4
|
+
/**
|
|
5
|
+
* DisplayService provides centralized formatting for all display output.
|
|
6
|
+
* This service handles task display, error formatting, and statistics presentation.
|
|
7
|
+
* All methods are pure functions that return strings or arrays of strings.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DisplayService {
|
|
10
|
+
/**
|
|
11
|
+
* Formats a priority as text (e.g., "High").
|
|
12
|
+
* Capitalizes the first letter.
|
|
13
|
+
*
|
|
14
|
+
* @param priority - The priority to format
|
|
15
|
+
* @returns The priority as formatted text
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* displayService.formatPriorityLabel(PRIORITY.High) // Returns 'High'
|
|
20
|
+
* displayService.formatPriorityLabel(PRIORITY.Medium) // Returns 'Medium'
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
formatPriorityLabel(priority: PRIORITY): string;
|
|
24
|
+
/**
|
|
25
|
+
* Formats a priority as a symbol (H, M, L).
|
|
26
|
+
*
|
|
27
|
+
* @param priority - The priority to format
|
|
28
|
+
* @returns A single character symbol representing the priority
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* displayService.formatPrioritySymbol(PRIORITY.High) // Returns 'H'
|
|
33
|
+
* displayService.formatPrioritySymbol(PRIORITY.Medium) // Returns 'M'
|
|
34
|
+
* displayService.formatPrioritySymbol(PRIORITY.Low) // Returns 'L'
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
formatPrioritySymbol(priority: PRIORITY): string;
|
|
38
|
+
/**
|
|
39
|
+
* Formats roadmap statistics for display.
|
|
40
|
+
* Returns an array of lines to be output.
|
|
41
|
+
*
|
|
42
|
+
* @param stats - The roadmap statistics to format
|
|
43
|
+
* @returns Array of formatted statistics lines
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const stats = roadmapService.getStats(roadmap);
|
|
48
|
+
* const lines = displayService.formatRoadmapStats(stats);
|
|
49
|
+
* for (const line of lines) {
|
|
50
|
+
* console.log(line);
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
formatRoadmapStats(stats: RoadmapStats): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Formats a status as a symbol (✓, ~, ○).
|
|
57
|
+
*
|
|
58
|
+
* @param status - The status to format
|
|
59
|
+
* @returns A single character symbol representing the status
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* displayService.formatStatusSymbol(STATUS.Completed) // Returns '✓'
|
|
64
|
+
* displayService.formatStatusSymbol(STATUS.InProgress) // Returns '~'
|
|
65
|
+
* displayService.formatStatusSymbol(STATUS.NotStarted) // Returns '○'
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
formatStatusSymbol(status: STATUS): string;
|
|
69
|
+
/**
|
|
70
|
+
* Formats a status as text (e.g., "In Progress").
|
|
71
|
+
* Converts kebab-case to Title Case.
|
|
72
|
+
*
|
|
73
|
+
* @param status - The status to format
|
|
74
|
+
* @returns The status as formatted text
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* displayService.formatStatusText(STATUS.InProgress) // Returns 'In Progress'
|
|
79
|
+
* displayService.formatStatusText(STATUS.NotStarted) // Returns 'Not Started'
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
formatStatusText(status: STATUS): string;
|
|
83
|
+
/**
|
|
84
|
+
* Formats complete task details for show command.
|
|
85
|
+
* Returns an array of lines to be output.
|
|
86
|
+
*
|
|
87
|
+
* @param task - The task to format
|
|
88
|
+
* @returns Array of formatted lines
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* const lines = displayService.formatTaskDetails(task);
|
|
93
|
+
* for (const line of lines) {
|
|
94
|
+
* console.log(line);
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
formatTaskDetails(task: Task): string[];
|
|
99
|
+
/**
|
|
100
|
+
* Formats a list of tasks for display.
|
|
101
|
+
* Returns an array of lines including a header and all task summaries.
|
|
102
|
+
*
|
|
103
|
+
* @param tasks - The tasks to format
|
|
104
|
+
* @param options - Optional formatting options (reserved for future use)
|
|
105
|
+
* @param options.format - Output format: 'default' (current), 'compact', or 'json' (reserved)
|
|
106
|
+
* @returns Array of formatted lines ready for output
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const lines = displayService.formatTaskList(tasks);
|
|
111
|
+
* for (const line of lines) {
|
|
112
|
+
* console.log(line);
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
formatTaskList(tasks: Task[], options?: {
|
|
117
|
+
format?: 'compact' | 'default' | 'json';
|
|
118
|
+
}): string[];
|
|
119
|
+
/**
|
|
120
|
+
* Formats a task summary for list display.
|
|
121
|
+
* Returns an array of lines to be output.
|
|
122
|
+
*
|
|
123
|
+
* Format:
|
|
124
|
+
* ✓ [H] [F-001] Task title
|
|
125
|
+
* Type: feature | Tests: ✓ | Deps: 2
|
|
126
|
+
* Depends on: F-002, F-003
|
|
127
|
+
* (blank line)
|
|
128
|
+
*
|
|
129
|
+
* @param task - The task to format
|
|
130
|
+
* @returns Array of formatted lines
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const lines = displayService.formatTaskSummary(task);
|
|
135
|
+
* for (const line of lines) {
|
|
136
|
+
* console.log(line);
|
|
137
|
+
* }
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
formatTaskSummary(task: Task): string[];
|
|
141
|
+
/**
|
|
142
|
+
* Formats test status as a symbol (✓ or ✗).
|
|
143
|
+
*
|
|
144
|
+
* @param passing - Whether the tests are passing
|
|
145
|
+
* @returns A checkmark if passing, X if not
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* displayService.formatTestStatus(true) // Returns '✓'
|
|
150
|
+
* displayService.formatTestStatus(false) // Returns '✗'
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
formatTestStatus(passing: boolean): string;
|
|
154
|
+
/**
|
|
155
|
+
* Formats validation errors for display.
|
|
156
|
+
* Returns an array of lines to be output.
|
|
157
|
+
*
|
|
158
|
+
* @param errors - The dependency validation errors to format
|
|
159
|
+
* @returns Array of formatted error lines
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const errorLines = displayService.formatValidationErrors(errors);
|
|
164
|
+
* for (const line of errorLines) {
|
|
165
|
+
* console.log(line);
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
formatValidationErrors(errors: DependencyValidationError[]): string[];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Default export instance of DisplayService for convenience.
|
|
173
|
+
* Can be imported and used directly without instantiation.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* import displayService from './services/display.service.js';
|
|
178
|
+
* const lines = displayService.formatTaskSummary(task);
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
declare const _default: DisplayService;
|
|
182
|
+
export default _default;
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { PRIORITY, STATUS } from '../util/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* DisplayService provides centralized formatting for all display output.
|
|
4
|
+
* This service handles task display, error formatting, and statistics presentation.
|
|
5
|
+
* All methods are pure functions that return strings or arrays of strings.
|
|
6
|
+
*/
|
|
7
|
+
export class DisplayService {
|
|
8
|
+
/**
|
|
9
|
+
* Formats a priority as text (e.g., "High").
|
|
10
|
+
* Capitalizes the first letter.
|
|
11
|
+
*
|
|
12
|
+
* @param priority - The priority to format
|
|
13
|
+
* @returns The priority as formatted text
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* displayService.formatPriorityLabel(PRIORITY.High) // Returns 'High'
|
|
18
|
+
* displayService.formatPriorityLabel(PRIORITY.Medium) // Returns 'Medium'
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
formatPriorityLabel(priority) {
|
|
22
|
+
switch (priority) {
|
|
23
|
+
case PRIORITY.High: {
|
|
24
|
+
return 'High';
|
|
25
|
+
}
|
|
26
|
+
case PRIORITY.Low: {
|
|
27
|
+
return 'Low';
|
|
28
|
+
}
|
|
29
|
+
case PRIORITY.Medium: {
|
|
30
|
+
return 'Medium';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Formats a priority as a symbol (H, M, L).
|
|
36
|
+
*
|
|
37
|
+
* @param priority - The priority to format
|
|
38
|
+
* @returns A single character symbol representing the priority
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* displayService.formatPrioritySymbol(PRIORITY.High) // Returns 'H'
|
|
43
|
+
* displayService.formatPrioritySymbol(PRIORITY.Medium) // Returns 'M'
|
|
44
|
+
* displayService.formatPrioritySymbol(PRIORITY.Low) // Returns 'L'
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
formatPrioritySymbol(priority) {
|
|
48
|
+
switch (priority) {
|
|
49
|
+
case PRIORITY.High: {
|
|
50
|
+
return 'H';
|
|
51
|
+
}
|
|
52
|
+
case PRIORITY.Low: {
|
|
53
|
+
return 'L';
|
|
54
|
+
}
|
|
55
|
+
case PRIORITY.Medium: {
|
|
56
|
+
return 'M';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Formats roadmap statistics for display.
|
|
62
|
+
* Returns an array of lines to be output.
|
|
63
|
+
*
|
|
64
|
+
* @param stats - The roadmap statistics to format
|
|
65
|
+
* @returns Array of formatted statistics lines
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const stats = roadmapService.getStats(roadmap);
|
|
70
|
+
* const lines = displayService.formatRoadmapStats(stats);
|
|
71
|
+
* for (const line of lines) {
|
|
72
|
+
* console.log(line);
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
formatRoadmapStats(stats) {
|
|
77
|
+
const lines = [];
|
|
78
|
+
lines.push('Roadmap Statistics:', '', `Total Tasks: ${stats.totalTasks}`, '', 'By Status:', ` Completed: ${stats.byStatus[STATUS.Completed]}`, ` In Progress: ${stats.byStatus[STATUS.InProgress]}`, ` Not Started: ${stats.byStatus[STATUS.NotStarted]}`, '', 'By Type:', ` Features: ${stats.byType.feature}`, ` Bugs: ${stats.byType.bug}`, ` Improvements: ${stats.byType.improvement}`, ` Planning: ${stats.byType.planning}`, ` Research: ${stats.byType.research}`, '', 'By Priority:', ` High: ${stats.byPriority[PRIORITY.High]}`, ` Medium: ${stats.byPriority[PRIORITY.Medium]}`, ` Low: ${stats.byPriority[PRIORITY.Low]}`);
|
|
79
|
+
return lines;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Formats a status as a symbol (✓, ~, ○).
|
|
83
|
+
*
|
|
84
|
+
* @param status - The status to format
|
|
85
|
+
* @returns A single character symbol representing the status
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* displayService.formatStatusSymbol(STATUS.Completed) // Returns '✓'
|
|
90
|
+
* displayService.formatStatusSymbol(STATUS.InProgress) // Returns '~'
|
|
91
|
+
* displayService.formatStatusSymbol(STATUS.NotStarted) // Returns '○'
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
formatStatusSymbol(status) {
|
|
95
|
+
switch (status) {
|
|
96
|
+
case STATUS.Completed: {
|
|
97
|
+
return '✓';
|
|
98
|
+
}
|
|
99
|
+
case STATUS.InProgress: {
|
|
100
|
+
return '~';
|
|
101
|
+
}
|
|
102
|
+
case STATUS.NotStarted: {
|
|
103
|
+
return '○';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Formats a status as text (e.g., "In Progress").
|
|
109
|
+
* Converts kebab-case to Title Case.
|
|
110
|
+
*
|
|
111
|
+
* @param status - The status to format
|
|
112
|
+
* @returns The status as formatted text
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* displayService.formatStatusText(STATUS.InProgress) // Returns 'In Progress'
|
|
117
|
+
* displayService.formatStatusText(STATUS.NotStarted) // Returns 'Not Started'
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
formatStatusText(status) {
|
|
121
|
+
return status
|
|
122
|
+
.replaceAll('-', ' ')
|
|
123
|
+
.split(' ')
|
|
124
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
125
|
+
.join(' ');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Formats complete task details for show command.
|
|
129
|
+
* Returns an array of lines to be output.
|
|
130
|
+
*
|
|
131
|
+
* @param task - The task to format
|
|
132
|
+
* @returns Array of formatted lines
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* const lines = displayService.formatTaskDetails(task);
|
|
137
|
+
* for (const line of lines) {
|
|
138
|
+
* console.log(line);
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
formatTaskDetails(task) {
|
|
143
|
+
const lines = [];
|
|
144
|
+
const statusSymbol = this.formatStatusSymbol(task.status);
|
|
145
|
+
const statusText = this.formatStatusText(task.status);
|
|
146
|
+
const priorityLabel = this.formatPriorityLabel(task.priority);
|
|
147
|
+
const testSymbol = this.formatTestStatus(task['passes-tests']);
|
|
148
|
+
// Header with blank line before
|
|
149
|
+
lines.push('', `Task: ${task.id}`, '', `Title: ${task.title}`, `Type: ${task.type}`, `Priority: ${priorityLabel}`, `Status: ${statusSymbol} ${statusText} | ${testSymbol} Tests Passing`, `\nDetails:\n${task.details}`);
|
|
150
|
+
// Dependencies
|
|
151
|
+
if (task['depends-on'].length > 0) {
|
|
152
|
+
lines.push(`\nDepends On: ${task['depends-on'].join(', ')}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
lines.push(`\nDepends On: None`);
|
|
156
|
+
}
|
|
157
|
+
// Blocks (optional - only if present and has items)
|
|
158
|
+
if (task.blocks && task.blocks.length > 0) {
|
|
159
|
+
lines.push(`Blocks: ${task.blocks.join(', ')}`);
|
|
160
|
+
}
|
|
161
|
+
// Timestamps
|
|
162
|
+
lines.push(`\nCreated: ${task.createdAt}`, `Updated: ${task.updatedAt}`);
|
|
163
|
+
// Optional fields - only display if present
|
|
164
|
+
if (task.tags && task.tags.length > 0) {
|
|
165
|
+
lines.push(`\nTags: ${task.tags.join(', ')}`);
|
|
166
|
+
}
|
|
167
|
+
if (task.effort !== undefined) {
|
|
168
|
+
lines.push(`Effort: ${task.effort}`);
|
|
169
|
+
}
|
|
170
|
+
if (task['github-refs'] && task['github-refs'].length > 0) {
|
|
171
|
+
lines.push(`GitHub Refs: ${task['github-refs'].join(', ')}`);
|
|
172
|
+
}
|
|
173
|
+
if (task.notes) {
|
|
174
|
+
lines.push(`\nNotes:\n${task.notes}`);
|
|
175
|
+
}
|
|
176
|
+
// Blank line at end
|
|
177
|
+
lines.push('');
|
|
178
|
+
return lines;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Formats a list of tasks for display.
|
|
182
|
+
* Returns an array of lines including a header and all task summaries.
|
|
183
|
+
*
|
|
184
|
+
* @param tasks - The tasks to format
|
|
185
|
+
* @param options - Optional formatting options (reserved for future use)
|
|
186
|
+
* @param options.format - Output format: 'default' (current), 'compact', or 'json' (reserved)
|
|
187
|
+
* @returns Array of formatted lines ready for output
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* const lines = displayService.formatTaskList(tasks);
|
|
192
|
+
* for (const line of lines) {
|
|
193
|
+
* console.log(line);
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
formatTaskList(tasks, options) {
|
|
198
|
+
const lines = [];
|
|
199
|
+
const format = options?.format ?? 'default';
|
|
200
|
+
// For now, only default format is implemented
|
|
201
|
+
// Future: support compact and json formats
|
|
202
|
+
if (format === 'default') {
|
|
203
|
+
// Add header
|
|
204
|
+
lines.push('', `Tasks (${tasks.length} total):`, '');
|
|
205
|
+
// Add each task summary
|
|
206
|
+
for (const task of tasks) {
|
|
207
|
+
const taskLines = this.formatTaskSummary(task);
|
|
208
|
+
for (const line of taskLines) {
|
|
209
|
+
lines.push(line);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return lines;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Formats a task summary for list display.
|
|
217
|
+
* Returns an array of lines to be output.
|
|
218
|
+
*
|
|
219
|
+
* Format:
|
|
220
|
+
* ✓ [H] [F-001] Task title
|
|
221
|
+
* Type: feature | Tests: ✓ | Deps: 2
|
|
222
|
+
* Depends on: F-002, F-003
|
|
223
|
+
* (blank line)
|
|
224
|
+
*
|
|
225
|
+
* @param task - The task to format
|
|
226
|
+
* @returns Array of formatted lines
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const lines = displayService.formatTaskSummary(task);
|
|
231
|
+
* for (const line of lines) {
|
|
232
|
+
* console.log(line);
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
formatTaskSummary(task) {
|
|
237
|
+
const lines = [];
|
|
238
|
+
const status = this.formatStatusSymbol(task.status);
|
|
239
|
+
const priority = this.formatPrioritySymbol(task.priority);
|
|
240
|
+
const tests = this.formatTestStatus(task['passes-tests']);
|
|
241
|
+
// First line: status [priority] [id] title
|
|
242
|
+
lines.push(`${status} [${priority}] [${task.id}] ${task.title}`, ` Type: ${task.type} | Tests: ${tests} | Deps: ${task['depends-on'].length}`);
|
|
243
|
+
// Third line (conditional): Depends on list
|
|
244
|
+
if (task['depends-on'].length > 0) {
|
|
245
|
+
lines.push(` Depends on: ${task['depends-on'].join(', ')}`);
|
|
246
|
+
}
|
|
247
|
+
// Blank line at end
|
|
248
|
+
lines.push('');
|
|
249
|
+
return lines;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Formats test status as a symbol (✓ or ✗).
|
|
253
|
+
*
|
|
254
|
+
* @param passing - Whether the tests are passing
|
|
255
|
+
* @returns A checkmark if passing, X if not
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```typescript
|
|
259
|
+
* displayService.formatTestStatus(true) // Returns '✓'
|
|
260
|
+
* displayService.formatTestStatus(false) // Returns '✗'
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
formatTestStatus(passing) {
|
|
264
|
+
return passing ? '✓' : '✗';
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Formats validation errors for display.
|
|
268
|
+
* Returns an array of lines to be output.
|
|
269
|
+
*
|
|
270
|
+
* @param errors - The dependency validation errors to format
|
|
271
|
+
* @returns Array of formatted error lines
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* const errorLines = displayService.formatValidationErrors(errors);
|
|
276
|
+
* for (const line of errorLines) {
|
|
277
|
+
* console.log(line);
|
|
278
|
+
* }
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
formatValidationErrors(errors) {
|
|
282
|
+
const lines = [];
|
|
283
|
+
const errorCount = errors.length;
|
|
284
|
+
const errorWord = errorCount === 1 ? 'error' : 'errors';
|
|
285
|
+
lines.push(`\nFound ${errorCount} dependency ${errorWord}:\n`);
|
|
286
|
+
for (const error of errors) {
|
|
287
|
+
switch (error.type) {
|
|
288
|
+
case 'circular': {
|
|
289
|
+
// Display circular dependency with cycle path
|
|
290
|
+
lines.push(`❌ CIRCULAR DEPENDENCY DETECTED`, ` ${error.message}`);
|
|
291
|
+
if (error.relatedTaskIds && error.relatedTaskIds.length > 0) {
|
|
292
|
+
lines.push(` Cycle path: ${error.relatedTaskIds.join(' -> ')}`);
|
|
293
|
+
}
|
|
294
|
+
lines.push('');
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
case 'invalid-reference': {
|
|
298
|
+
lines.push(`⚠️ ${error.message}`);
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case 'missing-task': {
|
|
302
|
+
lines.push(`❌ ${error.message}`);
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return lines;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Default export instance of DisplayService for convenience.
|
|
312
|
+
* Can be imported and used directly without instantiation.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```typescript
|
|
316
|
+
* import displayService from './services/display.service.js';
|
|
317
|
+
* const lines = displayService.formatTaskSummary(task);
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export default new DisplayService();
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { PrtErrorCode } from '../errors/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Exit codes used by the CLI application.
|
|
4
|
+
* These follow common UNIX conventions:
|
|
5
|
+
* - 0: Success
|
|
6
|
+
* - 1: General error
|
|
7
|
+
* - 2: Validation error
|
|
8
|
+
* - 3: Not found error
|
|
9
|
+
* - 4: Dependency error
|
|
10
|
+
*/
|
|
11
|
+
export declare const ExitCodes: {
|
|
12
|
+
readonly DEPENDENCY_ERROR: 4;
|
|
13
|
+
readonly GENERAL_ERROR: 1;
|
|
14
|
+
readonly NOT_FOUND: 3;
|
|
15
|
+
readonly SUCCESS: 0;
|
|
16
|
+
readonly VALIDATION_ERROR: 2;
|
|
17
|
+
};
|
|
18
|
+
export type ExitCode = (typeof ExitCodes)[keyof typeof ExitCodes];
|
|
19
|
+
/**
|
|
20
|
+
* ErrorHandlerService provides centralized error handling for CLI commands.
|
|
21
|
+
* This service handles error formatting, exit code mapping, and verbose output.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ErrorHandlerService {
|
|
24
|
+
/**
|
|
25
|
+
* Formats an error message for CLI display.
|
|
26
|
+
* When verbose=true, includes stack traces and context information.
|
|
27
|
+
*
|
|
28
|
+
* @param error - The error to format
|
|
29
|
+
* @param verbose - Whether to include verbose information (stack traces, context)
|
|
30
|
+
* @returns Formatted error message string
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // Basic error message
|
|
35
|
+
* const message = errorHandlerService.formatErrorMessage(error, false)
|
|
36
|
+
* console.error(message)
|
|
37
|
+
*
|
|
38
|
+
* // Verbose error message with stack trace
|
|
39
|
+
* const verboseMessage = errorHandlerService.formatErrorMessage(error, true)
|
|
40
|
+
* console.error(verboseMessage)
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
formatErrorMessage(error: unknown, verbose?: boolean): string;
|
|
44
|
+
/**
|
|
45
|
+
* Maps a PrtErrorCode to the appropriate CLI exit code.
|
|
46
|
+
*
|
|
47
|
+
* @param code - The PrtErrorCode to map
|
|
48
|
+
* @returns The corresponding exit code
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const exitCode = errorHandlerService.getExitCodeForErrorCode(PrtErrorCode.PRT_FILE_CONFIG_NOT_FOUND)
|
|
53
|
+
* // Returns ExitCodes.NOT_FOUND (3)
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
getExitCodeForErrorCode(code: PrtErrorCode): ExitCode;
|
|
57
|
+
/**
|
|
58
|
+
* Handles an error and returns the appropriate exit code.
|
|
59
|
+
* This is the main entry point for command error handling.
|
|
60
|
+
*
|
|
61
|
+
* @param error - The error to handle
|
|
62
|
+
* @returns The exit code to use when exiting the process
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* try {
|
|
67
|
+
* // Command logic
|
|
68
|
+
* } catch (error) {
|
|
69
|
+
* const exitCode = errorHandlerService.handleError(error)
|
|
70
|
+
* this.error(errorHandlerService.formatErrorMessage(error), {exit: exitCode})
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
handleError(error: unknown): ExitCode;
|
|
75
|
+
/**
|
|
76
|
+
* Determines if an error is recoverable.
|
|
77
|
+
* Recoverable errors allow the command to continue or retry,
|
|
78
|
+
* while non-recoverable errors should terminate the command.
|
|
79
|
+
*
|
|
80
|
+
* Currently, most PRT errors are non-recoverable as they indicate
|
|
81
|
+
* fundamental issues with the roadmap data or configuration.
|
|
82
|
+
*
|
|
83
|
+
* @param error - The error to check
|
|
84
|
+
* @returns True if the error is recoverable, false otherwise
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* if (errorHandlerService.isRecoverableError(error)) {
|
|
89
|
+
* console.log('Attempting retry...')
|
|
90
|
+
* } else {
|
|
91
|
+
* process.exit(1)
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
isRecoverableError(error: unknown): boolean;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Default export instance of ErrorHandlerService for convenience.
|
|
99
|
+
* Can be imported and used directly without instantiation.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* import errorHandlerService from './services/error-handler.service.js'
|
|
104
|
+
*
|
|
105
|
+
* try {
|
|
106
|
+
* // Command logic
|
|
107
|
+
* } catch (error) {
|
|
108
|
+
* const exitCode = errorHandlerService.handleError(error)
|
|
109
|
+
* this.error(errorHandlerService.formatErrorMessage(error, flags.verbose), {exit: exitCode})
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
declare const _default: ErrorHandlerService;
|
|
114
|
+
export default _default;
|