project-roadmap-tracking 0.2.0 → 0.2.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/README.md CHANGED
@@ -15,7 +15,7 @@ A modern, production-ready CLI tool for managing project tasks and roadmaps with
15
15
  - 🔍 **Powerful Filtering**: Filter and sort tasks by multiple criteria
16
16
  - 📊 **Validation**: Comprehensive roadmap validation with detailed error reporting
17
17
  - ⚡ **Performance**: LRU caching and file watching for optimal performance
18
- - 🏗️ **Modern Architecture**: Service layer, repository pattern, and 98.78% test coverage
18
+ - 🏗️ **Modern Architecture**: Service layer, repository pattern, and 96.81% test coverage
19
19
  - 📦 **Configuration**: Multi-level config inheritance (project → user → global)
20
20
  - 🔄 **Backward Compatible**: Legacy mode via `--no-repo` flag
21
21
 
@@ -166,7 +166,7 @@ $ npm install -g project-roadmap-tracking
166
166
  $ prt COMMAND
167
167
  running command...
168
168
  $ prt (--version)
169
- project-roadmap-tracking/0.2.0 darwin-arm64 node-v24.12.0
169
+ project-roadmap-tracking/0.2.1 darwin-arm64 node-v25.2.1
170
170
  $ prt --help [COMMAND]
171
171
  USAGE
172
172
  $ prt COMMAND
@@ -228,7 +228,7 @@ EXAMPLES
228
228
  $ prt add
229
229
  ```
230
230
 
231
- _See code: [src/commands/add.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/add.ts)_
231
+ _See code: [src/commands/add.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/add.ts)_
232
232
 
233
233
  ## `prt complete TASKID`
234
234
 
@@ -253,7 +253,7 @@ EXAMPLES
253
253
  $ prt complete F-001 --tests
254
254
  ```
255
255
 
256
- _See code: [src/commands/complete.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/complete.ts)_
256
+ _See code: [src/commands/complete.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/complete.ts)_
257
257
 
258
258
  ## `prt help [COMMAND]`
259
259
 
@@ -300,7 +300,7 @@ EXAMPLES
300
300
  $ prt init [path/to/directory]
301
301
  ```
302
302
 
303
- _See code: [src/commands/init.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/init.ts)_
303
+ _See code: [src/commands/init.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/init.ts)_
304
304
 
305
305
  ## `prt list`
306
306
 
@@ -329,7 +329,7 @@ EXAMPLES
329
329
  $ prt list -p=h --incomplete --sort=createdAt
330
330
  ```
331
331
 
332
- _See code: [src/commands/list.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/list.ts)_
332
+ _See code: [src/commands/list.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/list.ts)_
333
333
 
334
334
  ## `prt pass-test TASKID`
335
335
 
@@ -353,7 +353,7 @@ EXAMPLES
353
353
  $ prt pass-test F-001
354
354
  ```
355
355
 
356
- _See code: [src/commands/pass-test.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/pass-test.ts)_
356
+ _See code: [src/commands/pass-test.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/pass-test.ts)_
357
357
 
358
358
  ## `prt plugins`
359
359
 
@@ -667,7 +667,7 @@ EXAMPLES
667
667
  $ prt show F-001
668
668
  ```
669
669
 
670
- _See code: [src/commands/show.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/show.ts)_
670
+ _See code: [src/commands/show.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/show.ts)_
671
671
 
672
672
  ## `prt update TASKID`
673
673
 
@@ -676,7 +676,7 @@ Update a task in place
676
676
  ```
677
677
  USAGE
678
678
  $ prt update TASKID [--clear-notes] [-d <value>] [--no-repo] [-n <value>] [-s
679
- completed|in-progress|not-started] [-t true|false] [-v]
679
+ completed|in-progress|not-started] [-t true|false] [--type bug|feature|improvement|planning|research] [-v]
680
680
 
681
681
  ARGUMENTS
682
682
  TASKID ID of the task to update
@@ -691,6 +691,8 @@ FLAGS
691
691
  -v, --verbose show detailed error information including stack traces
692
692
  --clear-notes clear all notes from the task
693
693
  --no-repo use legacy direct file I/O instead of repository pattern
694
+ --type=<option> update the task type (reassigns task ID and cascades to all references)
695
+ <options: bug|feature|improvement|planning|research>
694
696
 
695
697
  DESCRIPTION
696
698
  Update a task in place
@@ -701,7 +703,7 @@ EXAMPLES
701
703
  $ prt update F-002 --deps="F-001" --clear-notes
702
704
  ```
703
705
 
704
- _See code: [src/commands/update.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/update.ts)_
706
+ _See code: [src/commands/update.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/update.ts)_
705
707
 
706
708
  ## `prt validate`
707
709
 
@@ -722,7 +724,7 @@ EXAMPLES
722
724
  $ prt validate
723
725
  ```
724
726
 
725
- _See code: [src/commands/validate.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.0/src/commands/validate.ts)_
727
+ _See code: [src/commands/validate.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.1/src/commands/validate.ts)_
726
728
  <!-- commandsstop -->
727
729
 
728
730
  ## Development
@@ -769,7 +771,7 @@ prt COMMAND
769
771
 
770
772
  ### Testing
771
773
 
772
- PRT has comprehensive test coverage (98.78%):
774
+ PRT has comprehensive test coverage (96.81%):
773
775
 
774
776
  - **Unit tests**: Services, repositories, utilities, errors
775
777
  - **Command tests**: All CLI commands
@@ -795,10 +797,10 @@ yarn test:coverage:summary
795
797
  For detailed architecture documentation, including design patterns, service layer architecture, repository pattern, and migration path, see [ARCHITECTURE.md](ARCHITECTURE.md).
796
798
 
797
799
  Key architectural features:
798
- - ✓ Service layer for business logic (99.89% coverage)
799
- - ✓ Repository pattern with caching and file watching (96.06% coverage)
800
+ - ✓ Service layer for business logic (97.43% coverage)
801
+ - ✓ Repository pattern with caching and file watching (94.7% coverage)
800
802
  - ✓ Custom error hierarchy with error codes (100% coverage)
801
- - ✓ Comprehensive test suite (98.78% overall coverage)
803
+ - ✓ Comprehensive test suite (96.81% overall coverage)
802
804
  - ✓ Backward compatible legacy mode
803
805
 
804
806
  ### Contributing
@@ -12,6 +12,7 @@ export default class Update extends Command {
12
12
  notes: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
13
  status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
14
  tested: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
16
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
17
  };
17
18
  run(): Promise<void>;
@@ -2,9 +2,10 @@ import { Args, Command, Flags } from '@oclif/core';
2
2
  import { getDefaultConfigRepository } from '../repositories/config.repository.js';
3
3
  import { RoadmapRepository } from '../repositories/roadmap.repository.js';
4
4
  import errorHandlerService from '../services/error-handler.service.js';
5
+ import taskService from '../services/task.service.js';
5
6
  import { readConfigFile } from '../util/read-config.js';
6
7
  import { readRoadmapFile } from '../util/read-roadmap.js';
7
- import { STATUS } from '../util/types.js';
8
+ import { STATUS, TASK_TYPE } from '../util/types.js';
8
9
  import { updateTaskInRoadmap } from '../util/update-task.js';
9
10
  import { validateTaskID } from '../util/validate-task-id.js';
10
11
  import { writeRoadmapFile } from '../util/write-roadmap.js';
@@ -38,6 +39,10 @@ export default class Update extends Command {
38
39
  description: 'update whether the task passes tests',
39
40
  options: ['true', 'false'],
40
41
  }),
42
+ type: Flags.string({
43
+ description: 'update the task type (reassigns task ID and cascades to all references)',
44
+ options: [TASK_TYPE.Bug, TASK_TYPE.Feature, TASK_TYPE.Improvement, TASK_TYPE.Planning, TASK_TYPE.Research],
45
+ }),
41
46
  verbose: Flags.boolean({
42
47
  char: 'v',
43
48
  default: false,
@@ -56,6 +61,23 @@ export default class Update extends Command {
56
61
  const roadmap = flags['no-repo']
57
62
  ? await readRoadmapFile(config.path)
58
63
  : await RoadmapRepository.fromConfig(config).load(config.path);
64
+ // Handle type update separately since it requires ID reassignment and cascading
65
+ if (flags.type) {
66
+ const newType = flags.type;
67
+ const oldTaskId = args.taskID;
68
+ const { newTaskId, roadmap: updatedRoadmap } = taskService.updateTaskType(roadmap, oldTaskId, newType);
69
+ await (flags['no-repo']
70
+ ? writeRoadmapFile(config.path, updatedRoadmap)
71
+ : RoadmapRepository.fromConfig(config).save(config.path, updatedRoadmap));
72
+ if (newTaskId === oldTaskId) {
73
+ this.log(`Task ${oldTaskId} was already of type ${newType}. No changes made.`);
74
+ }
75
+ else {
76
+ this.log(`Task ${oldTaskId} has been updated to type ${newType} with new ID ${newTaskId}.`);
77
+ this.log(`All task references to ${oldTaskId} have been updated to ${newTaskId}.`);
78
+ }
79
+ return;
80
+ }
59
81
  const updateObject = {};
60
82
  if (flags['clear-notes']) {
61
83
  updateObject.notes = '';
@@ -1,4 +1,4 @@
1
- import { Ajv } from 'ajv';
1
+ import Ajv from 'ajv';
2
2
  import { readFile, stat } from 'node:fs/promises';
3
3
  import { homedir } from 'node:os';
4
4
  import { join } from 'node:path';
@@ -76,7 +76,7 @@ export class ConfigRepository {
76
76
  searchPaths: config?.searchPaths ?? this.getDefaultSearchPaths(),
77
77
  };
78
78
  // Initialize JSON schema validator
79
- const ajv = new Ajv({ allErrors: true, strict: false });
79
+ const ajv = new Ajv({ allErrors: true });
80
80
  this.validateSchema = ajv.compile(ConfigRepository.configSchema);
81
81
  }
82
82
  /**
@@ -237,7 +237,7 @@ export class ConfigRepository {
237
237
  ]);
238
238
  }
239
239
  const errorDetails = this.validateSchema.errors.map((err) => ({
240
- field: err.instancePath || 'config',
240
+ field: err.dataPath || 'config',
241
241
  message: err.message || 'Unknown error',
242
242
  type: 'structure',
243
243
  }));
@@ -117,6 +117,29 @@ export declare class TaskService {
117
117
  * ```
118
118
  */
119
119
  updateTask(roadmap: Roadmap, taskId: string, updates: Partial<Task>): Roadmap;
120
+ /**
121
+ * Updates a task's type, reassigning its ID and cascading the change to all references.
122
+ * When a task type is changed, a new ID is generated to match the new type prefix.
123
+ * All other tasks that reference the old ID in their depends-on or blocks arrays
124
+ * will be updated to reference the new ID.
125
+ *
126
+ * @param roadmap - The roadmap containing the task to update
127
+ * @param taskId - The current ID of the task to update
128
+ * @param newType - The new task type to assign
129
+ * @returns An object containing the updated Roadmap and the new task ID
130
+ * @throws Error if the task with the given ID is not found
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * // Change task F-001 to a bug (will become B-001 or next available B-XXX)
135
+ * const {roadmap: updatedRoadmap, newTaskId} = taskService.updateTaskType(roadmap, 'F-001', TASK_TYPE.Bug);
136
+ * // All tasks that had 'F-001' in depends-on or blocks will now have the new bug ID
137
+ * ```
138
+ */
139
+ updateTaskType(roadmap: Roadmap, taskId: string, newType: TASK_TYPE): {
140
+ newTaskId: TaskID;
141
+ roadmap: Roadmap;
142
+ };
120
143
  }
121
144
  /**
122
145
  * Default export instance of TaskService for convenience.
@@ -159,6 +159,66 @@ export class TaskService {
159
159
  tasks: [...roadmap.tasks.slice(0, taskIndex), updatedTask, ...roadmap.tasks.slice(taskIndex + 1)],
160
160
  };
161
161
  }
162
+ /**
163
+ * Updates a task's type, reassigning its ID and cascading the change to all references.
164
+ * When a task type is changed, a new ID is generated to match the new type prefix.
165
+ * All other tasks that reference the old ID in their depends-on or blocks arrays
166
+ * will be updated to reference the new ID.
167
+ *
168
+ * @param roadmap - The roadmap containing the task to update
169
+ * @param taskId - The current ID of the task to update
170
+ * @param newType - The new task type to assign
171
+ * @returns An object containing the updated Roadmap and the new task ID
172
+ * @throws Error if the task with the given ID is not found
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * // Change task F-001 to a bug (will become B-001 or next available B-XXX)
177
+ * const {roadmap: updatedRoadmap, newTaskId} = taskService.updateTaskType(roadmap, 'F-001', TASK_TYPE.Bug);
178
+ * // All tasks that had 'F-001' in depends-on or blocks will now have the new bug ID
179
+ * ```
180
+ */
181
+ updateTaskType(roadmap, taskId, newType) {
182
+ const task = this.findTask(roadmap, taskId);
183
+ if (!task) {
184
+ throw new TaskNotFoundError(taskId);
185
+ }
186
+ // If the type isn't changing, just return the roadmap unchanged with the same task ID
187
+ if (task.type === newType) {
188
+ return { newTaskId: taskId, roadmap };
189
+ }
190
+ // Generate a new ID for the new type
191
+ const newTaskId = this.generateNextId(roadmap, newType);
192
+ // Update the task with the new type and new ID
193
+ let updatedRoadmap = this.updateTask(roadmap, taskId, {
194
+ id: newTaskId,
195
+ type: newType,
196
+ });
197
+ // Cascade the ID change to all tasks that reference the old ID
198
+ updatedRoadmap = {
199
+ ...updatedRoadmap,
200
+ tasks: updatedRoadmap.tasks.map((t) => {
201
+ // Skip the task we just updated
202
+ if (t.id === newTaskId) {
203
+ return t;
204
+ }
205
+ // Check if this task references the old ID in depends-on or blocks
206
+ const hasDependency = t['depends-on'].includes(taskId);
207
+ const hasBlock = t.blocks.includes(taskId);
208
+ if (!hasDependency && !hasBlock) {
209
+ return t;
210
+ }
211
+ // Update the references
212
+ return {
213
+ ...t,
214
+ blocks: hasBlock ? t.blocks.map((id) => (id === taskId ? newTaskId : id)) : t.blocks,
215
+ 'depends-on': hasDependency ? t['depends-on'].map((id) => (id === taskId ? newTaskId : id)) : t['depends-on'],
216
+ updatedAt: new Date().toISOString(),
217
+ };
218
+ }),
219
+ };
220
+ return { newTaskId, roadmap: updatedRoadmap };
221
+ }
162
222
  }
163
223
  /**
164
224
  * Default export instance of TaskService for convenience.
@@ -470,6 +470,20 @@
470
470
  ],
471
471
  "type": "option"
472
472
  },
473
+ "type": {
474
+ "description": "update the task type (reassigns task ID and cascades to all references)",
475
+ "name": "type",
476
+ "hasDynamicHelp": false,
477
+ "multiple": false,
478
+ "options": [
479
+ "bug",
480
+ "feature",
481
+ "improvement",
482
+ "planning",
483
+ "research"
484
+ ],
485
+ "type": "option"
486
+ },
473
487
  "verbose": {
474
488
  "char": "v",
475
489
  "description": "show detailed error information including stack traces",
@@ -531,5 +545,5 @@
531
545
  ]
532
546
  }
533
547
  },
534
- "version": "0.2.0"
548
+ "version": "0.2.1"
535
549
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "project-roadmap-tracking",
3
3
  "description": "CLI based project task tracking",
4
- "version": "0.2.0",
4
+ "version": "0.2.1",
5
5
  "author": "ZacharyEggert",
6
6
  "bin": {
7
7
  "prt": "./bin/run.js"
@@ -44,7 +44,15 @@
44
44
  ],
45
45
  "homepage": "https://github.com/ZacharyEggert/project-roadmap-tracking",
46
46
  "keywords": [
47
- "oclif"
47
+ "oclif",
48
+ "cli",
49
+ "project",
50
+ "roadmap",
51
+ "tracking",
52
+ "tasks",
53
+ "productivity",
54
+ "management",
55
+ "prt"
48
56
  ],
49
57
  "license": "MIT",
50
58
  "main": "dist/index.js",