@task-mcp/shared 1.0.10 → 1.0.11
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/dist/utils/dashboard-renderer.d.ts +83 -0
- package/dist/utils/dashboard-renderer.d.ts.map +1 -0
- package/dist/utils/dashboard-renderer.js +416 -0
- package/dist/utils/dashboard-renderer.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/utils/dashboard-renderer.ts +606 -0
- package/src/utils/index.ts +18 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dashboard renderer for CLI and MCP server
|
|
3
|
+
* Provides consistent dashboard layout across all interfaces
|
|
4
|
+
*/
|
|
5
|
+
import type { Task, Project, InboxItem } from "../schemas/index.js";
|
|
6
|
+
export interface DashboardStats {
|
|
7
|
+
total: number;
|
|
8
|
+
completed: number;
|
|
9
|
+
inProgress: number;
|
|
10
|
+
pending: number;
|
|
11
|
+
blocked: number;
|
|
12
|
+
cancelled: number;
|
|
13
|
+
byPriority: {
|
|
14
|
+
critical: number;
|
|
15
|
+
high: number;
|
|
16
|
+
medium: number;
|
|
17
|
+
low: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface DependencyMetrics {
|
|
21
|
+
readyToWork: number;
|
|
22
|
+
blockedByDependencies: number;
|
|
23
|
+
mostDependedOn?: {
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
dependentCount: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface DashboardData {
|
|
30
|
+
tasks: Task[];
|
|
31
|
+
projects: Project[];
|
|
32
|
+
inboxItems?: InboxItem[];
|
|
33
|
+
currentProject?: Project;
|
|
34
|
+
version?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function calculateStats(tasks: Task[]): DashboardStats;
|
|
37
|
+
export declare function calculateDependencyMetrics(tasks: Task[]): DependencyMetrics;
|
|
38
|
+
/**
|
|
39
|
+
* Render Status widget (progress, counts, priorities, dependencies)
|
|
40
|
+
*/
|
|
41
|
+
export declare function renderStatusWidget(tasks: Task[], _projects: Project[]): string;
|
|
42
|
+
/**
|
|
43
|
+
* Render Next Actions widget (top ready tasks)
|
|
44
|
+
*/
|
|
45
|
+
export declare function renderActionsWidget(tasks: Task[]): string;
|
|
46
|
+
/**
|
|
47
|
+
* Render Inbox widget (pending items)
|
|
48
|
+
*/
|
|
49
|
+
export declare function renderInboxWidget(inboxItems: InboxItem[]): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Render Projects table
|
|
52
|
+
*/
|
|
53
|
+
export declare function renderProjectsTable(projects: Project[], getProjectTasks: (projectId: string) => Task[]): string;
|
|
54
|
+
/**
|
|
55
|
+
* Render Tasks table for single project view
|
|
56
|
+
*/
|
|
57
|
+
export declare function renderTasksTable(tasks: Task[], limit?: number): string;
|
|
58
|
+
export interface RenderDashboardOptions {
|
|
59
|
+
showBanner?: boolean;
|
|
60
|
+
showInbox?: boolean;
|
|
61
|
+
showProjects?: boolean;
|
|
62
|
+
showTasks?: boolean;
|
|
63
|
+
stripAnsiCodes?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Render full dashboard (CLI and MCP compatible)
|
|
67
|
+
*/
|
|
68
|
+
export declare function renderDashboard(data: DashboardData, getProjectTasks: (projectId: string) => Task[], options?: RenderDashboardOptions): string;
|
|
69
|
+
/**
|
|
70
|
+
* Render single project dashboard
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderProjectDashboard(project: Project, tasks: Task[], options?: {
|
|
73
|
+
stripAnsiCodes?: boolean;
|
|
74
|
+
version?: string;
|
|
75
|
+
}): string;
|
|
76
|
+
/**
|
|
77
|
+
* Render global dashboard (all projects)
|
|
78
|
+
*/
|
|
79
|
+
export declare function renderGlobalDashboard(projects: Project[], allTasks: Task[], inboxItems: InboxItem[], getProjectTasks: (projectId: string) => Task[], options?: {
|
|
80
|
+
stripAnsiCodes?: boolean;
|
|
81
|
+
version?: string;
|
|
82
|
+
}): string;
|
|
83
|
+
//# sourceMappingURL=dashboard-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/dashboard-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAmBpE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE;QACf,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,cAAc,CAqC5D;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,iBAAiB,CAsD3E;AAiCD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,EAAE,OAAO,EAAE,GACnB,MAAM,CAwDR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAkCzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,IAAI,CA6BxE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,OAAO,EAAE,EACnB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EAAE,GAC7C,MAAM,CA4DR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,GAAE,MAAW,GAAG,MAAM,CAwC1E;AA+BD,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,EACnB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EAAE,EAC9C,OAAO,GAAE,sBAA2B,GACnC,MAAM,CAsER;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3D,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,IAAI,EAAE,EAChB,UAAU,EAAE,SAAS,EAAE,EACvB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EAAE,EAC9C,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3D,MAAM,CAeR"}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dashboard renderer for CLI and MCP server
|
|
3
|
+
* Provides consistent dashboard layout across all interfaces
|
|
4
|
+
*/
|
|
5
|
+
import { c, box, progressBar, table, icons, sideBySide, truncateStr, pad, banner, stripAnsi, } from "./terminal-ui.js";
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Statistics Calculators
|
|
8
|
+
// =============================================================================
|
|
9
|
+
export function calculateStats(tasks) {
|
|
10
|
+
const stats = {
|
|
11
|
+
total: tasks.length,
|
|
12
|
+
completed: 0,
|
|
13
|
+
inProgress: 0,
|
|
14
|
+
pending: 0,
|
|
15
|
+
blocked: 0,
|
|
16
|
+
cancelled: 0,
|
|
17
|
+
byPriority: { critical: 0, high: 0, medium: 0, low: 0 },
|
|
18
|
+
};
|
|
19
|
+
for (const task of tasks) {
|
|
20
|
+
switch (task.status) {
|
|
21
|
+
case "completed":
|
|
22
|
+
stats.completed++;
|
|
23
|
+
break;
|
|
24
|
+
case "in_progress":
|
|
25
|
+
stats.inProgress++;
|
|
26
|
+
break;
|
|
27
|
+
case "pending":
|
|
28
|
+
stats.pending++;
|
|
29
|
+
break;
|
|
30
|
+
case "blocked":
|
|
31
|
+
stats.blocked++;
|
|
32
|
+
break;
|
|
33
|
+
case "cancelled":
|
|
34
|
+
stats.cancelled++;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
const priority = task.priority ?? "medium";
|
|
38
|
+
if (priority in stats.byPriority) {
|
|
39
|
+
stats.byPriority[priority]++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return stats;
|
|
43
|
+
}
|
|
44
|
+
export function calculateDependencyMetrics(tasks) {
|
|
45
|
+
const completedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
|
|
46
|
+
let readyToWork = 0;
|
|
47
|
+
let blockedByDependencies = 0;
|
|
48
|
+
// Count dependents for each task
|
|
49
|
+
const dependentCounts = new Map();
|
|
50
|
+
for (const task of tasks) {
|
|
51
|
+
if (task.status === "completed" || task.status === "cancelled")
|
|
52
|
+
continue;
|
|
53
|
+
const deps = task.dependencies ?? [];
|
|
54
|
+
if (deps.length === 0) {
|
|
55
|
+
readyToWork++;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const allSatisfied = deps.every((d) => completedIds.has(d.taskId));
|
|
59
|
+
if (allSatisfied) {
|
|
60
|
+
readyToWork++;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
blockedByDependencies++;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Track dependent counts
|
|
67
|
+
for (const dep of deps) {
|
|
68
|
+
dependentCounts.set(dep.taskId, (dependentCounts.get(dep.taskId) ?? 0) + 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Find most depended on task
|
|
72
|
+
let mostDependedOn;
|
|
73
|
+
let maxCount = 0;
|
|
74
|
+
for (const [taskId, count] of dependentCounts) {
|
|
75
|
+
if (count > maxCount) {
|
|
76
|
+
maxCount = count;
|
|
77
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
78
|
+
if (task) {
|
|
79
|
+
mostDependedOn = {
|
|
80
|
+
id: taskId,
|
|
81
|
+
title: task.title,
|
|
82
|
+
dependentCount: count,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { readyToWork, blockedByDependencies, mostDependedOn };
|
|
88
|
+
}
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Formatters
|
|
91
|
+
// =============================================================================
|
|
92
|
+
function formatPriority(priority) {
|
|
93
|
+
const colors = {
|
|
94
|
+
critical: c.red,
|
|
95
|
+
high: c.yellow,
|
|
96
|
+
medium: c.blue,
|
|
97
|
+
low: c.gray,
|
|
98
|
+
};
|
|
99
|
+
return (colors[priority] ?? c.gray)(priority);
|
|
100
|
+
}
|
|
101
|
+
function getTimeAgo(date) {
|
|
102
|
+
const now = new Date();
|
|
103
|
+
const diffMs = now.getTime() - date.getTime();
|
|
104
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
105
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
106
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
107
|
+
if (diffMins < 60)
|
|
108
|
+
return `${diffMins}m ago`;
|
|
109
|
+
if (diffHours < 24)
|
|
110
|
+
return `${diffHours}h ago`;
|
|
111
|
+
if (diffDays < 7)
|
|
112
|
+
return `${diffDays}d ago`;
|
|
113
|
+
return date.toLocaleDateString();
|
|
114
|
+
}
|
|
115
|
+
// =============================================================================
|
|
116
|
+
// Widget Renderers
|
|
117
|
+
// =============================================================================
|
|
118
|
+
/**
|
|
119
|
+
* Render Status widget (progress, counts, priorities, dependencies)
|
|
120
|
+
*/
|
|
121
|
+
export function renderStatusWidget(tasks, _projects) {
|
|
122
|
+
const stats = calculateStats(tasks);
|
|
123
|
+
const depMetrics = calculateDependencyMetrics(tasks);
|
|
124
|
+
const today = getTodayTasks(tasks);
|
|
125
|
+
const overdue = getOverdueTasks(tasks);
|
|
126
|
+
const activeTasks = stats.total - stats.cancelled;
|
|
127
|
+
const percent = activeTasks > 0 ? Math.round((stats.completed / activeTasks) * 100) : 0;
|
|
128
|
+
const lines = [];
|
|
129
|
+
// Progress bar with fraction
|
|
130
|
+
const bar = progressBar(stats.completed, activeTasks, { width: 24 });
|
|
131
|
+
lines.push(`${bar} ${c.bold(`${percent}%`)} ${stats.completed}/${activeTasks} tasks`);
|
|
132
|
+
lines.push("");
|
|
133
|
+
// Status counts
|
|
134
|
+
lines.push(`${c.green("Done")}: ${stats.completed} ` +
|
|
135
|
+
`${c.blue("Progress")}: ${stats.inProgress} ` +
|
|
136
|
+
`${c.yellow("Pending")}: ${stats.pending} ` +
|
|
137
|
+
`${c.red("Blocked")}: ${stats.blocked}`);
|
|
138
|
+
// Schedule info
|
|
139
|
+
const scheduleInfo = [];
|
|
140
|
+
if (overdue.length > 0)
|
|
141
|
+
scheduleInfo.push(c.red(`Overdue: ${overdue.length}`));
|
|
142
|
+
if (today.length > 0)
|
|
143
|
+
scheduleInfo.push(c.yellow(`Today: ${today.length}`));
|
|
144
|
+
if (scheduleInfo.length > 0) {
|
|
145
|
+
lines.push(scheduleInfo.join(" "));
|
|
146
|
+
}
|
|
147
|
+
lines.push("");
|
|
148
|
+
// Priority breakdown
|
|
149
|
+
lines.push(`${c.red("Critical")}: ${stats.byPriority.critical} ` +
|
|
150
|
+
`${c.yellow("High")}: ${stats.byPriority.high} ` +
|
|
151
|
+
`${c.blue("Medium")}: ${stats.byPriority.medium} ` +
|
|
152
|
+
`${c.gray("Low")}: ${stats.byPriority.low}`);
|
|
153
|
+
// Dependencies summary
|
|
154
|
+
lines.push(`${c.green("Ready")}: ${depMetrics.readyToWork} ` +
|
|
155
|
+
`${c.red("Blocked")}: ${depMetrics.blockedByDependencies}` +
|
|
156
|
+
(depMetrics.mostDependedOn
|
|
157
|
+
? ` ${c.dim("Bottleneck:")} ${truncateStr(depMetrics.mostDependedOn.title, 15)}`
|
|
158
|
+
: ""));
|
|
159
|
+
return box(lines.join("\n"), {
|
|
160
|
+
title: "Status",
|
|
161
|
+
borderColor: "cyan",
|
|
162
|
+
padding: 1,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Render Next Actions widget (top ready tasks)
|
|
167
|
+
*/
|
|
168
|
+
export function renderActionsWidget(tasks) {
|
|
169
|
+
const lines = [];
|
|
170
|
+
// Get top 4 ready tasks sorted by priority
|
|
171
|
+
const readyTasks = tasks
|
|
172
|
+
.filter((t) => t.status === "pending" &&
|
|
173
|
+
(!t.dependencies || t.dependencies.length === 0))
|
|
174
|
+
.sort((a, b) => {
|
|
175
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
176
|
+
return ((priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2));
|
|
177
|
+
})
|
|
178
|
+
.slice(0, 4);
|
|
179
|
+
if (readyTasks.length > 0) {
|
|
180
|
+
for (const task of readyTasks) {
|
|
181
|
+
const deps = task.dependencies?.length ?? 0;
|
|
182
|
+
const depsInfo = deps > 0 ? `${deps} deps` : c.green("ready");
|
|
183
|
+
lines.push(`${c.cyan("→")} ${truncateStr(task.title, 24)}`);
|
|
184
|
+
lines.push(` ${formatPriority(task.priority)}, ${depsInfo}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
lines.push(c.dim("No tasks ready"));
|
|
189
|
+
}
|
|
190
|
+
return box(lines.join("\n"), {
|
|
191
|
+
title: "Next Actions",
|
|
192
|
+
borderColor: "green",
|
|
193
|
+
padding: 1,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Render Inbox widget (pending items)
|
|
198
|
+
*/
|
|
199
|
+
export function renderInboxWidget(inboxItems) {
|
|
200
|
+
const pendingItems = inboxItems.filter((item) => item.status === "pending");
|
|
201
|
+
if (pendingItems.length === 0) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const lines = [];
|
|
205
|
+
lines.push(`${c.yellow("Pending")}: ${pendingItems.length} items`);
|
|
206
|
+
lines.push("");
|
|
207
|
+
// Show up to 3 items
|
|
208
|
+
for (const item of pendingItems.slice(0, 3)) {
|
|
209
|
+
const date = new Date(item.capturedAt);
|
|
210
|
+
const ago = getTimeAgo(date);
|
|
211
|
+
const tags = item.tags?.length ? c.dim(` #${item.tags[0]}`) : "";
|
|
212
|
+
lines.push(`${c.yellow("○")} ${truncateStr(item.content, 40)}${tags}`);
|
|
213
|
+
lines.push(` ${c.dim(ago)}`);
|
|
214
|
+
}
|
|
215
|
+
if (pendingItems.length > 3) {
|
|
216
|
+
lines.push(c.gray(`+${pendingItems.length - 3} more`));
|
|
217
|
+
}
|
|
218
|
+
return box(lines.join("\n"), {
|
|
219
|
+
title: "Inbox",
|
|
220
|
+
borderColor: "yellow",
|
|
221
|
+
padding: 1,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Render Projects table
|
|
226
|
+
*/
|
|
227
|
+
export function renderProjectsTable(projects, getProjectTasks) {
|
|
228
|
+
if (projects.length === 0) {
|
|
229
|
+
return c.gray("No projects found.");
|
|
230
|
+
}
|
|
231
|
+
const rows = [];
|
|
232
|
+
for (const project of projects.slice(0, 10)) {
|
|
233
|
+
const tasks = getProjectTasks(project.id);
|
|
234
|
+
const stats = calculateStats(tasks);
|
|
235
|
+
const depMetrics = calculateDependencyMetrics(tasks);
|
|
236
|
+
const activeTasks = stats.total - stats.cancelled;
|
|
237
|
+
const percent = activeTasks > 0
|
|
238
|
+
? Math.round((stats.completed / activeTasks) * 100)
|
|
239
|
+
: 0;
|
|
240
|
+
// Create mini progress bar
|
|
241
|
+
const barWidth = 8;
|
|
242
|
+
const filled = Math.round((percent / 100) * barWidth);
|
|
243
|
+
const empty = barWidth - filled;
|
|
244
|
+
const miniBar = c.green("█".repeat(filled)) + c.gray("░".repeat(empty));
|
|
245
|
+
rows.push({
|
|
246
|
+
name: truncateStr(project.name, 20),
|
|
247
|
+
progress: `${miniBar} ${pad(String(percent) + "%", 4, "right")}`,
|
|
248
|
+
ready: depMetrics.readyToWork,
|
|
249
|
+
blocked: depMetrics.blockedByDependencies,
|
|
250
|
+
total: activeTasks,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
const columns = [
|
|
254
|
+
{ key: "name", header: "Project", width: 22 },
|
|
255
|
+
{ key: "progress", header: "Progress", width: 16 },
|
|
256
|
+
{ key: "total", header: "Tasks", width: 6, align: "right" },
|
|
257
|
+
{
|
|
258
|
+
key: "ready",
|
|
259
|
+
header: "Ready",
|
|
260
|
+
width: 6,
|
|
261
|
+
align: "right",
|
|
262
|
+
format: (v) => c.green(String(v)),
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
key: "blocked",
|
|
266
|
+
header: "Blocked",
|
|
267
|
+
width: 8,
|
|
268
|
+
align: "right",
|
|
269
|
+
format: (v) => (Number(v) > 0 ? c.red(String(v)) : c.gray(String(v))),
|
|
270
|
+
},
|
|
271
|
+
];
|
|
272
|
+
return table(rows, columns);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Render Tasks table for single project view
|
|
276
|
+
*/
|
|
277
|
+
export function renderTasksTable(tasks, limit = 10) {
|
|
278
|
+
const activeTasks = tasks.filter((t) => t.status !== "completed" && t.status !== "cancelled");
|
|
279
|
+
if (activeTasks.length === 0) {
|
|
280
|
+
return c.gray("No active tasks.");
|
|
281
|
+
}
|
|
282
|
+
const displayTasks = activeTasks.slice(0, limit);
|
|
283
|
+
const columns = [
|
|
284
|
+
{ key: "title", header: "Title", width: 40 },
|
|
285
|
+
{
|
|
286
|
+
key: "status",
|
|
287
|
+
header: "Status",
|
|
288
|
+
width: 12,
|
|
289
|
+
format: (v) => {
|
|
290
|
+
const icon = icons[v] ?? icons.pending;
|
|
291
|
+
return `${icon} ${v}`;
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
key: "priority",
|
|
296
|
+
header: "Priority",
|
|
297
|
+
width: 10,
|
|
298
|
+
format: (v) => formatPriority(v),
|
|
299
|
+
},
|
|
300
|
+
];
|
|
301
|
+
let result = table(displayTasks, columns);
|
|
302
|
+
if (activeTasks.length > limit) {
|
|
303
|
+
result += `\n${c.gray(`(+${activeTasks.length - limit} more tasks)`)}`;
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
// =============================================================================
|
|
308
|
+
// Date Helpers
|
|
309
|
+
// =============================================================================
|
|
310
|
+
function getTodayTasks(tasks) {
|
|
311
|
+
const today = new Date().toISOString().split("T")[0];
|
|
312
|
+
return tasks.filter((t) => t.dueDate === today &&
|
|
313
|
+
t.status !== "completed" &&
|
|
314
|
+
t.status !== "cancelled");
|
|
315
|
+
}
|
|
316
|
+
function getOverdueTasks(tasks) {
|
|
317
|
+
const today = new Date().toISOString().split("T")[0];
|
|
318
|
+
return tasks.filter((t) => t.dueDate &&
|
|
319
|
+
t.dueDate < today &&
|
|
320
|
+
t.status !== "completed" &&
|
|
321
|
+
t.status !== "cancelled");
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Render full dashboard (CLI and MCP compatible)
|
|
325
|
+
*/
|
|
326
|
+
export function renderDashboard(data, getProjectTasks, options = {}) {
|
|
327
|
+
const { showBanner = true, showInbox = true, showProjects = true, showTasks = true, stripAnsiCodes = false, } = options;
|
|
328
|
+
const { tasks, projects, inboxItems = [], currentProject, version } = data;
|
|
329
|
+
const lines = [];
|
|
330
|
+
// Banner
|
|
331
|
+
if (showBanner) {
|
|
332
|
+
lines.push("");
|
|
333
|
+
lines.push(banner("TASK MCP"));
|
|
334
|
+
lines.push("");
|
|
335
|
+
}
|
|
336
|
+
// Project info header
|
|
337
|
+
const projectInfo = currentProject
|
|
338
|
+
? `${c.bold("Project:")} ${currentProject.name}`
|
|
339
|
+
: `${c.bold("All Projects")} (${projects.length} projects)`;
|
|
340
|
+
if (version) {
|
|
341
|
+
lines.push(c.dim(`v${version} ${projectInfo}`));
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
lines.push(projectInfo);
|
|
345
|
+
}
|
|
346
|
+
lines.push("");
|
|
347
|
+
// Status + Actions widgets side by side
|
|
348
|
+
const statusWidget = renderStatusWidget(tasks, projects);
|
|
349
|
+
const actionsWidget = renderActionsWidget(tasks);
|
|
350
|
+
lines.push(sideBySide([statusWidget, actionsWidget], 2));
|
|
351
|
+
lines.push("");
|
|
352
|
+
// Inbox widget
|
|
353
|
+
if (showInbox && inboxItems.length > 0) {
|
|
354
|
+
const inboxWidget = renderInboxWidget(inboxItems);
|
|
355
|
+
if (inboxWidget) {
|
|
356
|
+
lines.push(inboxWidget);
|
|
357
|
+
lines.push("");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Projects table (only for all-projects view)
|
|
361
|
+
if (showProjects && !currentProject && projects.length > 1) {
|
|
362
|
+
lines.push(c.bold("Projects"));
|
|
363
|
+
lines.push("");
|
|
364
|
+
lines.push(renderProjectsTable(projects, getProjectTasks));
|
|
365
|
+
lines.push("");
|
|
366
|
+
}
|
|
367
|
+
// Tasks table (for single project view)
|
|
368
|
+
if (showTasks && (currentProject || projects.length === 1)) {
|
|
369
|
+
const activeTasks = tasks.filter((t) => t.status !== "completed" && t.status !== "cancelled");
|
|
370
|
+
if (activeTasks.length > 0) {
|
|
371
|
+
lines.push(c.bold(`Tasks (${activeTasks.length})`));
|
|
372
|
+
lines.push("");
|
|
373
|
+
lines.push(renderTasksTable(tasks));
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
lines.push("");
|
|
377
|
+
const output = lines.join("\n");
|
|
378
|
+
return stripAnsiCodes ? stripAnsi(output) : output;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Render single project dashboard
|
|
382
|
+
*/
|
|
383
|
+
export function renderProjectDashboard(project, tasks, options = {}) {
|
|
384
|
+
const data = {
|
|
385
|
+
tasks,
|
|
386
|
+
projects: [project],
|
|
387
|
+
currentProject: project,
|
|
388
|
+
version: options.version,
|
|
389
|
+
};
|
|
390
|
+
return renderDashboard(data, () => tasks, {
|
|
391
|
+
showBanner: true,
|
|
392
|
+
showInbox: false,
|
|
393
|
+
showProjects: false,
|
|
394
|
+
showTasks: true,
|
|
395
|
+
stripAnsiCodes: options.stripAnsiCodes,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Render global dashboard (all projects)
|
|
400
|
+
*/
|
|
401
|
+
export function renderGlobalDashboard(projects, allTasks, inboxItems, getProjectTasks, options = {}) {
|
|
402
|
+
const data = {
|
|
403
|
+
tasks: allTasks,
|
|
404
|
+
projects,
|
|
405
|
+
inboxItems,
|
|
406
|
+
version: options.version,
|
|
407
|
+
};
|
|
408
|
+
return renderDashboard(data, getProjectTasks, {
|
|
409
|
+
showBanner: true,
|
|
410
|
+
showInbox: true,
|
|
411
|
+
showProjects: true,
|
|
412
|
+
showTasks: projects.length === 1,
|
|
413
|
+
stripAnsiCodes: options.stripAnsiCodes,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=dashboard-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-renderer.js","sourceRoot":"","sources":["../../src/utils/dashboard-renderer.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { now, parseRelativeDate, formatDate, formatDisplayDate, isToday, isPastD
|
|
|
3
3
|
export { parseTaskInput, parseInboxInput, parseInput, type ParseTarget, type ParsedInput } from "./natural-language.js";
|
|
4
4
|
export { MAX_HIERARCHY_DEPTH, getTaskLevel, validateHierarchyDepth, getAncestorIds, getDescendantIds, getChildTasks, getRootTask, buildTaskTree, type TaskTreeNode, } from "./hierarchy.js";
|
|
5
5
|
export { projectTask, projectTasks, projectTasksPaginated, projectProject, projectProjects, projectInboxItem, projectInboxItems, formatResponse, applyPagination, truncate, summarizeList, } from "./projection.js";
|
|
6
|
+
export { calculateStats, calculateDependencyMetrics, renderStatusWidget, renderActionsWidget, renderInboxWidget, renderProjectsTable, renderTasksTable, renderDashboard, renderProjectDashboard, renderGlobalDashboard, type DashboardStats, type DependencyMetrics, type DashboardData, type RenderDashboardOptions, } from "./dashboard-renderer.js";
|
|
6
7
|
export { color, style, styled, c, BOX, box, drawBox, hline, stripAnsi, displayWidth, visibleLength, pad, padEnd, padStart, center, truncateStr, progressBar, type ProgressBarOptions, sideBySide, sideBySideArrays, type BoxOptions, table, renderTable, type TableColumn, statusColors, statusIcons, icons, formatStatus, priorityColors, formatPriority, formatDependencies, banner, } from "./terminal-ui.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAc,EACd,KAAK,kBAAkB,EACvB,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACxH,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAEL,KAAK,EACL,KAAK,EACL,MAAM,EACN,CAAC,EAED,GAAG,EACH,GAAG,EACH,OAAO,EACP,KAAK,EAEL,SAAS,EACT,YAAY,EACZ,aAAa,EACb,GAAG,EACH,MAAM,EACN,QAAQ,EACR,MAAM,EACN,WAAW,EAEX,WAAW,EACX,KAAK,kBAAkB,EAEvB,UAAU,EACV,gBAAgB,EAChB,KAAK,UAAU,EAEf,KAAK,EACL,WAAW,EACX,KAAK,WAAW,EAEhB,YAAY,EACZ,WAAW,EACX,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB,EAElB,MAAM,GACP,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EAEd,cAAc,EACd,KAAK,kBAAkB,EACvB,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACxH,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,sBAAsB,GAC5B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAEL,KAAK,EACL,KAAK,EACL,MAAM,EACN,CAAC,EAED,GAAG,EACH,GAAG,EACH,OAAO,EACP,KAAK,EAEL,SAAS,EACT,YAAY,EACZ,aAAa,EACb,GAAG,EACH,MAAM,EACN,QAAQ,EACR,MAAM,EACN,WAAW,EAEX,WAAW,EACX,KAAK,kBAAkB,EAEvB,UAAU,EACV,gBAAgB,EAChB,KAAK,UAAU,EAEf,KAAK,EACL,WAAW,EACX,KAAK,WAAW,EAEhB,YAAY,EACZ,WAAW,EACX,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB,EAElB,MAAM,GACP,MAAM,kBAAkB,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -6,6 +6,8 @@ export { parseTaskInput, parseInboxInput, parseInput } from "./natural-language.
|
|
|
6
6
|
export { MAX_HIERARCHY_DEPTH, getTaskLevel, validateHierarchyDepth, getAncestorIds, getDescendantIds, getChildTasks, getRootTask, buildTaskTree, } from "./hierarchy.js";
|
|
7
7
|
// Projection utilities (token optimization)
|
|
8
8
|
export { projectTask, projectTasks, projectTasksPaginated, projectProject, projectProjects, projectInboxItem, projectInboxItems, formatResponse, applyPagination, truncate, summarizeList, } from "./projection.js";
|
|
9
|
+
// Dashboard renderer
|
|
10
|
+
export { calculateStats, calculateDependencyMetrics, renderStatusWidget, renderActionsWidget, renderInboxWidget, renderProjectsTable, renderTasksTable, renderDashboard, renderProjectDashboard, renderGlobalDashboard, } from "./dashboard-renderer.js";
|
|
9
11
|
// Terminal UI utilities
|
|
10
12
|
export {
|
|
11
13
|
// Colors and styles
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc;AACd,uDAAuD;AACvD,cAAc,EAEd,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAsC,MAAM,uBAAuB,CAAC;AACxH,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,GAEd,MAAM,gBAAgB,CAAC;AAExB,4CAA4C;AAC5C,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,wBAAwB;AACxB,OAAO;AACL,oBAAoB;AACpB,KAAK,EACL,KAAK,EACL,MAAM,EACN,CAAC;AACD,cAAc;AACd,GAAG,EACH,GAAG,EACH,OAAO,EACP,KAAK;AACL,mBAAmB;AACnB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,GAAG,EACH,MAAM,EACN,QAAQ,EACR,MAAM,EACN,WAAW;AACX,eAAe;AACf,WAAW;AAEX,SAAS;AACT,UAAU,EACV,gBAAgB;AAEhB,SAAS;AACT,KAAK,EACL,WAAW;AAEX,aAAa;AACb,YAAY,EACZ,WAAW,EACX,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB;AAClB,SAAS;AACT,MAAM,GACP,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc;AACd,uDAAuD;AACvD,cAAc,EAEd,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAsC,MAAM,uBAAuB,CAAC;AACxH,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,GAEd,MAAM,gBAAgB,CAAC;AAExB,4CAA4C;AAC5C,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,qBAAqB;AACrB,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,GAKtB,MAAM,yBAAyB,CAAC;AAEjC,wBAAwB;AACxB,OAAO;AACL,oBAAoB;AACpB,KAAK,EACL,KAAK,EACL,MAAM,EACN,CAAC;AACD,cAAc;AACd,GAAG,EACH,GAAG,EACH,OAAO,EACP,KAAK;AACL,mBAAmB;AACnB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,GAAG,EACH,MAAM,EACN,QAAQ,EACR,MAAM,EACN,WAAW;AACX,eAAe;AACf,WAAW;AAEX,SAAS;AACT,UAAU,EACV,gBAAgB;AAEhB,SAAS;AACT,KAAK,EACL,WAAW;AAEX,aAAa;AACb,YAAY,EACZ,WAAW,EACX,KAAK,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB;AAClB,SAAS;AACT,MAAM,GACP,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dashboard renderer for CLI and MCP server
|
|
3
|
+
* Provides consistent dashboard layout across all interfaces
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Task, Project, InboxItem } from "../schemas/index.js";
|
|
7
|
+
import {
|
|
8
|
+
c,
|
|
9
|
+
box,
|
|
10
|
+
progressBar,
|
|
11
|
+
table,
|
|
12
|
+
icons,
|
|
13
|
+
sideBySide,
|
|
14
|
+
truncateStr,
|
|
15
|
+
pad,
|
|
16
|
+
banner,
|
|
17
|
+
stripAnsi,
|
|
18
|
+
type TableColumn,
|
|
19
|
+
} from "./terminal-ui.js";
|
|
20
|
+
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Types
|
|
23
|
+
// =============================================================================
|
|
24
|
+
|
|
25
|
+
export interface DashboardStats {
|
|
26
|
+
total: number;
|
|
27
|
+
completed: number;
|
|
28
|
+
inProgress: number;
|
|
29
|
+
pending: number;
|
|
30
|
+
blocked: number;
|
|
31
|
+
cancelled: number;
|
|
32
|
+
byPriority: {
|
|
33
|
+
critical: number;
|
|
34
|
+
high: number;
|
|
35
|
+
medium: number;
|
|
36
|
+
low: number;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DependencyMetrics {
|
|
41
|
+
readyToWork: number;
|
|
42
|
+
blockedByDependencies: number;
|
|
43
|
+
mostDependedOn?: {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
dependentCount: number;
|
|
47
|
+
} | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface DashboardData {
|
|
51
|
+
tasks: Task[];
|
|
52
|
+
projects: Project[];
|
|
53
|
+
inboxItems?: InboxItem[] | undefined;
|
|
54
|
+
currentProject?: Project | undefined;
|
|
55
|
+
version?: string | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Statistics Calculators
|
|
60
|
+
// =============================================================================
|
|
61
|
+
|
|
62
|
+
export function calculateStats(tasks: Task[]): DashboardStats {
|
|
63
|
+
const stats: DashboardStats = {
|
|
64
|
+
total: tasks.length,
|
|
65
|
+
completed: 0,
|
|
66
|
+
inProgress: 0,
|
|
67
|
+
pending: 0,
|
|
68
|
+
blocked: 0,
|
|
69
|
+
cancelled: 0,
|
|
70
|
+
byPriority: { critical: 0, high: 0, medium: 0, low: 0 },
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
for (const task of tasks) {
|
|
74
|
+
switch (task.status) {
|
|
75
|
+
case "completed":
|
|
76
|
+
stats.completed++;
|
|
77
|
+
break;
|
|
78
|
+
case "in_progress":
|
|
79
|
+
stats.inProgress++;
|
|
80
|
+
break;
|
|
81
|
+
case "pending":
|
|
82
|
+
stats.pending++;
|
|
83
|
+
break;
|
|
84
|
+
case "blocked":
|
|
85
|
+
stats.blocked++;
|
|
86
|
+
break;
|
|
87
|
+
case "cancelled":
|
|
88
|
+
stats.cancelled++;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const priority = task.priority ?? "medium";
|
|
93
|
+
if (priority in stats.byPriority) {
|
|
94
|
+
stats.byPriority[priority as keyof typeof stats.byPriority]++;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return stats;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function calculateDependencyMetrics(tasks: Task[]): DependencyMetrics {
|
|
102
|
+
const completedIds = new Set(
|
|
103
|
+
tasks.filter((t) => t.status === "completed").map((t) => t.id)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
let readyToWork = 0;
|
|
107
|
+
let blockedByDependencies = 0;
|
|
108
|
+
|
|
109
|
+
// Count dependents for each task
|
|
110
|
+
const dependentCounts = new Map<string, number>();
|
|
111
|
+
|
|
112
|
+
for (const task of tasks) {
|
|
113
|
+
if (task.status === "completed" || task.status === "cancelled") continue;
|
|
114
|
+
|
|
115
|
+
const deps = task.dependencies ?? [];
|
|
116
|
+
if (deps.length === 0) {
|
|
117
|
+
readyToWork++;
|
|
118
|
+
} else {
|
|
119
|
+
const allSatisfied = deps.every((d) => completedIds.has(d.taskId));
|
|
120
|
+
if (allSatisfied) {
|
|
121
|
+
readyToWork++;
|
|
122
|
+
} else {
|
|
123
|
+
blockedByDependencies++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Track dependent counts
|
|
128
|
+
for (const dep of deps) {
|
|
129
|
+
dependentCounts.set(
|
|
130
|
+
dep.taskId,
|
|
131
|
+
(dependentCounts.get(dep.taskId) ?? 0) + 1
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Find most depended on task
|
|
137
|
+
let mostDependedOn: DependencyMetrics["mostDependedOn"];
|
|
138
|
+
let maxCount = 0;
|
|
139
|
+
|
|
140
|
+
for (const [taskId, count] of dependentCounts) {
|
|
141
|
+
if (count > maxCount) {
|
|
142
|
+
maxCount = count;
|
|
143
|
+
const task = tasks.find((t) => t.id === taskId);
|
|
144
|
+
if (task) {
|
|
145
|
+
mostDependedOn = {
|
|
146
|
+
id: taskId,
|
|
147
|
+
title: task.title,
|
|
148
|
+
dependentCount: count,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return { readyToWork, blockedByDependencies, mostDependedOn };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Formatters
|
|
159
|
+
// =============================================================================
|
|
160
|
+
|
|
161
|
+
function formatPriority(priority: Task["priority"]): string {
|
|
162
|
+
const colors: Record<string, (s: string) => string> = {
|
|
163
|
+
critical: c.red,
|
|
164
|
+
high: c.yellow,
|
|
165
|
+
medium: c.blue,
|
|
166
|
+
low: c.gray,
|
|
167
|
+
};
|
|
168
|
+
return (colors[priority] ?? c.gray)(priority);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getTimeAgo(date: Date): string {
|
|
172
|
+
const now = new Date();
|
|
173
|
+
const diffMs = now.getTime() - date.getTime();
|
|
174
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
175
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
176
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
177
|
+
|
|
178
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
179
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
180
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
181
|
+
return date.toLocaleDateString();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// Widget Renderers
|
|
186
|
+
// =============================================================================
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Render Status widget (progress, counts, priorities, dependencies)
|
|
190
|
+
*/
|
|
191
|
+
export function renderStatusWidget(
|
|
192
|
+
tasks: Task[],
|
|
193
|
+
_projects: Project[]
|
|
194
|
+
): string {
|
|
195
|
+
const stats = calculateStats(tasks);
|
|
196
|
+
const depMetrics = calculateDependencyMetrics(tasks);
|
|
197
|
+
const today = getTodayTasks(tasks);
|
|
198
|
+
const overdue = getOverdueTasks(tasks);
|
|
199
|
+
const activeTasks = stats.total - stats.cancelled;
|
|
200
|
+
const percent =
|
|
201
|
+
activeTasks > 0 ? Math.round((stats.completed / activeTasks) * 100) : 0;
|
|
202
|
+
|
|
203
|
+
const lines: string[] = [];
|
|
204
|
+
|
|
205
|
+
// Progress bar with fraction
|
|
206
|
+
const bar = progressBar(stats.completed, activeTasks, { width: 24 });
|
|
207
|
+
lines.push(`${bar} ${c.bold(`${percent}%`)} ${stats.completed}/${activeTasks} tasks`);
|
|
208
|
+
lines.push("");
|
|
209
|
+
|
|
210
|
+
// Status counts
|
|
211
|
+
lines.push(
|
|
212
|
+
`${c.green("Done")}: ${stats.completed} ` +
|
|
213
|
+
`${c.blue("Progress")}: ${stats.inProgress} ` +
|
|
214
|
+
`${c.yellow("Pending")}: ${stats.pending} ` +
|
|
215
|
+
`${c.red("Blocked")}: ${stats.blocked}`
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Schedule info
|
|
219
|
+
const scheduleInfo = [];
|
|
220
|
+
if (overdue.length > 0) scheduleInfo.push(c.red(`Overdue: ${overdue.length}`));
|
|
221
|
+
if (today.length > 0) scheduleInfo.push(c.yellow(`Today: ${today.length}`));
|
|
222
|
+
if (scheduleInfo.length > 0) {
|
|
223
|
+
lines.push(scheduleInfo.join(" "));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
lines.push("");
|
|
227
|
+
|
|
228
|
+
// Priority breakdown
|
|
229
|
+
lines.push(
|
|
230
|
+
`${c.red("Critical")}: ${stats.byPriority.critical} ` +
|
|
231
|
+
`${c.yellow("High")}: ${stats.byPriority.high} ` +
|
|
232
|
+
`${c.blue("Medium")}: ${stats.byPriority.medium} ` +
|
|
233
|
+
`${c.gray("Low")}: ${stats.byPriority.low}`
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Dependencies summary
|
|
237
|
+
lines.push(
|
|
238
|
+
`${c.green("Ready")}: ${depMetrics.readyToWork} ` +
|
|
239
|
+
`${c.red("Blocked")}: ${depMetrics.blockedByDependencies}` +
|
|
240
|
+
(depMetrics.mostDependedOn
|
|
241
|
+
? ` ${c.dim("Bottleneck:")} ${truncateStr(depMetrics.mostDependedOn.title, 15)}`
|
|
242
|
+
: "")
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
return box(lines.join("\n"), {
|
|
246
|
+
title: "Status",
|
|
247
|
+
borderColor: "cyan",
|
|
248
|
+
padding: 1,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Render Next Actions widget (top ready tasks)
|
|
254
|
+
*/
|
|
255
|
+
export function renderActionsWidget(tasks: Task[]): string {
|
|
256
|
+
const lines: string[] = [];
|
|
257
|
+
|
|
258
|
+
// Get top 4 ready tasks sorted by priority
|
|
259
|
+
const readyTasks = tasks
|
|
260
|
+
.filter(
|
|
261
|
+
(t) =>
|
|
262
|
+
t.status === "pending" &&
|
|
263
|
+
(!t.dependencies || t.dependencies.length === 0)
|
|
264
|
+
)
|
|
265
|
+
.sort((a, b) => {
|
|
266
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
267
|
+
return (
|
|
268
|
+
(priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2)
|
|
269
|
+
);
|
|
270
|
+
})
|
|
271
|
+
.slice(0, 4);
|
|
272
|
+
|
|
273
|
+
if (readyTasks.length > 0) {
|
|
274
|
+
for (const task of readyTasks) {
|
|
275
|
+
const deps = task.dependencies?.length ?? 0;
|
|
276
|
+
const depsInfo = deps > 0 ? `${deps} deps` : c.green("ready");
|
|
277
|
+
lines.push(`${c.cyan("→")} ${truncateStr(task.title, 24)}`);
|
|
278
|
+
lines.push(` ${formatPriority(task.priority)}, ${depsInfo}`);
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
lines.push(c.dim("No tasks ready"));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return box(lines.join("\n"), {
|
|
285
|
+
title: "Next Actions",
|
|
286
|
+
borderColor: "green",
|
|
287
|
+
padding: 1,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Render Inbox widget (pending items)
|
|
293
|
+
*/
|
|
294
|
+
export function renderInboxWidget(inboxItems: InboxItem[]): string | null {
|
|
295
|
+
const pendingItems = inboxItems.filter((item) => item.status === "pending");
|
|
296
|
+
|
|
297
|
+
if (pendingItems.length === 0) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const lines: string[] = [];
|
|
302
|
+
lines.push(`${c.yellow("Pending")}: ${pendingItems.length} items`);
|
|
303
|
+
lines.push("");
|
|
304
|
+
|
|
305
|
+
// Show up to 3 items
|
|
306
|
+
for (const item of pendingItems.slice(0, 3)) {
|
|
307
|
+
const date = new Date(item.capturedAt);
|
|
308
|
+
const ago = getTimeAgo(date);
|
|
309
|
+
const tags = item.tags?.length ? c.dim(` #${item.tags[0]}`) : "";
|
|
310
|
+
lines.push(`${c.yellow("○")} ${truncateStr(item.content, 40)}${tags}`);
|
|
311
|
+
lines.push(` ${c.dim(ago)}`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (pendingItems.length > 3) {
|
|
315
|
+
lines.push(c.gray(`+${pendingItems.length - 3} more`));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return box(lines.join("\n"), {
|
|
319
|
+
title: "Inbox",
|
|
320
|
+
borderColor: "yellow",
|
|
321
|
+
padding: 1,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Render Projects table
|
|
327
|
+
*/
|
|
328
|
+
export function renderProjectsTable(
|
|
329
|
+
projects: Project[],
|
|
330
|
+
getProjectTasks: (projectId: string) => Task[]
|
|
331
|
+
): string {
|
|
332
|
+
if (projects.length === 0) {
|
|
333
|
+
return c.gray("No projects found.");
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const rows: {
|
|
337
|
+
name: string;
|
|
338
|
+
progress: string;
|
|
339
|
+
ready: number;
|
|
340
|
+
blocked: number;
|
|
341
|
+
total: number;
|
|
342
|
+
}[] = [];
|
|
343
|
+
|
|
344
|
+
for (const project of projects.slice(0, 10)) {
|
|
345
|
+
const tasks = getProjectTasks(project.id);
|
|
346
|
+
const stats = calculateStats(tasks);
|
|
347
|
+
const depMetrics = calculateDependencyMetrics(tasks);
|
|
348
|
+
const activeTasks = stats.total - stats.cancelled;
|
|
349
|
+
const percent =
|
|
350
|
+
activeTasks > 0
|
|
351
|
+
? Math.round((stats.completed / activeTasks) * 100)
|
|
352
|
+
: 0;
|
|
353
|
+
|
|
354
|
+
// Create mini progress bar
|
|
355
|
+
const barWidth = 8;
|
|
356
|
+
const filled = Math.round((percent / 100) * barWidth);
|
|
357
|
+
const empty = barWidth - filled;
|
|
358
|
+
const miniBar =
|
|
359
|
+
c.green("█".repeat(filled)) + c.gray("░".repeat(empty));
|
|
360
|
+
|
|
361
|
+
rows.push({
|
|
362
|
+
name: truncateStr(project.name, 20),
|
|
363
|
+
progress: `${miniBar} ${pad(String(percent) + "%", 4, "right")}`,
|
|
364
|
+
ready: depMetrics.readyToWork,
|
|
365
|
+
blocked: depMetrics.blockedByDependencies,
|
|
366
|
+
total: activeTasks,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const columns: TableColumn[] = [
|
|
371
|
+
{ key: "name", header: "Project", width: 22 },
|
|
372
|
+
{ key: "progress", header: "Progress", width: 16 },
|
|
373
|
+
{ key: "total", header: "Tasks", width: 6, align: "right" },
|
|
374
|
+
{
|
|
375
|
+
key: "ready",
|
|
376
|
+
header: "Ready",
|
|
377
|
+
width: 6,
|
|
378
|
+
align: "right",
|
|
379
|
+
format: (v) => c.green(String(v)),
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
key: "blocked",
|
|
383
|
+
header: "Blocked",
|
|
384
|
+
width: 8,
|
|
385
|
+
align: "right",
|
|
386
|
+
format: (v) => (Number(v) > 0 ? c.red(String(v)) : c.gray(String(v))),
|
|
387
|
+
},
|
|
388
|
+
];
|
|
389
|
+
|
|
390
|
+
return table(rows as unknown as Record<string, unknown>[], columns);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Render Tasks table for single project view
|
|
395
|
+
*/
|
|
396
|
+
export function renderTasksTable(tasks: Task[], limit: number = 10): string {
|
|
397
|
+
const activeTasks = tasks.filter(
|
|
398
|
+
(t) => t.status !== "completed" && t.status !== "cancelled"
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (activeTasks.length === 0) {
|
|
402
|
+
return c.gray("No active tasks.");
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const displayTasks = activeTasks.slice(0, limit);
|
|
406
|
+
|
|
407
|
+
const columns: TableColumn[] = [
|
|
408
|
+
{ key: "title", header: "Title", width: 40 },
|
|
409
|
+
{
|
|
410
|
+
key: "status",
|
|
411
|
+
header: "Status",
|
|
412
|
+
width: 12,
|
|
413
|
+
format: (v) => {
|
|
414
|
+
const icon = icons[v as Task["status"]] ?? icons.pending;
|
|
415
|
+
return `${icon} ${v}`;
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
key: "priority",
|
|
420
|
+
header: "Priority",
|
|
421
|
+
width: 10,
|
|
422
|
+
format: (v) => formatPriority(v as Task["priority"]),
|
|
423
|
+
},
|
|
424
|
+
];
|
|
425
|
+
|
|
426
|
+
let result = table(
|
|
427
|
+
displayTasks as unknown as Record<string, unknown>[],
|
|
428
|
+
columns
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
if (activeTasks.length > limit) {
|
|
432
|
+
result += `\n${c.gray(`(+${activeTasks.length - limit} more tasks)`)}`;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// =============================================================================
|
|
439
|
+
// Date Helpers
|
|
440
|
+
// =============================================================================
|
|
441
|
+
|
|
442
|
+
function getTodayTasks(tasks: Task[]): Task[] {
|
|
443
|
+
const today = new Date().toISOString().split("T")[0];
|
|
444
|
+
return tasks.filter(
|
|
445
|
+
(t) =>
|
|
446
|
+
t.dueDate === today &&
|
|
447
|
+
t.status !== "completed" &&
|
|
448
|
+
t.status !== "cancelled"
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function getOverdueTasks(tasks: Task[]): Task[] {
|
|
453
|
+
const today = new Date().toISOString().split("T")[0] ?? "";
|
|
454
|
+
return tasks.filter(
|
|
455
|
+
(t) =>
|
|
456
|
+
t.dueDate &&
|
|
457
|
+
t.dueDate < today &&
|
|
458
|
+
t.status !== "completed" &&
|
|
459
|
+
t.status !== "cancelled"
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// =============================================================================
|
|
464
|
+
// Full Dashboard Renderer
|
|
465
|
+
// =============================================================================
|
|
466
|
+
|
|
467
|
+
export interface RenderDashboardOptions {
|
|
468
|
+
showBanner?: boolean | undefined;
|
|
469
|
+
showInbox?: boolean | undefined;
|
|
470
|
+
showProjects?: boolean | undefined;
|
|
471
|
+
showTasks?: boolean | undefined;
|
|
472
|
+
stripAnsiCodes?: boolean | undefined;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Render full dashboard (CLI and MCP compatible)
|
|
477
|
+
*/
|
|
478
|
+
export function renderDashboard(
|
|
479
|
+
data: DashboardData,
|
|
480
|
+
getProjectTasks: (projectId: string) => Task[],
|
|
481
|
+
options: RenderDashboardOptions = {}
|
|
482
|
+
): string {
|
|
483
|
+
const {
|
|
484
|
+
showBanner = true,
|
|
485
|
+
showInbox = true,
|
|
486
|
+
showProjects = true,
|
|
487
|
+
showTasks = true,
|
|
488
|
+
stripAnsiCodes = false,
|
|
489
|
+
} = options;
|
|
490
|
+
|
|
491
|
+
const { tasks, projects, inboxItems = [], currentProject, version } = data;
|
|
492
|
+
const lines: string[] = [];
|
|
493
|
+
|
|
494
|
+
// Banner
|
|
495
|
+
if (showBanner) {
|
|
496
|
+
lines.push("");
|
|
497
|
+
lines.push(banner("TASK MCP"));
|
|
498
|
+
lines.push("");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Project info header
|
|
502
|
+
const projectInfo = currentProject
|
|
503
|
+
? `${c.bold("Project:")} ${currentProject.name}`
|
|
504
|
+
: `${c.bold("All Projects")} (${projects.length} projects)`;
|
|
505
|
+
|
|
506
|
+
if (version) {
|
|
507
|
+
lines.push(c.dim(`v${version} ${projectInfo}`));
|
|
508
|
+
} else {
|
|
509
|
+
lines.push(projectInfo);
|
|
510
|
+
}
|
|
511
|
+
lines.push("");
|
|
512
|
+
|
|
513
|
+
// Status + Actions widgets side by side
|
|
514
|
+
const statusWidget = renderStatusWidget(tasks, projects);
|
|
515
|
+
const actionsWidget = renderActionsWidget(tasks);
|
|
516
|
+
lines.push(sideBySide([statusWidget, actionsWidget], 2));
|
|
517
|
+
lines.push("");
|
|
518
|
+
|
|
519
|
+
// Inbox widget
|
|
520
|
+
if (showInbox && inboxItems.length > 0) {
|
|
521
|
+
const inboxWidget = renderInboxWidget(inboxItems);
|
|
522
|
+
if (inboxWidget) {
|
|
523
|
+
lines.push(inboxWidget);
|
|
524
|
+
lines.push("");
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Projects table (only for all-projects view)
|
|
529
|
+
if (showProjects && !currentProject && projects.length > 1) {
|
|
530
|
+
lines.push(c.bold("Projects"));
|
|
531
|
+
lines.push("");
|
|
532
|
+
lines.push(renderProjectsTable(projects, getProjectTasks));
|
|
533
|
+
lines.push("");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Tasks table (for single project view)
|
|
537
|
+
if (showTasks && (currentProject || projects.length === 1)) {
|
|
538
|
+
const activeTasks = tasks.filter(
|
|
539
|
+
(t) => t.status !== "completed" && t.status !== "cancelled"
|
|
540
|
+
);
|
|
541
|
+
if (activeTasks.length > 0) {
|
|
542
|
+
lines.push(c.bold(`Tasks (${activeTasks.length})`));
|
|
543
|
+
lines.push("");
|
|
544
|
+
lines.push(renderTasksTable(tasks));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
lines.push("");
|
|
549
|
+
|
|
550
|
+
const output = lines.join("\n");
|
|
551
|
+
return stripAnsiCodes ? stripAnsi(output) : output;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Render single project dashboard
|
|
556
|
+
*/
|
|
557
|
+
export function renderProjectDashboard(
|
|
558
|
+
project: Project,
|
|
559
|
+
tasks: Task[],
|
|
560
|
+
options: { stripAnsiCodes?: boolean; version?: string } = {}
|
|
561
|
+
): string {
|
|
562
|
+
const data: DashboardData = {
|
|
563
|
+
tasks,
|
|
564
|
+
projects: [project],
|
|
565
|
+
currentProject: project,
|
|
566
|
+
version: options.version,
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
return renderDashboard(
|
|
570
|
+
data,
|
|
571
|
+
() => tasks,
|
|
572
|
+
{
|
|
573
|
+
showBanner: true,
|
|
574
|
+
showInbox: false,
|
|
575
|
+
showProjects: false,
|
|
576
|
+
showTasks: true,
|
|
577
|
+
stripAnsiCodes: options.stripAnsiCodes,
|
|
578
|
+
}
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Render global dashboard (all projects)
|
|
584
|
+
*/
|
|
585
|
+
export function renderGlobalDashboard(
|
|
586
|
+
projects: Project[],
|
|
587
|
+
allTasks: Task[],
|
|
588
|
+
inboxItems: InboxItem[],
|
|
589
|
+
getProjectTasks: (projectId: string) => Task[],
|
|
590
|
+
options: { stripAnsiCodes?: boolean; version?: string } = {}
|
|
591
|
+
): string {
|
|
592
|
+
const data: DashboardData = {
|
|
593
|
+
tasks: allTasks,
|
|
594
|
+
projects,
|
|
595
|
+
inboxItems,
|
|
596
|
+
version: options.version,
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
return renderDashboard(data, getProjectTasks, {
|
|
600
|
+
showBanner: true,
|
|
601
|
+
showInbox: true,
|
|
602
|
+
showProjects: true,
|
|
603
|
+
showTasks: projects.length === 1,
|
|
604
|
+
stripAnsiCodes: options.stripAnsiCodes,
|
|
605
|
+
});
|
|
606
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -46,6 +46,24 @@ export {
|
|
|
46
46
|
summarizeList,
|
|
47
47
|
} from "./projection.js";
|
|
48
48
|
|
|
49
|
+
// Dashboard renderer
|
|
50
|
+
export {
|
|
51
|
+
calculateStats,
|
|
52
|
+
calculateDependencyMetrics,
|
|
53
|
+
renderStatusWidget,
|
|
54
|
+
renderActionsWidget,
|
|
55
|
+
renderInboxWidget,
|
|
56
|
+
renderProjectsTable,
|
|
57
|
+
renderTasksTable,
|
|
58
|
+
renderDashboard,
|
|
59
|
+
renderProjectDashboard,
|
|
60
|
+
renderGlobalDashboard,
|
|
61
|
+
type DashboardStats,
|
|
62
|
+
type DependencyMetrics,
|
|
63
|
+
type DashboardData,
|
|
64
|
+
type RenderDashboardOptions,
|
|
65
|
+
} from "./dashboard-renderer.js";
|
|
66
|
+
|
|
49
67
|
// Terminal UI utilities
|
|
50
68
|
export {
|
|
51
69
|
// Colors and styles
|