@task-mcp/cli 1.0.21 → 1.0.22

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/src/storage.ts DELETED
@@ -1,221 +0,0 @@
1
- /**
2
- * CLI Storage utilities
3
- * Wrapper functions for store access and pure functions for task statistics
4
- */
5
-
6
- import type { Task, InboxItem } from "@task-mcp/shared";
7
- import type { WorkspaceInfo } from "@task-mcp/shared";
8
- import {
9
- TaskStore,
10
- InboxStore,
11
- StateStore,
12
- } from "@task-mcp/mcp-server/storage";
13
-
14
- // Re-export types from shared for consumers of this module
15
- export type { Task, InboxItem, WorkspaceInfo };
16
-
17
- // Initialize stores
18
- const taskStore = new TaskStore();
19
- const inboxStore = new InboxStore();
20
- const stateStore = new StateStore();
21
-
22
- // =============================================================================
23
- // Store Wrapper Functions
24
- // =============================================================================
25
-
26
- /**
27
- * Get current workspace name
28
- */
29
- export function getCurrentWorkspace(): string {
30
- return taskStore.currentWorkspace;
31
- }
32
-
33
- /**
34
- * List all workspaces
35
- */
36
- export async function listWorkspaces(): Promise<WorkspaceInfo[]> {
37
- const workspaceNames = await taskStore.listWorkspaces();
38
- const workspaces: WorkspaceInfo[] = [];
39
-
40
- for (const name of workspaceNames) {
41
- const tasks = await taskStore.list({ workspaces: [name] });
42
- workspaces.push({
43
- name,
44
- taskCount: tasks.length,
45
- completedCount: tasks.filter(t => t.status === "completed").length,
46
- });
47
- }
48
-
49
- return workspaces;
50
- }
51
-
52
- /**
53
- * List tasks for current workspace
54
- */
55
- export async function listTasks(): Promise<Task[]> {
56
- return taskStore.list();
57
- }
58
-
59
- /**
60
- * List all tasks across all workspaces
61
- */
62
- export async function listAllTasks(): Promise<Task[]> {
63
- return taskStore.listAll();
64
- }
65
-
66
- /**
67
- * List inbox items by status
68
- */
69
- export async function listInboxItems(
70
- status?: "pending" | "promoted" | "discarded"
71
- ): Promise<InboxItem[]> {
72
- return inboxStore.list({ status });
73
- }
74
-
75
- /**
76
- * Get the active tag (git branch context)
77
- */
78
- export async function getActiveTag(): Promise<string> {
79
- return stateStore.getActiveTag();
80
- }
81
-
82
- /**
83
- * Get workspace statistics
84
- */
85
- export interface WorkspaceStats {
86
- total: number;
87
- completed: number;
88
- inProgress: number;
89
- pending: number;
90
- blocked: number;
91
- cancelled: number;
92
- byPriority: Record<string, number>;
93
- completionPercent: number;
94
- }
95
-
96
- export function calculateStats(tasks: Task[]): WorkspaceStats {
97
- const stats: WorkspaceStats = {
98
- total: tasks.length,
99
- completed: 0,
100
- inProgress: 0,
101
- pending: 0,
102
- blocked: 0,
103
- cancelled: 0,
104
- byPriority: { critical: 0, high: 0, medium: 0, low: 0 },
105
- completionPercent: 0,
106
- };
107
-
108
- for (const task of tasks) {
109
- switch (task.status) {
110
- case "completed":
111
- stats.completed++;
112
- break;
113
- case "in_progress":
114
- stats.inProgress++;
115
- break;
116
- case "pending":
117
- stats.pending++;
118
- break;
119
- case "blocked":
120
- stats.blocked++;
121
- break;
122
- case "cancelled":
123
- stats.cancelled++;
124
- break;
125
- }
126
- stats.byPriority[task.priority]++;
127
- }
128
-
129
- const nonCancelled = stats.total - stats.cancelled;
130
- stats.completionPercent = nonCancelled > 0
131
- ? Math.round((stats.completed / nonCancelled) * 100)
132
- : 0;
133
-
134
- return stats;
135
- }
136
-
137
- /**
138
- * Get dependency metrics
139
- */
140
- export interface DependencyMetrics {
141
- noDependencies: number;
142
- readyToWork: number;
143
- blockedByDependencies: number;
144
- mostDependedOn: { id: string; title: string; count: number } | null;
145
- avgDependencies: number;
146
- }
147
-
148
- export function calculateDependencyMetrics(tasks: Task[]): DependencyMetrics {
149
- const activeTasks = tasks.filter(t => t.status !== "completed" && t.status !== "cancelled");
150
- const completedIds = new Set(tasks.filter(t => t.status === "completed").map(t => t.id));
151
-
152
- // Count how many tasks depend on each task
153
- const dependentCounts: Record<string, number> = {};
154
- for (const task of activeTasks) {
155
- for (const dep of task.dependencies ?? []) {
156
- dependentCounts[dep.taskId] = (dependentCounts[dep.taskId] ?? 0) + 1;
157
- }
158
- }
159
-
160
- let mostDependedOn: DependencyMetrics["mostDependedOn"] = null;
161
- let maxCount = 0;
162
- for (const [id, count] of Object.entries(dependentCounts)) {
163
- if (count > maxCount) {
164
- maxCount = count;
165
- const task = tasks.find(t => t.id === id);
166
- if (task) {
167
- mostDependedOn = { id, title: task.title, count };
168
- }
169
- }
170
- }
171
-
172
- const noDependencies = activeTasks.filter(t => (t.dependencies?.length ?? 0) === 0).length;
173
-
174
- // Ready to work: no uncompleted dependencies
175
- const readyToWork = activeTasks.filter(t => {
176
- const deps = t.dependencies ?? [];
177
- if (deps.length === 0) return true;
178
- return deps.every(d => completedIds.has(d.taskId));
179
- }).length;
180
-
181
- const blockedByDependencies = activeTasks.length - readyToWork;
182
-
183
- const totalDeps = activeTasks.reduce((sum, t) => sum + (t.dependencies?.length ?? 0), 0);
184
- const avgDependencies = activeTasks.length > 0 ? totalDeps / activeTasks.length : 0;
185
-
186
- return {
187
- noDependencies,
188
- readyToWork,
189
- blockedByDependencies,
190
- mostDependedOn,
191
- avgDependencies: Math.round(avgDependencies * 10) / 10,
192
- };
193
- }
194
-
195
- /**
196
- * Get next task suggestion
197
- */
198
- export function suggestNextTask(tasks: Task[]): Task | null {
199
- const completedIds = new Set(tasks.filter(t => t.status === "completed").map(t => t.id));
200
-
201
- // Filter to actionable tasks
202
- const actionable = tasks.filter(t => {
203
- if (t.status !== "pending" && t.status !== "in_progress") return false;
204
-
205
- // Check if all dependencies are completed
206
- const deps = t.dependencies ?? [];
207
- return deps.every(d => completedIds.has(d.taskId));
208
- });
209
-
210
- if (actionable.length === 0) return null;
211
-
212
- // Sort by priority then by creation date
213
- const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
214
- actionable.sort((a, b) => {
215
- const pDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
216
- if (pDiff !== 0) return pDiff;
217
- return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
218
- });
219
-
220
- return actionable[0] ?? null;
221
- }