@task-mcp/shared 1.0.13 → 1.0.14
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/algorithms/critical-path.d.ts.map +1 -1
- package/dist/algorithms/critical-path.js +2 -14
- package/dist/algorithms/critical-path.js.map +1 -1
- package/dist/algorithms/dependency-integrity.d.ts +8 -0
- package/dist/algorithms/dependency-integrity.d.ts.map +1 -1
- package/dist/algorithms/dependency-integrity.js +42 -24
- package/dist/algorithms/dependency-integrity.js.map +1 -1
- package/dist/algorithms/dependency-integrity.test.d.ts +2 -0
- package/dist/algorithms/dependency-integrity.test.d.ts.map +1 -0
- package/dist/algorithms/dependency-integrity.test.js +309 -0
- package/dist/algorithms/dependency-integrity.test.js.map +1 -0
- package/dist/algorithms/tech-analysis.d.ts +5 -5
- package/dist/algorithms/tech-analysis.d.ts.map +1 -1
- package/dist/algorithms/tech-analysis.js +65 -17
- package/dist/algorithms/tech-analysis.js.map +1 -1
- package/dist/algorithms/topological-sort.d.ts.map +1 -1
- package/dist/algorithms/topological-sort.js +1 -56
- package/dist/algorithms/topological-sort.js.map +1 -1
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/project.d.ts +6 -6
- package/dist/schemas/state.d.ts +17 -0
- package/dist/schemas/state.d.ts.map +1 -0
- package/dist/schemas/state.js +17 -0
- package/dist/schemas/state.js.map +1 -0
- package/dist/schemas/task.d.ts +13 -4
- package/dist/schemas/task.d.ts.map +1 -1
- package/dist/schemas/task.js +3 -0
- package/dist/schemas/task.js.map +1 -1
- package/dist/schemas/view.d.ts +4 -4
- package/dist/utils/dashboard-renderer.d.ts +3 -0
- package/dist/utils/dashboard-renderer.d.ts.map +1 -1
- package/dist/utils/dashboard-renderer.js +12 -13
- package/dist/utils/dashboard-renderer.js.map +1 -1
- package/dist/utils/dashboard-renderer.test.d.ts +2 -0
- package/dist/utils/dashboard-renderer.test.d.ts.map +1 -0
- package/dist/utils/dashboard-renderer.test.js +777 -0
- package/dist/utils/dashboard-renderer.test.js.map +1 -0
- package/dist/utils/date.d.ts +49 -0
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +174 -19
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/date.test.js +139 -1
- package/dist/utils/date.test.js.map +1 -1
- package/dist/utils/hierarchy.d.ts +1 -1
- package/dist/utils/hierarchy.d.ts.map +1 -1
- package/dist/utils/hierarchy.js +15 -5
- package/dist/utils/hierarchy.js.map +1 -1
- package/dist/utils/hierarchy.test.d.ts +2 -0
- package/dist/utils/hierarchy.test.d.ts.map +1 -0
- package/dist/utils/hierarchy.test.js +351 -0
- package/dist/utils/hierarchy.test.js.map +1 -0
- package/dist/utils/id.js +1 -1
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/index.d.ts +3 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/natural-language.d.ts.map +1 -1
- package/dist/utils/natural-language.js +7 -0
- package/dist/utils/natural-language.js.map +1 -1
- package/dist/utils/natural-language.test.js +24 -0
- package/dist/utils/natural-language.test.js.map +1 -1
- package/dist/utils/priority-queue.d.ts +17 -0
- package/dist/utils/priority-queue.d.ts.map +1 -0
- package/dist/utils/priority-queue.js +62 -0
- package/dist/utils/priority-queue.js.map +1 -0
- package/dist/utils/projection.d.ts +9 -0
- package/dist/utils/projection.d.ts.map +1 -1
- package/dist/utils/projection.js +37 -0
- package/dist/utils/projection.js.map +1 -1
- package/dist/utils/terminal-ui.d.ts +5 -0
- package/dist/utils/terminal-ui.d.ts.map +1 -1
- package/dist/utils/terminal-ui.js +88 -11
- package/dist/utils/terminal-ui.js.map +1 -1
- package/dist/utils/terminal-ui.test.d.ts +2 -0
- package/dist/utils/terminal-ui.test.d.ts.map +1 -0
- package/dist/utils/terminal-ui.test.js +683 -0
- package/dist/utils/terminal-ui.test.js.map +1 -0
- package/package.json +1 -1
- package/src/algorithms/critical-path.ts +6 -14
- package/src/algorithms/dependency-integrity.test.ts +348 -0
- package/src/algorithms/dependency-integrity.ts +41 -26
- package/src/algorithms/tech-analysis.ts +86 -18
- package/src/algorithms/topological-sort.ts +1 -62
- package/src/schemas/index.ts +3 -0
- package/src/schemas/state.ts +23 -0
- package/src/schemas/task.ts +3 -0
- package/src/utils/dashboard-renderer.test.ts +981 -0
- package/src/utils/dashboard-renderer.ts +14 -15
- package/src/utils/date.test.ts +170 -1
- package/src/utils/date.ts +214 -19
- package/src/utils/hierarchy.test.ts +411 -0
- package/src/utils/hierarchy.ts +22 -5
- package/src/utils/id.ts +1 -1
- package/src/utils/index.ts +17 -1
- package/src/utils/natural-language.test.ts +28 -0
- package/src/utils/natural-language.ts +8 -0
- package/src/utils/priority-queue.ts +68 -0
- package/src/utils/projection.ts +46 -2
- package/src/utils/terminal-ui.test.ts +831 -0
- package/src/utils/terminal-ui.ts +90 -10
|
@@ -25,6 +25,57 @@ const RISK_ORDER: Record<RiskLevel, number> = {
|
|
|
25
25
|
critical: 3,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Priority ordering for tiebreaker sorting (lower = higher priority)
|
|
30
|
+
*/
|
|
31
|
+
const PRIORITY_ORDER = {
|
|
32
|
+
critical: 0,
|
|
33
|
+
high: 1,
|
|
34
|
+
medium: 2,
|
|
35
|
+
low: 3,
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
/** Default priority order when priority is undefined */
|
|
39
|
+
const DEFAULT_PRIORITY_ORDER = PRIORITY_ORDER.medium;
|
|
40
|
+
|
|
41
|
+
/** Initial value for tech order tracking (before any phase) */
|
|
42
|
+
const INITIAL_TECH_ORDER = -1;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Complexity score thresholds for categorization
|
|
46
|
+
*/
|
|
47
|
+
const COMPLEXITY_THRESHOLDS = {
|
|
48
|
+
/** Maximum score for "low" complexity (1-3) */
|
|
49
|
+
LOW_MAX: 3,
|
|
50
|
+
/** Maximum score for "medium" complexity (4-6) */
|
|
51
|
+
MEDIUM_MAX: 6,
|
|
52
|
+
/** Minimum score requiring task breakdown (7+) */
|
|
53
|
+
BREAKDOWN_MIN: 7,
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Complexity score ranges for subtask suggestion calculation
|
|
58
|
+
*/
|
|
59
|
+
const SUBTASK_CALCULATION = {
|
|
60
|
+
/** Maximum score requiring no breakdown */
|
|
61
|
+
NO_BREAKDOWN_MAX: 2,
|
|
62
|
+
/** Maximum score for minimal breakdown */
|
|
63
|
+
MINIMAL_BREAKDOWN_MAX: 4,
|
|
64
|
+
/** Subtask count for minimal breakdown */
|
|
65
|
+
MINIMAL_SUBTASK_COUNT: 2,
|
|
66
|
+
/** Maximum score for moderate breakdown (3-4 subtasks) */
|
|
67
|
+
MODERATE_BREAKDOWN_MAX: 6,
|
|
68
|
+
/** Maximum score for significant breakdown (5-6 subtasks) */
|
|
69
|
+
SIGNIFICANT_BREAKDOWN_MAX: 8,
|
|
70
|
+
/** Coefficients for subtask count calculation */
|
|
71
|
+
MODERATE_COEFFICIENT: 0.5,
|
|
72
|
+
MODERATE_BASE: 3,
|
|
73
|
+
SIGNIFICANT_COEFFICIENT: 0.5,
|
|
74
|
+
SIGNIFICANT_BASE: 5,
|
|
75
|
+
EXTENSIVE_COEFFICIENT: 1.5,
|
|
76
|
+
EXTENSIVE_BASE: 7,
|
|
77
|
+
} as const;
|
|
78
|
+
|
|
28
79
|
/**
|
|
29
80
|
* Result of safe order suggestion
|
|
30
81
|
*/
|
|
@@ -124,13 +175,12 @@ export function suggestSafeOrder(tasks: Task[]): SafeOrderResult {
|
|
|
124
175
|
if (aBreaking !== bBreaking) return aBreaking - bBreaking;
|
|
125
176
|
|
|
126
177
|
// 4. Priority as tiebreaker (higher priority first)
|
|
127
|
-
|
|
128
|
-
return (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2);
|
|
178
|
+
return (PRIORITY_ORDER[a.priority] ?? DEFAULT_PRIORITY_ORDER) - (PRIORITY_ORDER[b.priority] ?? DEFAULT_PRIORITY_ORDER);
|
|
129
179
|
});
|
|
130
180
|
|
|
131
181
|
// Group into phases by tech level
|
|
132
182
|
const phases: SafeOrderPhase[] = [];
|
|
133
|
-
let currentTechOrder =
|
|
183
|
+
let currentTechOrder = INITIAL_TECH_ORDER;
|
|
134
184
|
let currentPhase: SafeOrderPhase | null = null;
|
|
135
185
|
|
|
136
186
|
for (const task of sorted) {
|
|
@@ -264,9 +314,9 @@ export function groupByTechArea(tasks: Task[]): Map<TechArea, Task[]> {
|
|
|
264
314
|
* Complexity distribution by level
|
|
265
315
|
*/
|
|
266
316
|
export interface ComplexityDistribution {
|
|
267
|
-
low: number; // 1
|
|
268
|
-
medium: number; //
|
|
269
|
-
high: number; //
|
|
317
|
+
low: number; // 1 to LOW_MAX
|
|
318
|
+
medium: number; // LOW_MAX+1 to MEDIUM_MAX
|
|
319
|
+
high: number; // MEDIUM_MAX+1 to 10
|
|
270
320
|
}
|
|
271
321
|
|
|
272
322
|
/**
|
|
@@ -275,7 +325,7 @@ export interface ComplexityDistribution {
|
|
|
275
325
|
export interface ComplexitySummary {
|
|
276
326
|
/** Distribution of complexity scores */
|
|
277
327
|
distribution: ComplexityDistribution;
|
|
278
|
-
/** Tasks that should be broken down (score >=
|
|
328
|
+
/** Tasks that should be broken down (score >= BREAKDOWN_MIN) */
|
|
279
329
|
needsBreakdown: Task[];
|
|
280
330
|
/** Average complexity score */
|
|
281
331
|
averageScore: number;
|
|
@@ -308,9 +358,9 @@ export function getComplexitySummary(tasks: Task[]): ComplexitySummary {
|
|
|
308
358
|
const score = task.complexity!.score!;
|
|
309
359
|
totalScore += score;
|
|
310
360
|
|
|
311
|
-
if (score <=
|
|
361
|
+
if (score <= COMPLEXITY_THRESHOLDS.LOW_MAX) {
|
|
312
362
|
distribution.low++;
|
|
313
|
-
} else if (score <=
|
|
363
|
+
} else if (score <= COMPLEXITY_THRESHOLDS.MEDIUM_MAX) {
|
|
314
364
|
distribution.medium++;
|
|
315
365
|
} else {
|
|
316
366
|
distribution.high++;
|
|
@@ -398,15 +448,33 @@ export function getTechStackSummary(tasks: Task[]): TechStackSummary {
|
|
|
398
448
|
*
|
|
399
449
|
* Mapping:
|
|
400
450
|
* 1-2: 0 (no breakdown needed)
|
|
401
|
-
* 3-4: 2
|
|
402
|
-
* 5-6: 3-4
|
|
403
|
-
* 7-8: 5-6
|
|
404
|
-
* 9-10: 7-10
|
|
451
|
+
* 3-4: 2 (minimal breakdown)
|
|
452
|
+
* 5-6: 3-4 (moderate breakdown)
|
|
453
|
+
* 7-8: 5-6 (significant breakdown)
|
|
454
|
+
* 9-10: 7-10 (extensive breakdown)
|
|
405
455
|
*/
|
|
406
456
|
export function suggestSubtaskCount(score: number): number {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
457
|
+
const {
|
|
458
|
+
NO_BREAKDOWN_MAX,
|
|
459
|
+
MINIMAL_BREAKDOWN_MAX,
|
|
460
|
+
MINIMAL_SUBTASK_COUNT,
|
|
461
|
+
MODERATE_BREAKDOWN_MAX,
|
|
462
|
+
SIGNIFICANT_BREAKDOWN_MAX,
|
|
463
|
+
MODERATE_COEFFICIENT,
|
|
464
|
+
MODERATE_BASE,
|
|
465
|
+
SIGNIFICANT_COEFFICIENT,
|
|
466
|
+
SIGNIFICANT_BASE,
|
|
467
|
+
EXTENSIVE_COEFFICIENT,
|
|
468
|
+
EXTENSIVE_BASE,
|
|
469
|
+
} = SUBTASK_CALCULATION;
|
|
470
|
+
|
|
471
|
+
if (score <= NO_BREAKDOWN_MAX) return 0;
|
|
472
|
+
if (score <= MINIMAL_BREAKDOWN_MAX) return MINIMAL_SUBTASK_COUNT;
|
|
473
|
+
if (score <= MODERATE_BREAKDOWN_MAX) {
|
|
474
|
+
return Math.ceil((score - MINIMAL_BREAKDOWN_MAX) * MODERATE_COEFFICIENT + MODERATE_BASE);
|
|
475
|
+
}
|
|
476
|
+
if (score <= SIGNIFICANT_BREAKDOWN_MAX) {
|
|
477
|
+
return Math.ceil((score - MODERATE_BREAKDOWN_MAX) * SIGNIFICANT_COEFFICIENT + SIGNIFICANT_BASE);
|
|
478
|
+
}
|
|
479
|
+
return Math.ceil((score - SIGNIFICANT_BREAKDOWN_MAX) * EXTENSIVE_COEFFICIENT + EXTENSIVE_BASE);
|
|
412
480
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Task } from "../schemas/task.js";
|
|
2
|
+
import { PriorityQueue } from "../utils/priority-queue.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Node representation for graph algorithms
|
|
@@ -10,67 +11,6 @@ export interface TaskNode {
|
|
|
10
11
|
estimate: number; // Duration in minutes
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* Max-heap implementation for priority queue (higher priority = higher value comes first)
|
|
15
|
-
* O(log n) insert and extract operations vs O(n log n) for sort-based approach
|
|
16
|
-
*/
|
|
17
|
-
class PriorityQueue<T> {
|
|
18
|
-
private heap: T[] = [];
|
|
19
|
-
private compare: (a: T, b: T) => number;
|
|
20
|
-
|
|
21
|
-
constructor(compare: (a: T, b: T) => number) {
|
|
22
|
-
this.compare = compare;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
get length(): number {
|
|
26
|
-
return this.heap.length;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
push(item: T): void {
|
|
30
|
-
this.heap.push(item);
|
|
31
|
-
this.bubbleUp(this.heap.length - 1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
pop(): T | undefined {
|
|
35
|
-
if (this.heap.length === 0) return undefined;
|
|
36
|
-
if (this.heap.length === 1) return this.heap.pop();
|
|
37
|
-
|
|
38
|
-
const result = this.heap[0];
|
|
39
|
-
this.heap[0] = this.heap.pop()!;
|
|
40
|
-
this.bubbleDown(0);
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private bubbleUp(index: number): void {
|
|
45
|
-
while (index > 0) {
|
|
46
|
-
const parentIndex = Math.floor((index - 1) / 2);
|
|
47
|
-
if (this.compare(this.heap[index]!, this.heap[parentIndex]!) <= 0) break;
|
|
48
|
-
[this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex]!, this.heap[index]!];
|
|
49
|
-
index = parentIndex;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private bubbleDown(index: number): void {
|
|
54
|
-
const length = this.heap.length;
|
|
55
|
-
while (true) {
|
|
56
|
-
const leftChild = 2 * index + 1;
|
|
57
|
-
const rightChild = 2 * index + 2;
|
|
58
|
-
let largest = index;
|
|
59
|
-
|
|
60
|
-
if (leftChild < length && this.compare(this.heap[leftChild]!, this.heap[largest]!) > 0) {
|
|
61
|
-
largest = leftChild;
|
|
62
|
-
}
|
|
63
|
-
if (rightChild < length && this.compare(this.heap[rightChild]!, this.heap[largest]!) > 0) {
|
|
64
|
-
largest = rightChild;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (largest === index) break;
|
|
68
|
-
[this.heap[index], this.heap[largest]] = [this.heap[largest]!, this.heap[index]!];
|
|
69
|
-
index = largest;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
14
|
/**
|
|
75
15
|
* Convert priority string to numeric value
|
|
76
16
|
*/
|
|
@@ -206,7 +146,6 @@ export function wouldCreateCycle(
|
|
|
206
146
|
* Find all tasks that depend on a given task (directly or transitively)
|
|
207
147
|
*/
|
|
208
148
|
export function findDependents(tasks: Task[], taskId: string): Task[] {
|
|
209
|
-
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
210
149
|
const visited = new Set<string>();
|
|
211
150
|
const result: Task[] = [];
|
|
212
151
|
|
package/src/schemas/index.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// State schema for persisting application state
|
|
4
|
+
// Stored in .tasks/state.json
|
|
5
|
+
|
|
6
|
+
export const State = z.object({
|
|
7
|
+
// Current git branch (auto-detected or manually set)
|
|
8
|
+
gitBranch: z.string().optional(),
|
|
9
|
+
|
|
10
|
+
// Active tag for task filtering (maps to git branch by default)
|
|
11
|
+
// Required field - use DEFAULT_STATE when creating new state
|
|
12
|
+
activeTag: z.string(),
|
|
13
|
+
|
|
14
|
+
// Last updated timestamp
|
|
15
|
+
updatedAt: z.string().optional(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type State = z.infer<typeof State>;
|
|
19
|
+
|
|
20
|
+
// Default state when no state.json exists
|
|
21
|
+
export const DEFAULT_STATE: State = {
|
|
22
|
+
activeTag: "main",
|
|
23
|
+
};
|
package/src/schemas/task.ts
CHANGED
|
@@ -124,6 +124,7 @@ export const Task = z.object({
|
|
|
124
124
|
// Organization
|
|
125
125
|
contexts: z.array(z.string()).optional(), // e.g., ["focus", "review"]
|
|
126
126
|
tags: z.array(z.string()).optional(),
|
|
127
|
+
sortOrder: z.number().optional(), // Manual ordering within lists
|
|
127
128
|
|
|
128
129
|
// Recurrence
|
|
129
130
|
recurrence: Recurrence.optional(),
|
|
@@ -157,6 +158,7 @@ export const TaskCreateInput = z.object({
|
|
|
157
158
|
startDate: z.string().optional(),
|
|
158
159
|
contexts: z.array(z.string()).optional(),
|
|
159
160
|
tags: z.array(z.string()).optional(),
|
|
161
|
+
sortOrder: z.number().optional(),
|
|
160
162
|
recurrence: Recurrence.optional(),
|
|
161
163
|
});
|
|
162
164
|
export type TaskCreateInput = z.infer<typeof TaskCreateInput>;
|
|
@@ -176,6 +178,7 @@ export const TaskUpdateInput = z.object({
|
|
|
176
178
|
startDate: z.string().optional(),
|
|
177
179
|
contexts: z.array(z.string()).optional(),
|
|
178
180
|
tags: z.array(z.string()).optional(),
|
|
181
|
+
sortOrder: z.number().optional(),
|
|
179
182
|
recurrence: Recurrence.optional(),
|
|
180
183
|
// Analysis fields
|
|
181
184
|
complexity: ComplexityAnalysis.optional(),
|