opencode-conductor-cdd-plugin 1.0.0-beta.16 → 1.0.0-beta.18

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.
@@ -0,0 +1,81 @@
1
+ // ANSI color codes
2
+ const colors = {
3
+ reset: "\x1b[0m",
4
+ bright: "\x1b[1m",
5
+ dim: "\x1b[2m",
6
+ green: "\x1b[32m",
7
+ yellow: "\x1b[33m",
8
+ blue: "\x1b[34m",
9
+ cyan: "\x1b[36m",
10
+ gray: "\x1b[90m"
11
+ };
12
+ /**
13
+ * Calculates progress percentage
14
+ * @param completed Number of completed items
15
+ * @param total Total number of items
16
+ * @returns Progress percentage (0-100)
17
+ */
18
+ export function calculateProgress(completed, total) {
19
+ if (total === 0)
20
+ return 0;
21
+ return Math.round((completed / total) * 100);
22
+ }
23
+ /**
24
+ * Generates a visual progress bar
25
+ * @param percentage Progress percentage (0-100)
26
+ * @param length Length of the progress bar (default: 20)
27
+ * @returns Progress bar string
28
+ */
29
+ export function generateProgressBar(percentage, length = 20) {
30
+ const filled = Math.round((percentage / 100) * length);
31
+ const empty = length - filled;
32
+ return "█".repeat(filled) + "░".repeat(empty);
33
+ }
34
+ /**
35
+ * Formats track status into a visually appealing display
36
+ * @param track Track status information
37
+ * @param options Formatting options
38
+ * @returns Formatted status string
39
+ */
40
+ export function formatTrackStatus(track, options = {}) {
41
+ const { compact = false, noColor = false, barLength = 20 } = options;
42
+ const c = noColor
43
+ ? {
44
+ reset: "",
45
+ bright: "",
46
+ dim: "",
47
+ green: "",
48
+ yellow: "",
49
+ blue: "",
50
+ cyan: "",
51
+ gray: ""
52
+ }
53
+ : colors;
54
+ const progress = calculateProgress(track.completedTasks, track.totalTasks);
55
+ const progressBar = generateProgressBar(progress, barLength);
56
+ if (compact) {
57
+ return `${c.bright}${track.trackName}${c.reset} ${c.gray}[${track.trackId}]${c.reset}
58
+ ${c.cyan}${track.currentPhase}${c.reset} ${c.dim}|${c.reset} ${c.green}${track.completedTasks}${c.reset}/${track.totalTasks} tasks ${c.dim}(${progress}%)${c.reset}`;
59
+ }
60
+ const inProgressInfo = track.inProgressTasks > 0 ? `, ${track.inProgressTasks} in progress` : "";
61
+ const formattedDate = new Date(track.lastUpdated).toLocaleString("en-US", {
62
+ year: "numeric",
63
+ month: "short",
64
+ day: "numeric",
65
+ hour: "2-digit",
66
+ minute: "2-digit"
67
+ });
68
+ return `${c.bright}${c.blue}━━━ Track Status ━━━${c.reset}
69
+
70
+ ${c.bright}Track:${c.reset} ${track.trackName}
71
+ ${c.dim}ID: ${track.trackId}${c.reset}
72
+
73
+ ${c.bright}Phase:${c.reset} ${c.cyan}${track.currentPhase}${c.reset}
74
+
75
+ ${c.bright}Progress:${c.reset} ${c.green}${track.completedTasks}${c.reset}/${track.totalTasks} tasks ${c.dim}(${progress}%)${c.reset}${inProgressInfo}
76
+ ${progressBar}
77
+
78
+ ${c.gray}Last updated: ${formattedDate}${c.reset}
79
+
80
+ ${c.bright}${c.blue}━━━━━━━━━━━━━━━━━━━━${c.reset}`;
81
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatTrackStatus, calculateProgress, generateProgressBar } from "./statusDisplay.js";
3
+ describe("statusDisplay", () => {
4
+ describe("calculateProgress", () => {
5
+ it("should calculate progress percentage correctly", () => {
6
+ expect(calculateProgress(3, 10)).toBe(30);
7
+ expect(calculateProgress(5, 5)).toBe(100);
8
+ expect(calculateProgress(0, 10)).toBe(0);
9
+ });
10
+ it("should handle zero total gracefully", () => {
11
+ expect(calculateProgress(0, 0)).toBe(0);
12
+ });
13
+ it("should round to nearest integer", () => {
14
+ expect(calculateProgress(1, 3)).toBe(33);
15
+ expect(calculateProgress(2, 3)).toBe(67);
16
+ });
17
+ });
18
+ describe("generateProgressBar", () => {
19
+ it("should generate a progress bar with default length", () => {
20
+ const bar = generateProgressBar(50);
21
+ expect(bar).toHaveLength(20); // Default bar length
22
+ expect(bar).toContain("█");
23
+ expect(bar).toContain("░");
24
+ });
25
+ it("should generate full bar at 100%", () => {
26
+ const bar = generateProgressBar(100, 10);
27
+ expect(bar).toBe("██████████");
28
+ });
29
+ it("should generate empty bar at 0%", () => {
30
+ const bar = generateProgressBar(0, 10);
31
+ expect(bar).toBe("░░░░░░░░░░");
32
+ });
33
+ it("should handle custom bar length", () => {
34
+ const bar = generateProgressBar(50, 30);
35
+ expect(bar).toHaveLength(30);
36
+ });
37
+ it("should show correct filled/unfilled ratio", () => {
38
+ const bar = generateProgressBar(25, 8);
39
+ expect(bar).toBe("██░░░░░░"); // 25% of 8 = 2 filled
40
+ });
41
+ });
42
+ describe("formatTrackStatus", () => {
43
+ const sampleTrack = {
44
+ trackId: "track_test_123",
45
+ trackName: "Implement Authentication",
46
+ totalTasks: 10,
47
+ completedTasks: 7,
48
+ inProgressTasks: 1,
49
+ currentPhase: "Phase 2: Implementation",
50
+ lastUpdated: "2026-01-18T12:00:00Z"
51
+ };
52
+ it("should format a complete track status display", () => {
53
+ const status = formatTrackStatus(sampleTrack);
54
+ expect(status).toContain("Implement Authentication");
55
+ expect(status).toContain("Phase 2: Implementation");
56
+ expect(status).toMatch(/7.*\/.*10.*tasks/); // Match "7/10 tasks" with potential ANSI codes
57
+ expect(status).toContain("█"); // Progress bar
58
+ expect(status).toContain("Last updated:");
59
+ });
60
+ it("should show 100% completion for fully complete track", () => {
61
+ const completeTrack = {
62
+ ...sampleTrack,
63
+ completedTasks: 10,
64
+ inProgressTasks: 0,
65
+ currentPhase: "Completed"
66
+ };
67
+ const status = formatTrackStatus(completeTrack);
68
+ expect(status).toContain("100%");
69
+ expect(status).toMatch(/10.*\/.*10.*tasks/); // Match "10/10 tasks" with potential ANSI codes
70
+ });
71
+ it("should indicate in-progress tasks", () => {
72
+ const status = formatTrackStatus(sampleTrack);
73
+ expect(status).toContain("1 in progress");
74
+ });
75
+ it("should handle track with no tasks", () => {
76
+ const emptyTrack = {
77
+ ...sampleTrack,
78
+ totalTasks: 0,
79
+ completedTasks: 0,
80
+ inProgressTasks: 0
81
+ };
82
+ const status = formatTrackStatus(emptyTrack);
83
+ expect(status).toMatch(/0.*\/.*0.*tasks/); // Match "0/0 tasks" with potential ANSI codes
84
+ expect(status).toContain("0%");
85
+ });
86
+ it("should include color indicators in status (ANSI codes)", () => {
87
+ const status = formatTrackStatus(sampleTrack);
88
+ // Should contain ANSI escape codes for colors
89
+ expect(status).toMatch(/\x1b\[\d+m/); // Contains ANSI color codes
90
+ });
91
+ it("should format status with compact mode option", () => {
92
+ const status = formatTrackStatus(sampleTrack, { compact: true });
93
+ // Compact mode should be shorter (no progress bar or timestamps)
94
+ expect(status.split("\n").length).toBeLessThan(5);
95
+ });
96
+ it("should allow disabling color output", () => {
97
+ const status = formatTrackStatus(sampleTrack, { noColor: true });
98
+ // Should not contain ANSI escape codes
99
+ expect(status).not.toMatch(/\x1b\[\d+m/);
100
+ });
101
+ });
102
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-conductor-cdd-plugin",
3
- "version": "1.0.0-beta.16",
3
+ "version": "1.0.0-beta.18",
4
4
  "description": "Context-Driven Development (CDD) plugin for OpenCode - Transform your AI coding workflow with structured specifications, plans, and implementation tracking",
5
5
  "type": "module",
6
6
  "repository": {