@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.
Files changed (104) hide show
  1. package/dist/algorithms/critical-path.d.ts.map +1 -1
  2. package/dist/algorithms/critical-path.js +2 -14
  3. package/dist/algorithms/critical-path.js.map +1 -1
  4. package/dist/algorithms/dependency-integrity.d.ts +8 -0
  5. package/dist/algorithms/dependency-integrity.d.ts.map +1 -1
  6. package/dist/algorithms/dependency-integrity.js +42 -24
  7. package/dist/algorithms/dependency-integrity.js.map +1 -1
  8. package/dist/algorithms/dependency-integrity.test.d.ts +2 -0
  9. package/dist/algorithms/dependency-integrity.test.d.ts.map +1 -0
  10. package/dist/algorithms/dependency-integrity.test.js +309 -0
  11. package/dist/algorithms/dependency-integrity.test.js.map +1 -0
  12. package/dist/algorithms/tech-analysis.d.ts +5 -5
  13. package/dist/algorithms/tech-analysis.d.ts.map +1 -1
  14. package/dist/algorithms/tech-analysis.js +65 -17
  15. package/dist/algorithms/tech-analysis.js.map +1 -1
  16. package/dist/algorithms/topological-sort.d.ts.map +1 -1
  17. package/dist/algorithms/topological-sort.js +1 -56
  18. package/dist/algorithms/topological-sort.js.map +1 -1
  19. package/dist/schemas/index.d.ts +1 -0
  20. package/dist/schemas/index.d.ts.map +1 -1
  21. package/dist/schemas/index.js +2 -0
  22. package/dist/schemas/index.js.map +1 -1
  23. package/dist/schemas/project.d.ts +6 -6
  24. package/dist/schemas/state.d.ts +17 -0
  25. package/dist/schemas/state.d.ts.map +1 -0
  26. package/dist/schemas/state.js +17 -0
  27. package/dist/schemas/state.js.map +1 -0
  28. package/dist/schemas/task.d.ts +13 -4
  29. package/dist/schemas/task.d.ts.map +1 -1
  30. package/dist/schemas/task.js +3 -0
  31. package/dist/schemas/task.js.map +1 -1
  32. package/dist/schemas/view.d.ts +4 -4
  33. package/dist/utils/dashboard-renderer.d.ts +3 -0
  34. package/dist/utils/dashboard-renderer.d.ts.map +1 -1
  35. package/dist/utils/dashboard-renderer.js +12 -13
  36. package/dist/utils/dashboard-renderer.js.map +1 -1
  37. package/dist/utils/dashboard-renderer.test.d.ts +2 -0
  38. package/dist/utils/dashboard-renderer.test.d.ts.map +1 -0
  39. package/dist/utils/dashboard-renderer.test.js +777 -0
  40. package/dist/utils/dashboard-renderer.test.js.map +1 -0
  41. package/dist/utils/date.d.ts +49 -0
  42. package/dist/utils/date.d.ts.map +1 -1
  43. package/dist/utils/date.js +174 -19
  44. package/dist/utils/date.js.map +1 -1
  45. package/dist/utils/date.test.js +139 -1
  46. package/dist/utils/date.test.js.map +1 -1
  47. package/dist/utils/hierarchy.d.ts +1 -1
  48. package/dist/utils/hierarchy.d.ts.map +1 -1
  49. package/dist/utils/hierarchy.js +15 -5
  50. package/dist/utils/hierarchy.js.map +1 -1
  51. package/dist/utils/hierarchy.test.d.ts +2 -0
  52. package/dist/utils/hierarchy.test.d.ts.map +1 -0
  53. package/dist/utils/hierarchy.test.js +351 -0
  54. package/dist/utils/hierarchy.test.js.map +1 -0
  55. package/dist/utils/id.js +1 -1
  56. package/dist/utils/id.js.map +1 -1
  57. package/dist/utils/index.d.ts +3 -2
  58. package/dist/utils/index.d.ts.map +1 -1
  59. package/dist/utils/index.js +3 -2
  60. package/dist/utils/index.js.map +1 -1
  61. package/dist/utils/natural-language.d.ts.map +1 -1
  62. package/dist/utils/natural-language.js +7 -0
  63. package/dist/utils/natural-language.js.map +1 -1
  64. package/dist/utils/natural-language.test.js +24 -0
  65. package/dist/utils/natural-language.test.js.map +1 -1
  66. package/dist/utils/priority-queue.d.ts +17 -0
  67. package/dist/utils/priority-queue.d.ts.map +1 -0
  68. package/dist/utils/priority-queue.js +62 -0
  69. package/dist/utils/priority-queue.js.map +1 -0
  70. package/dist/utils/projection.d.ts +9 -0
  71. package/dist/utils/projection.d.ts.map +1 -1
  72. package/dist/utils/projection.js +37 -0
  73. package/dist/utils/projection.js.map +1 -1
  74. package/dist/utils/terminal-ui.d.ts +5 -0
  75. package/dist/utils/terminal-ui.d.ts.map +1 -1
  76. package/dist/utils/terminal-ui.js +88 -11
  77. package/dist/utils/terminal-ui.js.map +1 -1
  78. package/dist/utils/terminal-ui.test.d.ts +2 -0
  79. package/dist/utils/terminal-ui.test.d.ts.map +1 -0
  80. package/dist/utils/terminal-ui.test.js +683 -0
  81. package/dist/utils/terminal-ui.test.js.map +1 -0
  82. package/package.json +1 -1
  83. package/src/algorithms/critical-path.ts +6 -14
  84. package/src/algorithms/dependency-integrity.test.ts +348 -0
  85. package/src/algorithms/dependency-integrity.ts +41 -26
  86. package/src/algorithms/tech-analysis.ts +86 -18
  87. package/src/algorithms/topological-sort.ts +1 -62
  88. package/src/schemas/index.ts +3 -0
  89. package/src/schemas/state.ts +23 -0
  90. package/src/schemas/task.ts +3 -0
  91. package/src/utils/dashboard-renderer.test.ts +981 -0
  92. package/src/utils/dashboard-renderer.ts +14 -15
  93. package/src/utils/date.test.ts +170 -1
  94. package/src/utils/date.ts +214 -19
  95. package/src/utils/hierarchy.test.ts +411 -0
  96. package/src/utils/hierarchy.ts +22 -5
  97. package/src/utils/id.ts +1 -1
  98. package/src/utils/index.ts +17 -1
  99. package/src/utils/natural-language.test.ts +28 -0
  100. package/src/utils/natural-language.ts +8 -0
  101. package/src/utils/priority-queue.ts +68 -0
  102. package/src/utils/projection.ts +46 -2
  103. package/src/utils/terminal-ui.test.ts +831 -0
  104. 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
- const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
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 = -1;
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-3
268
- medium: number; // 4-6
269
- high: number; // 7-10
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 >= 7) */
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 <= 3) {
361
+ if (score <= COMPLEXITY_THRESHOLDS.LOW_MAX) {
312
362
  distribution.low++;
313
- } else if (score <= 6) {
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
- if (score <= 2) return 0;
408
- if (score <= 4) return 2;
409
- if (score <= 6) return Math.ceil((score - 4) * 0.5 + 3); // 3-4
410
- if (score <= 8) return Math.ceil((score - 6) * 0.5 + 5); // 5-6
411
- return Math.ceil((score - 8) * 1.5 + 7); // 7-10
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
 
@@ -82,3 +82,6 @@ export {
82
82
  AgentResponse,
83
83
  GenerateResponseInput,
84
84
  } from "./response-schema.js";
85
+
86
+ // State schema (git branch, active tag)
87
+ export { State, DEFAULT_STATE } from "./state.js";
@@ -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
+ };
@@ -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(),