@task-mcp/shared 1.0.20 → 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/README.md +122 -0
- package/package.json +1 -6
- package/src/algorithms/critical-path.ts +31 -6
- package/src/algorithms/dependency-integrity.ts +5 -2
- package/src/algorithms/topological-sort.ts +66 -17
- package/src/utils/index.ts +5 -5
- package/src/utils/natural-language.ts +210 -83
- package/src/utils/projection.ts +8 -8
- package/src/utils/workspace.ts +16 -4
- package/dist/algorithms/critical-path.d.ts +0 -46
- package/dist/algorithms/critical-path.d.ts.map +0 -1
- package/dist/algorithms/critical-path.js +0 -320
- package/dist/algorithms/critical-path.js.map +0 -1
- package/dist/algorithms/critical-path.test.d.ts +0 -2
- package/dist/algorithms/critical-path.test.d.ts.map +0 -1
- package/dist/algorithms/critical-path.test.js +0 -194
- package/dist/algorithms/critical-path.test.js.map +0 -1
- package/dist/algorithms/dependency-integrity.d.ts +0 -81
- package/dist/algorithms/dependency-integrity.d.ts.map +0 -1
- package/dist/algorithms/dependency-integrity.js +0 -207
- package/dist/algorithms/dependency-integrity.js.map +0 -1
- package/dist/algorithms/dependency-integrity.test.d.ts +0 -2
- package/dist/algorithms/dependency-integrity.test.d.ts.map +0 -1
- package/dist/algorithms/dependency-integrity.test.js +0 -309
- package/dist/algorithms/dependency-integrity.test.js.map +0 -1
- package/dist/algorithms/index.d.ts +0 -5
- package/dist/algorithms/index.d.ts.map +0 -1
- package/dist/algorithms/index.js +0 -5
- package/dist/algorithms/index.js.map +0 -1
- package/dist/algorithms/tech-analysis.d.ts +0 -106
- package/dist/algorithms/tech-analysis.d.ts.map +0 -1
- package/dist/algorithms/tech-analysis.js +0 -344
- package/dist/algorithms/tech-analysis.js.map +0 -1
- package/dist/algorithms/tech-analysis.test.d.ts +0 -2
- package/dist/algorithms/tech-analysis.test.d.ts.map +0 -1
- package/dist/algorithms/tech-analysis.test.js +0 -338
- package/dist/algorithms/tech-analysis.test.js.map +0 -1
- package/dist/algorithms/topological-sort.d.ts +0 -41
- package/dist/algorithms/topological-sort.d.ts.map +0 -1
- package/dist/algorithms/topological-sort.js +0 -165
- package/dist/algorithms/topological-sort.js.map +0 -1
- package/dist/algorithms/topological-sort.test.d.ts +0 -2
- package/dist/algorithms/topological-sort.test.d.ts.map +0 -1
- package/dist/algorithms/topological-sort.test.js +0 -162
- package/dist/algorithms/topological-sort.test.js.map +0 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -7
- package/dist/index.js.map +0 -1
- package/dist/schemas/inbox.d.ts +0 -55
- package/dist/schemas/inbox.d.ts.map +0 -1
- package/dist/schemas/inbox.js +0 -25
- package/dist/schemas/inbox.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -7
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -17
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/project.d.ts +0 -177
- package/dist/schemas/project.d.ts.map +0 -1
- package/dist/schemas/project.js +0 -56
- package/dist/schemas/project.js.map +0 -1
- package/dist/schemas/response-format.d.ts +0 -148
- package/dist/schemas/response-format.d.ts.map +0 -1
- package/dist/schemas/response-format.js +0 -18
- package/dist/schemas/response-format.js.map +0 -1
- package/dist/schemas/response-schema.d.ts +0 -307
- package/dist/schemas/response-schema.d.ts.map +0 -1
- package/dist/schemas/response-schema.js +0 -75
- package/dist/schemas/response-schema.js.map +0 -1
- package/dist/schemas/response-schema.test.d.ts +0 -2
- package/dist/schemas/response-schema.test.d.ts.map +0 -1
- package/dist/schemas/response-schema.test.js +0 -256
- package/dist/schemas/response-schema.test.js.map +0 -1
- package/dist/schemas/state.d.ts +0 -17
- package/dist/schemas/state.d.ts.map +0 -1
- package/dist/schemas/state.js +0 -17
- package/dist/schemas/state.js.map +0 -1
- package/dist/schemas/task.d.ts +0 -881
- package/dist/schemas/task.d.ts.map +0 -1
- package/dist/schemas/task.js +0 -189
- package/dist/schemas/task.js.map +0 -1
- package/dist/schemas/view.d.ts +0 -143
- package/dist/schemas/view.d.ts.map +0 -1
- package/dist/schemas/view.js +0 -48
- package/dist/schemas/view.js.map +0 -1
- package/dist/utils/dashboard-renderer.d.ts +0 -93
- package/dist/utils/dashboard-renderer.d.ts.map +0 -1
- package/dist/utils/dashboard-renderer.js +0 -424
- package/dist/utils/dashboard-renderer.js.map +0 -1
- package/dist/utils/dashboard-renderer.test.d.ts +0 -2
- package/dist/utils/dashboard-renderer.test.d.ts.map +0 -1
- package/dist/utils/dashboard-renderer.test.js +0 -774
- package/dist/utils/dashboard-renderer.test.js.map +0 -1
- package/dist/utils/date.d.ts +0 -94
- package/dist/utils/date.d.ts.map +0 -1
- package/dist/utils/date.js +0 -323
- package/dist/utils/date.js.map +0 -1
- package/dist/utils/date.test.d.ts +0 -2
- package/dist/utils/date.test.d.ts.map +0 -1
- package/dist/utils/date.test.js +0 -276
- package/dist/utils/date.test.js.map +0 -1
- package/dist/utils/hierarchy.d.ts +0 -102
- package/dist/utils/hierarchy.d.ts.map +0 -1
- package/dist/utils/hierarchy.js +0 -236
- package/dist/utils/hierarchy.js.map +0 -1
- package/dist/utils/hierarchy.test.d.ts +0 -2
- package/dist/utils/hierarchy.test.d.ts.map +0 -1
- package/dist/utils/hierarchy.test.js +0 -436
- package/dist/utils/hierarchy.test.js.map +0 -1
- package/dist/utils/id.d.ts +0 -60
- package/dist/utils/id.d.ts.map +0 -1
- package/dist/utils/id.js +0 -118
- package/dist/utils/id.js.map +0 -1
- package/dist/utils/id.test.d.ts +0 -2
- package/dist/utils/id.test.d.ts.map +0 -1
- package/dist/utils/id.test.js +0 -193
- package/dist/utils/id.test.js.map +0 -1
- package/dist/utils/index.d.ts +0 -12
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -34
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/natural-language.d.ts +0 -57
- package/dist/utils/natural-language.d.ts.map +0 -1
- package/dist/utils/natural-language.js +0 -211
- package/dist/utils/natural-language.js.map +0 -1
- package/dist/utils/natural-language.test.d.ts +0 -2
- package/dist/utils/natural-language.test.d.ts.map +0 -1
- package/dist/utils/natural-language.test.js +0 -197
- package/dist/utils/natural-language.test.js.map +0 -1
- package/dist/utils/priority-queue.d.ts +0 -17
- package/dist/utils/priority-queue.d.ts.map +0 -1
- package/dist/utils/priority-queue.js +0 -62
- package/dist/utils/priority-queue.js.map +0 -1
- package/dist/utils/priority-queue.test.d.ts +0 -2
- package/dist/utils/priority-queue.test.d.ts.map +0 -1
- package/dist/utils/priority-queue.test.js +0 -82
- package/dist/utils/priority-queue.test.js.map +0 -1
- package/dist/utils/projection.d.ts +0 -65
- package/dist/utils/projection.d.ts.map +0 -1
- package/dist/utils/projection.js +0 -180
- package/dist/utils/projection.js.map +0 -1
- package/dist/utils/projection.test.d.ts +0 -2
- package/dist/utils/projection.test.d.ts.map +0 -1
- package/dist/utils/projection.test.js +0 -336
- package/dist/utils/projection.test.js.map +0 -1
- package/dist/utils/terminal-ui.d.ts +0 -208
- package/dist/utils/terminal-ui.d.ts.map +0 -1
- package/dist/utils/terminal-ui.js +0 -611
- package/dist/utils/terminal-ui.js.map +0 -1
- package/dist/utils/terminal-ui.test.d.ts +0 -2
- package/dist/utils/terminal-ui.test.d.ts.map +0 -1
- package/dist/utils/terminal-ui.test.js +0 -683
- package/dist/utils/terminal-ui.test.js.map +0 -1
- package/dist/utils/workspace.d.ts +0 -100
- package/dist/utils/workspace.d.ts.map +0 -1
- package/dist/utils/workspace.js +0 -173
- package/dist/utils/workspace.js.map +0 -1
- package/dist/utils/workspace.test.d.ts +0 -2
- package/dist/utils/workspace.test.d.ts.map +0 -1
- package/dist/utils/workspace.test.js +0 -97
- package/dist/utils/workspace.test.js.map +0 -1
- package/src/algorithms/critical-path.test.ts +0 -241
- package/src/algorithms/dependency-integrity.test.ts +0 -348
- package/src/algorithms/tech-analysis.test.ts +0 -413
- package/src/algorithms/topological-sort.test.ts +0 -190
- package/src/schemas/response-schema.test.ts +0 -314
- package/src/utils/dashboard-renderer.test.ts +0 -983
- package/src/utils/date.test.ts +0 -329
- package/src/utils/hierarchy.test.ts +0 -505
- package/src/utils/id.test.ts +0 -235
- package/src/utils/natural-language.test.ts +0 -242
- package/src/utils/priority-queue.test.ts +0 -103
- package/src/utils/projection.test.ts +0 -425
- package/src/utils/terminal-ui.test.ts +0 -831
- package/src/utils/workspace.test.ts +0 -125
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# @task-mcp/shared
|
|
2
|
+
|
|
3
|
+
Core algorithms, schemas, and utilities for task-mcp. Zero MCP dependency - can be used standalone.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @task-mcp/shared
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Modules
|
|
12
|
+
|
|
13
|
+
### Algorithms
|
|
14
|
+
|
|
15
|
+
Graph algorithms for task dependency management.
|
|
16
|
+
|
|
17
|
+
| Module | Description |
|
|
18
|
+
|--------|-------------|
|
|
19
|
+
| `critical-path` | CPM (Critical Path Method) - finds longest path, parallel tasks, bottlenecks |
|
|
20
|
+
| `topological-sort` | Kahn's algorithm for dependency ordering with cycle detection |
|
|
21
|
+
| `dependency-integrity` | Validates dependency graph integrity (cycles, orphans, self-refs) |
|
|
22
|
+
| `tech-analysis` | Analyzes tasks for technology stack patterns |
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import {
|
|
26
|
+
findCriticalPath,
|
|
27
|
+
findParallelTasks,
|
|
28
|
+
detectBottlenecks,
|
|
29
|
+
topologicalSort,
|
|
30
|
+
validateDependencies
|
|
31
|
+
} from "@task-mcp/shared";
|
|
32
|
+
|
|
33
|
+
// Find critical path through task graph
|
|
34
|
+
const { criticalPath, totalDuration } = findCriticalPath(tasks);
|
|
35
|
+
|
|
36
|
+
// Find tasks that can run in parallel
|
|
37
|
+
const parallelGroups = findParallelTasks(tasks);
|
|
38
|
+
|
|
39
|
+
// Topological sort with cycle detection
|
|
40
|
+
const { sorted, hasCycle } = topologicalSort(tasks);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Schemas
|
|
44
|
+
|
|
45
|
+
Zod schemas for validation and type inference.
|
|
46
|
+
|
|
47
|
+
| Schema | Description |
|
|
48
|
+
|--------|-------------|
|
|
49
|
+
| `Task` | Task with status, priority, dependencies, hierarchy |
|
|
50
|
+
| `InboxItem` | Quick capture items pending triage |
|
|
51
|
+
| `ResponseFormat` | `concise` / `standard` / `detailed` output modes |
|
|
52
|
+
| `View` | Filtered task views (today, blocked, quick-wins) |
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { TaskSchema, Task, Priority, Status } from "@task-mcp/shared";
|
|
56
|
+
|
|
57
|
+
// Validate and parse
|
|
58
|
+
const task = TaskSchema.parse(rawData);
|
|
59
|
+
|
|
60
|
+
// Type inference
|
|
61
|
+
type Task = z.infer<typeof TaskSchema>;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Utilities
|
|
65
|
+
|
|
66
|
+
| Utility | Description |
|
|
67
|
+
|---------|-------------|
|
|
68
|
+
| `natural-language` | Parse "task !high @context #tag due:tomorrow" syntax |
|
|
69
|
+
| `workspace` | Auto-detect workspace from git repository name |
|
|
70
|
+
| `projection` | Format tasks to concise/standard/detailed (70-88% token savings) |
|
|
71
|
+
| `hierarchy` | Build parent-child tree, find descendants/ancestors |
|
|
72
|
+
| `date` | Parse relative dates ("tomorrow", "next week", "in 3 days") |
|
|
73
|
+
| `id` | Generate collision-resistant IDs (`task_xxxx`, `inbox_xxxx`) |
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import {
|
|
77
|
+
parseNaturalLanguage,
|
|
78
|
+
detectWorkspace,
|
|
79
|
+
formatTask,
|
|
80
|
+
buildHierarchy
|
|
81
|
+
} from "@task-mcp/shared";
|
|
82
|
+
|
|
83
|
+
// Parse natural language input
|
|
84
|
+
const parsed = parseNaturalLanguage("Review PR !high @work #urgent due:tomorrow");
|
|
85
|
+
// { title: "Review PR", priority: "high", contexts: ["work"], tags: ["urgent"], dueDate: "2024-01-02" }
|
|
86
|
+
|
|
87
|
+
// Detect workspace from git
|
|
88
|
+
const workspace = await detectWorkspace(); // "task-mcp"
|
|
89
|
+
|
|
90
|
+
// Format for token efficiency
|
|
91
|
+
const concise = formatTask(task, "concise");
|
|
92
|
+
// { id, title, status, priority } - minimal fields
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Architecture
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
shared/
|
|
99
|
+
├── algorithms/ # Graph algorithms (no external deps)
|
|
100
|
+
│ ├── critical-path.ts
|
|
101
|
+
│ ├── topological-sort.ts
|
|
102
|
+
│ └── dependency-integrity.ts
|
|
103
|
+
├── schemas/ # Zod schemas + type exports
|
|
104
|
+
│ ├── task.ts
|
|
105
|
+
│ ├── inbox.ts
|
|
106
|
+
│ └── response-format.ts
|
|
107
|
+
└── utils/ # Pure utility functions
|
|
108
|
+
├── natural-language.ts
|
|
109
|
+
├── workspace.ts
|
|
110
|
+
└── projection.ts
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Design Principles
|
|
114
|
+
|
|
115
|
+
1. **Zero MCP dependency** - Can be used in any TypeScript project
|
|
116
|
+
2. **Zod-first validation** - Runtime safety with static types
|
|
117
|
+
3. **Algorithm efficiency** - O(n+e) graph operations
|
|
118
|
+
4. **Token optimization** - Projection system reduces LLM token usage by 70-88%
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@task-mcp/shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Shared utilities for task-mcp: types, algorithms, and natural language parsing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,11 +12,6 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
16
|
-
"src",
|
|
17
|
-
"dist",
|
|
18
|
-
"README.md"
|
|
19
|
-
],
|
|
20
15
|
"scripts": {
|
|
21
16
|
"build": "tsc",
|
|
22
17
|
"dev": "tsc --watch",
|
|
@@ -315,6 +315,7 @@ export function criticalPathAnalysis(tasks: Task[]): CPMResult {
|
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
317
|
* Find tasks that can be executed in parallel (no dependencies between them)
|
|
318
|
+
* Optimized to O(n + e) where n = number of tasks, e = number of dependencies
|
|
318
319
|
*/
|
|
319
320
|
export function findParallelTasks(tasks: Task[]): Task[][] {
|
|
320
321
|
const activeTasks = tasks.filter(
|
|
@@ -335,7 +336,26 @@ export function findParallelTasks(tasks: Task[]): Task[][] {
|
|
|
335
336
|
|
|
336
337
|
if (available.length <= 1) return [available];
|
|
337
338
|
|
|
338
|
-
//
|
|
339
|
+
// Build dependency Sets for O(1) lookup - O(n + e) total
|
|
340
|
+
const dependsOn = new Map<string, Set<string>>();
|
|
341
|
+
for (const task of available) {
|
|
342
|
+
const deps = (task.dependencies ?? []).map((d) => d.taskId);
|
|
343
|
+
dependsOn.set(task.id, new Set(deps));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Build reverse dependency index (who depends on me) - O(e) total
|
|
347
|
+
const dependedBy = new Map<string, Set<string>>();
|
|
348
|
+
for (const task of available) {
|
|
349
|
+
dependedBy.set(task.id, new Set());
|
|
350
|
+
}
|
|
351
|
+
for (const task of available) {
|
|
352
|
+
const deps = dependsOn.get(task.id) ?? new Set();
|
|
353
|
+
for (const depId of deps) {
|
|
354
|
+
dependedBy.get(depId)?.add(task.id);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Group tasks that don't depend on each other - O(n + e)
|
|
339
359
|
const groups: Task[][] = [];
|
|
340
360
|
const processed = new Set<string>();
|
|
341
361
|
|
|
@@ -345,15 +365,20 @@ export function findParallelTasks(tasks: Task[]): Task[][] {
|
|
|
345
365
|
const group: Task[] = [task];
|
|
346
366
|
processed.add(task.id);
|
|
347
367
|
|
|
368
|
+
// Get all tasks that this task depends on or that depend on this task
|
|
369
|
+
const conflicting = new Set<string>();
|
|
370
|
+
const taskDeps = dependsOn.get(task.id) ?? new Set();
|
|
371
|
+
const taskDependedBy = dependedBy.get(task.id) ?? new Set();
|
|
372
|
+
for (const id of taskDeps) conflicting.add(id);
|
|
373
|
+
for (const id of taskDependedBy) conflicting.add(id);
|
|
374
|
+
|
|
348
375
|
for (const other of available) {
|
|
349
376
|
if (processed.has(other.id)) continue;
|
|
350
377
|
|
|
351
|
-
//
|
|
352
|
-
const taskDeps = (task.dependencies ?? []).map((d) => d.taskId);
|
|
353
|
-
const otherDeps = (other.dependencies ?? []).map((d) => d.taskId);
|
|
354
|
-
|
|
378
|
+
// O(1) check: tasks are independent if neither depends on the other
|
|
355
379
|
const independent =
|
|
356
|
-
!
|
|
380
|
+
!conflicting.has(other.id) &&
|
|
381
|
+
!dependsOn.get(other.id)?.has(task.id);
|
|
357
382
|
|
|
358
383
|
if (independent) {
|
|
359
384
|
group.push(other);
|
|
@@ -50,8 +50,11 @@ export function validateDependency(
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// Build taskMap once for O(1) lookups
|
|
54
|
+
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
55
|
+
|
|
53
56
|
// 2. Task existence check
|
|
54
|
-
const task =
|
|
57
|
+
const task = taskMap.get(taskId);
|
|
55
58
|
if (!task) {
|
|
56
59
|
return {
|
|
57
60
|
valid: false,
|
|
@@ -62,7 +65,7 @@ export function validateDependency(
|
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
// 3. Blocker task existence check
|
|
65
|
-
const blocker =
|
|
68
|
+
const blocker = taskMap.get(blockedBy);
|
|
66
69
|
if (!blocker) {
|
|
67
70
|
return {
|
|
68
71
|
valid: false,
|
|
@@ -142,23 +142,73 @@ export function wouldCreateCycle(
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Build inverted indices for efficient dependency lookups
|
|
147
|
+
* Returns:
|
|
148
|
+
* - dependentsIndex: taskId -> [tasks that depend on this task]
|
|
149
|
+
* - dependenciesIndex: taskId -> [tasks this task depends on]
|
|
150
|
+
*
|
|
151
|
+
* Time complexity: O(n + e) where n = tasks, e = edges
|
|
152
|
+
*/
|
|
153
|
+
export function buildDependencyIndices(tasks: Task[]): {
|
|
154
|
+
taskMap: Map<string, Task>;
|
|
155
|
+
dependentsIndex: Map<string, string[]>;
|
|
156
|
+
dependenciesIndex: Map<string, string[]>;
|
|
157
|
+
} {
|
|
158
|
+
const taskMap = new Map<string, Task>();
|
|
159
|
+
const dependentsIndex = new Map<string, string[]>();
|
|
160
|
+
const dependenciesIndex = new Map<string, string[]>();
|
|
161
|
+
|
|
162
|
+
// Initialize maps - O(n)
|
|
163
|
+
for (const task of tasks) {
|
|
164
|
+
taskMap.set(task.id, task);
|
|
165
|
+
dependentsIndex.set(task.id, []);
|
|
166
|
+
dependenciesIndex.set(task.id, []);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Build indices - O(e)
|
|
170
|
+
for (const task of tasks) {
|
|
171
|
+
const deps = (task.dependencies ?? [])
|
|
172
|
+
.filter((d) => d.type === "blocked_by")
|
|
173
|
+
.map((d) => d.taskId);
|
|
174
|
+
|
|
175
|
+
// Store direct dependencies for this task
|
|
176
|
+
dependenciesIndex.set(task.id, deps.filter((depId) => taskMap.has(depId)));
|
|
177
|
+
|
|
178
|
+
// Update dependents index (reverse lookup)
|
|
179
|
+
for (const depId of deps) {
|
|
180
|
+
if (taskMap.has(depId)) {
|
|
181
|
+
dependentsIndex.get(depId)!.push(task.id);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return { taskMap, dependentsIndex, dependenciesIndex };
|
|
187
|
+
}
|
|
188
|
+
|
|
145
189
|
/**
|
|
146
190
|
* Find all tasks that depend on a given task (directly or transitively)
|
|
191
|
+
*
|
|
192
|
+
* Time complexity: O(n + e) with inverted index
|
|
147
193
|
*/
|
|
148
194
|
export function findDependents(tasks: Task[], taskId: string): Task[] {
|
|
195
|
+
const { taskMap, dependentsIndex } = buildDependencyIndices(tasks);
|
|
196
|
+
|
|
149
197
|
const visited = new Set<string>();
|
|
150
198
|
const result: Task[] = [];
|
|
151
199
|
|
|
152
200
|
function dfs(id: string) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
201
|
+
const dependentIds = dependentsIndex.get(id);
|
|
202
|
+
if (!dependentIds) return;
|
|
203
|
+
|
|
204
|
+
for (const depId of dependentIds) {
|
|
205
|
+
if (!visited.has(depId)) {
|
|
206
|
+
visited.add(depId);
|
|
207
|
+
const task = taskMap.get(depId);
|
|
208
|
+
if (task) {
|
|
209
|
+
result.push(task);
|
|
210
|
+
dfs(depId);
|
|
211
|
+
}
|
|
162
212
|
}
|
|
163
213
|
}
|
|
164
214
|
}
|
|
@@ -169,21 +219,20 @@ export function findDependents(tasks: Task[], taskId: string): Task[] {
|
|
|
169
219
|
|
|
170
220
|
/**
|
|
171
221
|
* Find all tasks that a given task depends on (directly or transitively)
|
|
222
|
+
*
|
|
223
|
+
* Time complexity: O(n + e) with pre-built index
|
|
172
224
|
*/
|
|
173
225
|
export function findDependencies(tasks: Task[], taskId: string): Task[] {
|
|
174
|
-
const taskMap =
|
|
226
|
+
const { taskMap, dependenciesIndex } = buildDependencyIndices(tasks);
|
|
227
|
+
|
|
175
228
|
const visited = new Set<string>();
|
|
176
229
|
const result: Task[] = [];
|
|
177
230
|
|
|
178
231
|
function dfs(id: string) {
|
|
179
|
-
const
|
|
180
|
-
if (!
|
|
181
|
-
|
|
182
|
-
const deps = (task.dependencies ?? [])
|
|
183
|
-
.filter((d) => d.type === "blocked_by")
|
|
184
|
-
.map((d) => d.taskId);
|
|
232
|
+
const depIds = dependenciesIndex.get(id);
|
|
233
|
+
if (!depIds) return;
|
|
185
234
|
|
|
186
|
-
for (const depId of
|
|
235
|
+
for (const depId of depIds) {
|
|
187
236
|
if (!visited.has(depId)) {
|
|
188
237
|
visited.add(depId);
|
|
189
238
|
const depTask = taskMap.get(depId);
|
package/src/utils/index.ts
CHANGED
|
@@ -46,11 +46,11 @@ export {
|
|
|
46
46
|
|
|
47
47
|
// Projection utilities (token optimization)
|
|
48
48
|
export {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
formatTask,
|
|
50
|
+
formatTasks,
|
|
51
|
+
formatTasksPaginated,
|
|
52
|
+
formatInboxItem,
|
|
53
|
+
formatInboxItems,
|
|
54
54
|
formatResponse,
|
|
55
55
|
applyPagination,
|
|
56
56
|
truncate,
|