project-roadmap-tracking 0.2.5 → 0.2.7

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
@@ -49,6 +49,9 @@ prt list -p high
49
49
  # Show task details
50
50
  prt show F-001
51
51
 
52
+ # Show task details with dependencies
53
+ prt show F-001 -d
54
+
52
55
  # Update task status
53
56
  prt update F-001 --status=in-progress
54
57
 
@@ -137,6 +140,7 @@ IDs are auto-generated sequentially per task type.
137
140
  * [Add a new feature](#add-a-new-feature)
138
141
  * [List all high-priority tasks](#list-all-high-priority-tasks)
139
142
  * [Show task details](#show-task-details)
143
+ * [Show task details with dependencies](#show-task-details-with-dependencies)
140
144
  * [Update task status](#update-task-status)
141
145
  * [Complete a task](#complete-a-task)
142
146
  * [Validate roadmap integrity](#validate-roadmap-integrity)
@@ -156,6 +160,10 @@ IDs are auto-generated sequentially per task type.
156
160
  * [Run a specific test file](#run-a-specific-test-file)
157
161
  * [Generate coverage report](#generate-coverage-report)
158
162
  * [View coverage summary](#view-coverage-summary)
163
+ * [1. Update version](#1-update-version)
164
+ * [2. Build and package](#2-build-and-package)
165
+ * [3. Publish to npm](#3-publish-to-npm)
166
+ * [4. Create GitHub release](#4-create-github-release)
159
167
  <!-- tocstop -->
160
168
 
161
169
  # Usage
@@ -166,7 +174,7 @@ $ npm install -g project-roadmap-tracking
166
174
  $ prt COMMAND
167
175
  running command...
168
176
  $ prt (--version)
169
- project-roadmap-tracking/0.2.5 linux-x64 node-v25.4.0
177
+ project-roadmap-tracking/0.2.7 linux-x64 node-v25.4.0
170
178
  $ prt --help [COMMAND]
171
179
  USAGE
172
180
  $ prt COMMAND
@@ -228,7 +236,7 @@ EXAMPLES
228
236
  $ prt add
229
237
  ```
230
238
 
231
- _See code: [src/commands/add.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/add.ts)_
239
+ _See code: [src/commands/add.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/add.ts)_
232
240
 
233
241
  ## `prt complete TASKID`
234
242
 
@@ -253,7 +261,7 @@ EXAMPLES
253
261
  $ prt complete F-001 --tests
254
262
  ```
255
263
 
256
- _See code: [src/commands/complete.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/complete.ts)_
264
+ _See code: [src/commands/complete.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/complete.ts)_
257
265
 
258
266
  ## `prt help [COMMAND]`
259
267
 
@@ -300,7 +308,7 @@ EXAMPLES
300
308
  $ prt init [path/to/directory]
301
309
  ```
302
310
 
303
- _See code: [src/commands/init.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/init.ts)_
311
+ _See code: [src/commands/init.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/init.ts)_
304
312
 
305
313
  ## `prt list`
306
314
 
@@ -329,7 +337,7 @@ EXAMPLES
329
337
  $ prt list -p=h --incomplete --sort=createdAt
330
338
  ```
331
339
 
332
- _See code: [src/commands/list.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/list.ts)_
340
+ _See code: [src/commands/list.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/list.ts)_
333
341
 
334
342
  ## `prt pass-test TASKID`
335
343
 
@@ -353,7 +361,7 @@ EXAMPLES
353
361
  $ prt pass-test F-001
354
362
  ```
355
363
 
356
- _See code: [src/commands/pass-test.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/pass-test.ts)_
364
+ _See code: [src/commands/pass-test.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/pass-test.ts)_
357
365
 
358
366
  ## `prt plugins`
359
367
 
@@ -651,14 +659,15 @@ show details of a specific task in the project roadmap
651
659
 
652
660
  ```
653
661
  USAGE
654
- $ prt show TASK [--no-repo] [-v]
662
+ $ prt show TASK [--no-repo] [-d] [-v]
655
663
 
656
664
  ARGUMENTS
657
665
  TASK task ID to show
658
666
 
659
667
  FLAGS
660
- -v, --verbose show detailed error information including stack traces
661
- --no-repo use legacy direct file I/O instead of repository pattern
668
+ -d, --show-dependencies show task dependencies
669
+ -v, --verbose show detailed error information including stack traces
670
+ --no-repo use legacy direct file I/O instead of repository pattern
662
671
 
663
672
  DESCRIPTION
664
673
  show details of a specific task in the project roadmap
@@ -667,7 +676,7 @@ EXAMPLES
667
676
  $ prt show F-001
668
677
  ```
669
678
 
670
- _See code: [src/commands/show.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/show.ts)_
679
+ _See code: [src/commands/show.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/show.ts)_
671
680
 
672
681
  ## `prt update TASKID`
673
682
 
@@ -703,7 +712,7 @@ EXAMPLES
703
712
  $ prt update F-002 --deps="F-001" --clear-notes
704
713
  ```
705
714
 
706
- _See code: [src/commands/update.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/update.ts)_
715
+ _See code: [src/commands/update.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/update.ts)_
707
716
 
708
717
  ## `prt validate`
709
718
 
@@ -724,7 +733,7 @@ EXAMPLES
724
733
  $ prt validate
725
734
  ```
726
735
 
727
- _See code: [src/commands/validate.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.5/src/commands/validate.ts)_
736
+ _See code: [src/commands/validate.ts](https://github.com/ZacharyEggert/project-roadmap-tracking/blob/v0.2.7/src/commands/validate.ts)_
728
737
  <!-- commandsstop -->
729
738
 
730
739
  ## Development
@@ -809,11 +818,92 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
809
818
 
810
819
  ### Release Process
811
820
 
812
- 1. Update version in `package.json`
813
- 2. Run `yarn prepack` (generates manifest and updates README)
814
- 3. Commit changes
815
- 4. Run `yarn pack` to create tarball
816
- 5. Run `npm publish` to publish to npm registry
821
+ PRT uses a fully automated CI/CD pipeline powered by GitHub Actions. Releases are created automatically when code is pushed to the `master` branch.
822
+
823
+ #### Automated Release (Standard Process)
824
+
825
+ 1. **Update version** in `package.json`:
826
+ ```bash
827
+ # Example: 0.2.6 → 0.2.7
828
+ npm version patch # or minor, or major
829
+ ```
830
+
831
+ 2. **Commit and push** to `master`:
832
+ ```bash
833
+ git add package.json
834
+ git commit -m "chore: bump version to 0.2.7"
835
+ git push origin master
836
+ ```
837
+
838
+ 3. **GitHub Actions automatically**:
839
+ - ✅ Runs test suite (944 tests must pass)
840
+ - ✅ Validates build and linting
841
+ - ✅ Creates GitHub release (only if tests pass)
842
+ - ✅ Publishes to npm registry
843
+ - ⏱️ Total time: ~4-6 minutes
844
+
845
+ **Quality Gate:** If tests fail, no release is created. Fix the issues and push again.
846
+
847
+ #### Manual Release (Fallback)
848
+
849
+ For emergency releases or when automation is unavailable:
850
+
851
+ ```bash
852
+ # 1. Update version
853
+ npm version patch
854
+
855
+ # 2. Build and package
856
+ yarn prepack # generates manifest, updates README
857
+ yarn pack # creates tarball
858
+
859
+ # 3. Publish to npm
860
+ npm publish
861
+
862
+ # 4. Create GitHub release
863
+ gh release create v$(node -p "require('./package.json').version") --generate-notes
864
+ ```
865
+
866
+ #### Required GitHub Secrets
867
+
868
+ For automated releases, configure these secrets in your GitHub repository:
869
+
870
+ | Secret | Purpose |
871
+ |--------|---------|
872
+ | `GH_TOKEN` | GitHub API access (repo + workflow scopes) |
873
+ | `GH_EMAIL` | Git commit author email |
874
+ | `GH_USERNAME` | Git commit author name |
875
+ | `NPM_TOKEN` | npm authentication (optional with Trusted Publishing) |
876
+
877
+ #### npm Authentication
878
+
879
+ **Option A: Trusted Publishing (Recommended)**
880
+ - More secure (OIDC-based, no long-lived tokens)
881
+ - Configure at: https://www.npmjs.com/settings/project-roadmap-tracking/packages/project-roadmap-tracking/access
882
+ - No `NPM_TOKEN` secret needed
883
+
884
+ **Option B: Granular Access Token**
885
+ - Generate at: https://www.npmjs.com/settings/~/tokens
886
+ - Permissions: Read and write for `project-roadmap-tracking` package
887
+ - Store as `NPM_TOKEN` GitHub secret
888
+
889
+ #### CI/CD Workflows
890
+
891
+ The project uses three GitHub Actions workflows:
892
+
893
+ 1. **`test.yml`** - Runs on feature branches
894
+ - Tests across Ubuntu/Windows
895
+ - Tests across Node LTS versions
896
+ - Fast feedback during development
897
+
898
+ 2. **`onPushToMaster.yml`** - Runs on master push
899
+ - Test job (build + tests + lint) ← **Quality gate**
900
+ - Release job (create GitHub release) ← **Only runs if tests pass**
901
+
902
+ 3. **`onRelease.yml`** - Runs when release created
903
+ - Builds package
904
+ - Publishes to npm with provenance
905
+
906
+ For detailed CI/CD architecture, see [ARCHITECTURE.md - CI/CD Pipeline](ARCHITECTURE.md#cicd-pipeline)
817
907
 
818
908
  ## License
819
909
 
@@ -7,6 +7,7 @@ export default class Show extends Command {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  'no-repo': import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ 'show-dependencies': import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
11
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
12
  };
12
13
  run(): Promise<void>;
@@ -16,6 +16,11 @@ export default class Show extends Command {
16
16
  default: false,
17
17
  description: 'use legacy direct file I/O instead of repository pattern',
18
18
  }),
19
+ 'show-dependencies': Flags.boolean({
20
+ char: 'd',
21
+ default: false,
22
+ description: 'show task dependencies',
23
+ }),
19
24
  // flag with no value (-f, --force)
20
25
  // force: Flags.boolean({char: 'f'}),
21
26
  // flag with a value (-n, --name=VALUE)
@@ -43,6 +48,12 @@ export default class Show extends Command {
43
48
  for (const line of lines) {
44
49
  console.log(line);
45
50
  }
51
+ if (flags['show-dependencies'] && task) {
52
+ const dependencyLines = displayService.formatTaskDependencies(task, roadmap);
53
+ for (const line of dependencyLines) {
54
+ console.log(line);
55
+ }
56
+ }
46
57
  }
47
58
  catch (error) {
48
59
  const exitCode = errorHandlerService.handleError(error);
@@ -1,5 +1,14 @@
1
1
  import { watch } from 'chokidar';
2
2
  import { readFile, stat, writeFile } from 'node:fs/promises';
3
+ /**
4
+ * Detect if we're running in a test environment
5
+ */
6
+ function isTestEnvironment() {
7
+ return (process.env.NODE_ENV === 'test' ||
8
+ process.env.MOCHA === 'true' ||
9
+ typeof globalThis.describe === 'function' ||
10
+ typeof globalThis.it === 'function');
11
+ }
3
12
  /**
4
13
  * RoadmapRepository provides caching and file watching for roadmap data.
5
14
  * Features:
@@ -13,20 +22,24 @@ export class RoadmapRepository {
13
22
  config;
14
23
  watchers = new Map();
15
24
  constructor(config) {
25
+ // Disable file watching in test environments by default
26
+ const defaultWatchFiles = !isTestEnvironment();
16
27
  this.config = {
17
28
  cacheEnabled: config?.cacheEnabled ?? true,
18
29
  maxCacheSize: config?.maxCacheSize ?? 10,
19
- watchFiles: config?.watchFiles ?? true,
30
+ watchFiles: config?.watchFiles ?? defaultWatchFiles,
20
31
  };
21
32
  }
22
33
  /**
23
34
  * Create a repository instance from a Config object
24
35
  */
25
36
  static fromConfig(config) {
37
+ // Respect explicit watchFiles setting in config, but default based on environment
38
+ const defaultWatchFiles = !isTestEnvironment();
26
39
  return new RoadmapRepository({
27
40
  cacheEnabled: config.cache?.enabled ?? true,
28
41
  maxCacheSize: config.cache?.maxSize ?? 10,
29
- watchFiles: config.cache?.watchFiles ?? true,
42
+ watchFiles: config.cache?.watchFiles ?? defaultWatchFiles,
30
43
  });
31
44
  }
32
45
  /**
@@ -153,27 +166,46 @@ export class RoadmapRepository {
153
166
  * Set up file watcher for a path
154
167
  */
155
168
  setupWatcher(path) {
156
- const watcher = watch(path, {
157
- awaitWriteFinish: {
158
- pollInterval: 100,
159
- stabilityThreshold: 250,
160
- },
161
- persistent: false,
162
- });
163
- watcher.on('change', () => {
164
- this.invalidate(path);
165
- });
166
- watcher.on('unlink', () => {
167
- this.invalidate(path);
168
- this.watchers
169
- .get(path)
170
- ?.close()
171
- .catch(() => {
172
- /* ignore close errors */
169
+ try {
170
+ const watcher = watch(path, {
171
+ awaitWriteFinish: {
172
+ pollInterval: 100,
173
+ stabilityThreshold: 250,
174
+ },
175
+ persistent: false,
173
176
  });
174
- this.watchers.delete(path);
175
- });
176
- this.watchers.set(path, watcher);
177
+ watcher.on('change', () => {
178
+ this.invalidate(path);
179
+ });
180
+ watcher.on('unlink', () => {
181
+ this.invalidate(path);
182
+ this.watchers
183
+ .get(path)
184
+ ?.close()
185
+ .catch(() => {
186
+ /* ignore close errors */
187
+ });
188
+ this.watchers.delete(path);
189
+ });
190
+ watcher.on('error', (error) => {
191
+ // Log error but don't crash - especially important for Windows EPERM errors
192
+ if (process.env.NODE_ENV !== 'production') {
193
+ console.warn(`File watcher error for ${path}:`, error.message);
194
+ }
195
+ // Clean up the watcher on error
196
+ this.watchers.get(path)?.close().catch(() => {
197
+ /* ignore close errors */
198
+ });
199
+ this.watchers.delete(path);
200
+ });
201
+ this.watchers.set(path, watcher);
202
+ }
203
+ catch (error) {
204
+ // If watcher setup fails (e.g., permission issues), log and continue
205
+ if (process.env.NODE_ENV !== 'production') {
206
+ console.warn(`Failed to set up file watcher for ${path}:`, error.message);
207
+ }
208
+ }
177
209
  }
178
210
  }
179
211
  // Singleton instance with default configuration
@@ -1,4 +1,4 @@
1
- import { PRIORITY, STATUS, Task } from '../util/types.js';
1
+ import { PRIORITY, Roadmap, STATUS, Task } from '../util/types.js';
2
2
  import { RoadmapStats } from './roadmap.service.js';
3
3
  import { DependencyValidationError } from './task-dependency.service.js';
4
4
  /**
@@ -80,6 +80,15 @@ export declare class DisplayService {
80
80
  * ```
81
81
  */
82
82
  formatStatusText(status: STATUS): string;
83
+ /**
84
+ * Formats the dependencies of a task for display.
85
+ *
86
+ *
87
+ * @param task - the task whose dependencies are to be formatted
88
+ * @param roadmap - the roadmap containing all tasks
89
+ * @returns Array of formatted dependency lines
90
+ */
91
+ formatTaskDependencies(task: Task, roadmap: Roadmap): string[];
83
92
  /**
84
93
  * Formats complete task details for show command.
85
94
  * Returns an array of lines to be output.
@@ -124,6 +124,34 @@ export class DisplayService {
124
124
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
125
125
  .join(' ');
126
126
  }
127
+ /**
128
+ * Formats the dependencies of a task for display.
129
+ *
130
+ *
131
+ * @param task - the task whose dependencies are to be formatted
132
+ * @param roadmap - the roadmap containing all tasks
133
+ * @returns Array of formatted dependency lines
134
+ */
135
+ formatTaskDependencies(task, roadmap) {
136
+ const lines = [];
137
+ lines.push(`\nDependencies for Task: ${task.id}\n`);
138
+ if (task['depends-on'].length === 0) {
139
+ lines.push('This task has no dependencies.\n');
140
+ return lines;
141
+ }
142
+ for (const depId of task['depends-on']) {
143
+ const depTask = roadmap.tasks.find((t) => t.id === depId);
144
+ if (depTask) {
145
+ const statusSymbol = this.formatStatusSymbol(depTask.status);
146
+ const priorityLabel = this.formatPriorityLabel(depTask.priority);
147
+ lines.push(` ${statusSymbol} [${priorityLabel}] [${depTask.id}] ${depTask.title}`, ` Details: ${depTask.details}\n`);
148
+ }
149
+ else {
150
+ lines.push(`❌ [Unknown Task] [${depId}] (Task not found in roadmap)`);
151
+ }
152
+ }
153
+ return lines;
154
+ }
127
155
  /**
128
156
  * Formats complete task details for show command.
129
157
  * Returns an array of lines to be output.
@@ -379,6 +379,13 @@
379
379
  "allowNo": false,
380
380
  "type": "boolean"
381
381
  },
382
+ "show-dependencies": {
383
+ "char": "d",
384
+ "description": "show task dependencies",
385
+ "name": "show-dependencies",
386
+ "allowNo": false,
387
+ "type": "boolean"
388
+ },
382
389
  "verbose": {
383
390
  "char": "v",
384
391
  "description": "show detailed error information including stack traces",
@@ -545,5 +552,5 @@
545
552
  ]
546
553
  }
547
554
  },
548
- "version": "0.2.5"
555
+ "version": "0.2.7"
549
556
  }
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.5",
4
+ "version": "0.2.7",
5
5
  "author": "ZacharyEggert",
6
6
  "bin": {
7
7
  "prt": "./bin/run.js"
@@ -23,6 +23,7 @@
23
23
  "@types/node": "^18",
24
24
  "c8": "^10.1.3",
25
25
  "chai": "^4",
26
+ "cross-env": "^10.1.0",
26
27
  "eslint": "^9",
27
28
  "eslint-config-oclif": "^6",
28
29
  "eslint-config-prettier": "^10",
@@ -45,14 +46,14 @@
45
46
  "homepage": "https://github.com/ZacharyEggert/project-roadmap-tracking",
46
47
  "keywords": [
47
48
  "oclif",
48
- "cli",
49
- "project",
50
- "roadmap",
51
- "tracking",
52
- "tasks",
53
- "productivity",
54
- "management",
55
- "prt"
49
+ "cli",
50
+ "project",
51
+ "roadmap",
52
+ "tracking",
53
+ "tasks",
54
+ "productivity",
55
+ "management",
56
+ "prt"
56
57
  ],
57
58
  "license": "MIT",
58
59
  "main": "dist/index.js",
@@ -81,7 +82,7 @@
81
82
  "postpack": "shx rm -f oclif.manifest.json",
82
83
  "posttest": "yarn lint",
83
84
  "prepack": "oclif manifest && oclif readme",
84
- "test": "c8 mocha --loader=tsx/esm --forbid-only 'test/**/*.test.ts'",
85
+ "test": "cross-env NODE_ENV=test c8 mocha --loader=tsx/esm --forbid-only 'test/**/*.test.ts'",
85
86
  "test:coverage": "c8 report",
86
87
  "test:coverage:summary": "c8 report --reporter=text",
87
88
  "version": "oclif readme && git add README.md"