@task-mcp/shared 1.0.4 → 1.0.7
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 +50 -26
- package/dist/algorithms/critical-path.js.map +1 -1
- package/dist/algorithms/dependency-integrity.d.ts +73 -0
- package/dist/algorithms/dependency-integrity.d.ts.map +1 -0
- package/dist/algorithms/dependency-integrity.js +189 -0
- package/dist/algorithms/dependency-integrity.js.map +1 -0
- package/dist/algorithms/index.d.ts +2 -0
- package/dist/algorithms/index.d.ts.map +1 -1
- package/dist/algorithms/index.js +2 -0
- package/dist/algorithms/index.js.map +1 -1
- package/dist/algorithms/tech-analysis.d.ts +106 -0
- package/dist/algorithms/tech-analysis.d.ts.map +1 -0
- package/dist/algorithms/tech-analysis.js +296 -0
- package/dist/algorithms/tech-analysis.js.map +1 -0
- package/dist/algorithms/tech-analysis.test.d.ts +2 -0
- package/dist/algorithms/tech-analysis.test.d.ts.map +1 -0
- package/dist/algorithms/tech-analysis.test.js +338 -0
- package/dist/algorithms/tech-analysis.test.js.map +1 -0
- package/dist/algorithms/topological-sort.d.ts.map +1 -1
- package/dist/algorithms/topological-sort.js +60 -8
- package/dist/algorithms/topological-sort.js.map +1 -1
- package/dist/schemas/inbox.d.ts +55 -0
- package/dist/schemas/inbox.d.ts.map +1 -0
- package/dist/schemas/inbox.js +25 -0
- package/dist/schemas/inbox.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +9 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/project.d.ts +154 -41
- package/dist/schemas/project.d.ts.map +1 -1
- package/dist/schemas/project.js +38 -33
- package/dist/schemas/project.js.map +1 -1
- package/dist/schemas/response-format.d.ts +80 -0
- package/dist/schemas/response-format.d.ts.map +1 -0
- package/dist/schemas/response-format.js +17 -0
- package/dist/schemas/response-format.js.map +1 -0
- package/dist/schemas/task.d.ts +592 -94
- package/dist/schemas/task.d.ts.map +1 -1
- package/dist/schemas/task.js +124 -64
- package/dist/schemas/task.js.map +1 -1
- package/dist/schemas/view.d.ts +128 -37
- package/dist/schemas/view.d.ts.map +1 -1
- package/dist/schemas/view.js +38 -24
- package/dist/schemas/view.js.map +1 -1
- package/dist/utils/date.d.ts.map +1 -1
- package/dist/utils/date.js +17 -2
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/hierarchy.d.ts +75 -0
- package/dist/utils/hierarchy.d.ts.map +1 -0
- package/dist/utils/hierarchy.js +179 -0
- package/dist/utils/hierarchy.js.map +1 -0
- package/dist/utils/id.d.ts +51 -1
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +124 -4
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/id.test.d.ts +2 -0
- package/dist/utils/id.test.d.ts.map +1 -0
- package/dist/utils/id.test.js +228 -0
- package/dist/utils/id.test.js.map +1 -0
- package/dist/utils/index.d.ts +4 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +7 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/natural-language.d.ts +45 -0
- package/dist/utils/natural-language.d.ts.map +1 -1
- package/dist/utils/natural-language.js +86 -0
- package/dist/utils/natural-language.js.map +1 -1
- package/dist/utils/projection.d.ts +65 -0
- package/dist/utils/projection.d.ts.map +1 -0
- package/dist/utils/projection.js +181 -0
- package/dist/utils/projection.js.map +1 -0
- package/dist/utils/projection.test.d.ts +2 -0
- package/dist/utils/projection.test.d.ts.map +1 -0
- package/dist/utils/projection.test.js +400 -0
- package/dist/utils/projection.test.js.map +1 -0
- package/package.json +2 -2
- package/src/algorithms/critical-path.ts +56 -24
- package/src/algorithms/dependency-integrity.ts +270 -0
- package/src/algorithms/index.ts +28 -0
- package/src/algorithms/tech-analysis.test.ts +413 -0
- package/src/algorithms/tech-analysis.ts +412 -0
- package/src/algorithms/topological-sort.ts +66 -9
- package/src/schemas/inbox.ts +32 -0
- package/src/schemas/index.ts +31 -0
- package/src/schemas/project.ts +43 -40
- package/src/schemas/response-format.ts +108 -0
- package/src/schemas/task.ts +145 -77
- package/src/schemas/view.ts +43 -33
- package/src/utils/date.ts +18 -2
- package/src/utils/hierarchy.ts +224 -0
- package/src/utils/id.test.ts +281 -0
- package/src/utils/id.ts +139 -4
- package/src/utils/index.ts +46 -2
- package/src/utils/natural-language.ts +113 -0
- package/src/utils/projection.test.ts +505 -0
- package/src/utils/projection.ts +251 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Response Format Schema
|
|
5
|
+
*
|
|
6
|
+
* Token-efficient response formats for MCP tools.
|
|
7
|
+
* Based on Anthropic's recommended patterns for reducing token usage.
|
|
8
|
+
*
|
|
9
|
+
* - concise: Minimal fields (4-6), JSON format for machine processing
|
|
10
|
+
* - standard: Common fields (7-10), balanced for most use cases
|
|
11
|
+
* - detailed: Full object, human-readable format
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Response format options
|
|
15
|
+
export const ResponseFormat = z.enum(["concise", "standard", "detailed"]);
|
|
16
|
+
export type ResponseFormat = z.infer<typeof ResponseFormat>;
|
|
17
|
+
|
|
18
|
+
// Default limits for pagination
|
|
19
|
+
export const DEFAULT_LIMIT = 20;
|
|
20
|
+
export const MAX_LIMIT = 100;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Paginated response wrapper
|
|
24
|
+
*/
|
|
25
|
+
export interface PaginatedResponse<T> {
|
|
26
|
+
items: T[];
|
|
27
|
+
total: number;
|
|
28
|
+
limit: number;
|
|
29
|
+
offset: number;
|
|
30
|
+
hasMore: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Task projection types - progressively more detailed
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// Concise: 4 essential fields (~30 tokens per task)
|
|
38
|
+
export interface TaskSummary {
|
|
39
|
+
id: string;
|
|
40
|
+
title: string;
|
|
41
|
+
status: string;
|
|
42
|
+
priority: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Standard: 8 common fields (~60 tokens per task)
|
|
46
|
+
export interface TaskPreview extends TaskSummary {
|
|
47
|
+
dueDate?: string;
|
|
48
|
+
tags?: string[];
|
|
49
|
+
contexts?: string[];
|
|
50
|
+
parentId?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Detailed: Full Task object (~200+ tokens per task)
|
|
54
|
+
// Use the full Task type from task.ts
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Project projection types
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
// Concise: 4 essential fields
|
|
61
|
+
export interface ProjectSummary {
|
|
62
|
+
id: string;
|
|
63
|
+
name: string;
|
|
64
|
+
status: string;
|
|
65
|
+
completionPercentage?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Standard: 7 common fields
|
|
69
|
+
export interface ProjectPreview extends ProjectSummary {
|
|
70
|
+
description?: string;
|
|
71
|
+
totalTasks?: number;
|
|
72
|
+
completedTasks?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Inbox projection types
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
// Concise: 3 essential fields
|
|
80
|
+
export interface InboxSummary {
|
|
81
|
+
id: string;
|
|
82
|
+
content: string;
|
|
83
|
+
status: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Standard: 5 common fields
|
|
87
|
+
export interface InboxPreview extends InboxSummary {
|
|
88
|
+
capturedAt: string;
|
|
89
|
+
tags?: string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Analysis result types - optimized for token efficiency
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
// Critical path summary (concise format)
|
|
97
|
+
export interface CriticalPathSummary {
|
|
98
|
+
totalDuration: number;
|
|
99
|
+
taskCount: number;
|
|
100
|
+
taskIds: string[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Bottleneck summary (concise format)
|
|
104
|
+
export interface BottleneckSummary {
|
|
105
|
+
taskId: string;
|
|
106
|
+
title: string;
|
|
107
|
+
blockedCount: number;
|
|
108
|
+
}
|
package/src/schemas/task.ts
CHANGED
|
@@ -1,116 +1,184 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
// Priority levels
|
|
4
|
-
export const Priority =
|
|
5
|
-
export type Priority = typeof Priority
|
|
4
|
+
export const Priority = z.enum(["critical", "high", "medium", "low"]);
|
|
5
|
+
export type Priority = z.infer<typeof Priority>;
|
|
6
6
|
|
|
7
7
|
// Task status with clear state machine
|
|
8
|
-
export const TaskStatus =
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const TaskStatus = z.enum([
|
|
9
|
+
"pending",
|
|
10
|
+
"in_progress",
|
|
11
|
+
"blocked",
|
|
12
|
+
"completed",
|
|
13
|
+
"cancelled",
|
|
14
|
+
]);
|
|
15
|
+
export type TaskStatus = z.infer<typeof TaskStatus>;
|
|
12
16
|
|
|
13
17
|
// Dependency relationship types
|
|
14
|
-
export const DependencyType =
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
export type DependencyType = typeof DependencyType.infer;
|
|
18
|
+
export const DependencyType = z.enum(["blocks", "blocked_by", "related"]);
|
|
19
|
+
export type DependencyType = z.infer<typeof DependencyType>;
|
|
18
20
|
|
|
19
21
|
// A single dependency link
|
|
20
|
-
export const Dependency =
|
|
21
|
-
taskId:
|
|
22
|
+
export const Dependency = z.object({
|
|
23
|
+
taskId: z.string(),
|
|
22
24
|
type: DependencyType,
|
|
23
|
-
|
|
25
|
+
reason: z.string().optional(),
|
|
24
26
|
});
|
|
25
|
-
export type Dependency = typeof Dependency
|
|
27
|
+
export type Dependency = z.infer<typeof Dependency>;
|
|
26
28
|
|
|
27
29
|
// Time estimation
|
|
28
|
-
export const TimeEstimate =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
export const TimeEstimate = z.object({
|
|
31
|
+
optimistic: z.number().optional(), // minutes
|
|
32
|
+
expected: z.number().optional(), // minutes
|
|
33
|
+
pessimistic: z.number().optional(), // minutes
|
|
34
|
+
confidence: z.enum(["low", "medium", "high"]).optional(),
|
|
33
35
|
});
|
|
34
|
-
export type TimeEstimate = typeof TimeEstimate
|
|
36
|
+
export type TimeEstimate = z.infer<typeof TimeEstimate>;
|
|
35
37
|
|
|
36
38
|
// Recurrence pattern
|
|
37
|
-
export const Recurrence =
|
|
38
|
-
pattern: "
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
export const Recurrence = z.object({
|
|
40
|
+
pattern: z.enum(["daily", "weekly", "monthly", "after_completion"]),
|
|
41
|
+
interval: z.number().optional(), // every N days/weeks/months
|
|
42
|
+
daysOfWeek: z.array(z.number()).optional(), // 0-6 for weekly
|
|
43
|
+
endDate: z.string().optional(),
|
|
42
44
|
});
|
|
43
|
-
export type Recurrence = typeof Recurrence
|
|
45
|
+
export type Recurrence = z.infer<typeof Recurrence>;
|
|
46
|
+
|
|
47
|
+
// Complexity factors that contribute to task difficulty
|
|
48
|
+
export const ComplexityFactor = z.enum([
|
|
49
|
+
"cross_cutting",
|
|
50
|
+
"state_management",
|
|
51
|
+
"error_handling",
|
|
52
|
+
"performance",
|
|
53
|
+
"security",
|
|
54
|
+
"external_dependency",
|
|
55
|
+
"data_migration",
|
|
56
|
+
"breaking_change",
|
|
57
|
+
"unclear_requirements",
|
|
58
|
+
"coordination",
|
|
59
|
+
]);
|
|
60
|
+
export type ComplexityFactor = z.infer<typeof ComplexityFactor>;
|
|
61
|
+
|
|
62
|
+
// Complexity analysis result (populated by Claude)
|
|
63
|
+
export const ComplexityAnalysis = z.object({
|
|
64
|
+
score: z.number().optional(), // 1-10 complexity score
|
|
65
|
+
factors: z.array(ComplexityFactor).optional(),
|
|
66
|
+
suggestedSubtasks: z.number().optional(), // 0-10 recommended subtask count
|
|
67
|
+
rationale: z.string().optional(),
|
|
68
|
+
analyzedAt: z.string().optional(),
|
|
69
|
+
});
|
|
70
|
+
export type ComplexityAnalysis = z.infer<typeof ComplexityAnalysis>;
|
|
71
|
+
|
|
72
|
+
// Tech area categories for ordering
|
|
73
|
+
export const TechArea = z.enum([
|
|
74
|
+
"schema",
|
|
75
|
+
"backend",
|
|
76
|
+
"frontend",
|
|
77
|
+
"infra",
|
|
78
|
+
"devops",
|
|
79
|
+
"test",
|
|
80
|
+
"docs",
|
|
81
|
+
"refactor",
|
|
82
|
+
]);
|
|
83
|
+
export type TechArea = z.infer<typeof TechArea>;
|
|
84
|
+
|
|
85
|
+
// Risk level for changes
|
|
86
|
+
export const RiskLevel = z.enum(["low", "medium", "high", "critical"]);
|
|
87
|
+
export type RiskLevel = z.infer<typeof RiskLevel>;
|
|
88
|
+
|
|
89
|
+
// Tech stack analysis result (populated by Claude)
|
|
90
|
+
export const TechStackAnalysis = z.object({
|
|
91
|
+
areas: z.array(TechArea).optional(),
|
|
92
|
+
hasBreakingChange: z.boolean().optional(),
|
|
93
|
+
riskLevel: RiskLevel.optional(),
|
|
94
|
+
affectedComponents: z.array(z.string()).optional(),
|
|
95
|
+
rationale: z.string().optional(),
|
|
96
|
+
analyzedAt: z.string().optional(),
|
|
97
|
+
});
|
|
98
|
+
export type TechStackAnalysis = z.infer<typeof TechStackAnalysis>;
|
|
44
99
|
|
|
45
100
|
// Core Task schema
|
|
46
|
-
export const Task =
|
|
47
|
-
id:
|
|
48
|
-
title:
|
|
49
|
-
|
|
101
|
+
export const Task = z.object({
|
|
102
|
+
id: z.string(),
|
|
103
|
+
title: z.string(),
|
|
104
|
+
description: z.string().optional(),
|
|
50
105
|
status: TaskStatus,
|
|
51
106
|
priority: Priority,
|
|
52
|
-
projectId:
|
|
107
|
+
projectId: z.string(),
|
|
108
|
+
|
|
109
|
+
// Hierarchy (subtask support)
|
|
110
|
+
parentId: z.string().nullable().optional(), // Parent task ID for subtasks (null to unlink)
|
|
111
|
+
level: z.number().optional(), // Hierarchy depth (0=root, 1=subtask, 2=sub-subtask, max 3)
|
|
53
112
|
|
|
54
113
|
// Dependencies
|
|
55
|
-
|
|
114
|
+
dependencies: z.array(Dependency).optional(),
|
|
56
115
|
|
|
57
116
|
// Time tracking
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
117
|
+
estimate: TimeEstimate.optional(),
|
|
118
|
+
actualMinutes: z.number().optional(),
|
|
119
|
+
dueDate: z.string().optional(), // ISO date string
|
|
120
|
+
startDate: z.string().optional(), // When task can start
|
|
121
|
+
startedAt: z.string().optional(),
|
|
122
|
+
completedAt: z.string().optional(),
|
|
64
123
|
|
|
65
124
|
// Organization
|
|
66
|
-
|
|
67
|
-
|
|
125
|
+
contexts: z.array(z.string()).optional(), // e.g., ["focus", "review"]
|
|
126
|
+
tags: z.array(z.string()).optional(),
|
|
68
127
|
|
|
69
128
|
// Recurrence
|
|
70
|
-
|
|
129
|
+
recurrence: Recurrence.optional(),
|
|
71
130
|
|
|
72
131
|
// Metadata
|
|
73
|
-
createdAt:
|
|
74
|
-
updatedAt:
|
|
132
|
+
createdAt: z.string(),
|
|
133
|
+
updatedAt: z.string(),
|
|
75
134
|
|
|
76
135
|
// Computed fields (populated at runtime)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
136
|
+
criticalPath: z.boolean().optional(),
|
|
137
|
+
slack: z.number().optional(), // Minutes of slack time
|
|
138
|
+
earliestStart: z.number().optional(), // Minutes from project start
|
|
139
|
+
latestStart: z.number().optional(),
|
|
140
|
+
|
|
141
|
+
// Analysis fields (populated by Claude)
|
|
142
|
+
complexity: ComplexityAnalysis.optional(),
|
|
143
|
+
techStack: TechStackAnalysis.optional(),
|
|
81
144
|
});
|
|
82
|
-
export type Task = typeof Task
|
|
145
|
+
export type Task = z.infer<typeof Task>;
|
|
83
146
|
|
|
84
147
|
// Task creation input (minimal required fields)
|
|
85
|
-
export const TaskCreateInput =
|
|
86
|
-
title:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
148
|
+
export const TaskCreateInput = z.object({
|
|
149
|
+
title: z.string(),
|
|
150
|
+
description: z.string().optional(),
|
|
151
|
+
projectId: z.string().optional(),
|
|
152
|
+
priority: Priority.optional(),
|
|
153
|
+
parentId: z.string().nullable().optional(), // Parent task ID for creating subtasks (null to unlink)
|
|
154
|
+
dependencies: z.array(Dependency).optional(),
|
|
155
|
+
estimate: TimeEstimate.optional(),
|
|
156
|
+
dueDate: z.string().optional(),
|
|
157
|
+
startDate: z.string().optional(),
|
|
158
|
+
contexts: z.array(z.string()).optional(),
|
|
159
|
+
tags: z.array(z.string()).optional(),
|
|
160
|
+
recurrence: Recurrence.optional(),
|
|
97
161
|
});
|
|
98
|
-
export type TaskCreateInput = typeof TaskCreateInput
|
|
162
|
+
export type TaskCreateInput = z.infer<typeof TaskCreateInput>;
|
|
99
163
|
|
|
100
164
|
// Task update input
|
|
101
|
-
export const TaskUpdateInput =
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
165
|
+
export const TaskUpdateInput = z.object({
|
|
166
|
+
title: z.string().optional(),
|
|
167
|
+
description: z.string().optional(),
|
|
168
|
+
status: TaskStatus.optional(),
|
|
169
|
+
priority: Priority.optional(),
|
|
170
|
+
projectId: z.string().optional(),
|
|
171
|
+
parentId: z.string().nullable().optional(), // Parent task ID for moving task in hierarchy (null to unlink)
|
|
172
|
+
dependencies: z.array(Dependency).optional(),
|
|
173
|
+
estimate: TimeEstimate.optional(),
|
|
174
|
+
actualMinutes: z.number().optional(),
|
|
175
|
+
dueDate: z.string().optional(),
|
|
176
|
+
startDate: z.string().optional(),
|
|
177
|
+
contexts: z.array(z.string()).optional(),
|
|
178
|
+
tags: z.array(z.string()).optional(),
|
|
179
|
+
recurrence: Recurrence.optional(),
|
|
180
|
+
// Analysis fields
|
|
181
|
+
complexity: ComplexityAnalysis.optional(),
|
|
182
|
+
techStack: TechStackAnalysis.optional(),
|
|
115
183
|
});
|
|
116
|
-
export type TaskUpdateInput = typeof TaskUpdateInput
|
|
184
|
+
export type TaskUpdateInput = z.infer<typeof TaskUpdateInput>;
|
package/src/schemas/view.ts
CHANGED
|
@@ -1,46 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
import { Priority, TaskStatus } from "./task.js";
|
|
3
3
|
|
|
4
4
|
// Smart View filter
|
|
5
|
-
export const SmartViewFilter =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
export const SmartViewFilter = z.object({
|
|
6
|
+
statuses: z.array(TaskStatus).optional(),
|
|
7
|
+
priorities: z.array(Priority).optional(),
|
|
8
|
+
contexts: z.array(z.string()).optional(),
|
|
9
|
+
tags: z.array(z.string()).optional(),
|
|
10
|
+
projectIds: z.array(z.string()).optional(),
|
|
11
|
+
dueBefore: z.string().optional(),
|
|
12
|
+
dueAfter: z.string().optional(),
|
|
13
|
+
isBlocked: z.boolean().optional(),
|
|
14
|
+
isCriticalPath: z.boolean().optional(),
|
|
15
|
+
hasNoDependencies: z.boolean().optional(),
|
|
16
|
+
search: z.string().optional(), // Search in title/description
|
|
17
17
|
});
|
|
18
|
-
export type SmartViewFilter = typeof SmartViewFilter
|
|
18
|
+
export type SmartViewFilter = z.infer<typeof SmartViewFilter>;
|
|
19
19
|
|
|
20
20
|
// Sort options
|
|
21
|
-
export const SortField =
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
export const SortField = z.enum([
|
|
22
|
+
"priority",
|
|
23
|
+
"dueDate",
|
|
24
|
+
"createdAt",
|
|
25
|
+
"criticalPath",
|
|
26
|
+
"slack",
|
|
27
|
+
"title",
|
|
28
|
+
]);
|
|
29
|
+
export type SortField = z.infer<typeof SortField>;
|
|
25
30
|
|
|
26
|
-
export const SortOrder =
|
|
27
|
-
export type SortOrder = typeof SortOrder
|
|
31
|
+
export const SortOrder = z.enum(["asc", "desc"]);
|
|
32
|
+
export type SortOrder = z.infer<typeof SortOrder>;
|
|
28
33
|
|
|
29
34
|
// Smart View definition
|
|
30
|
-
export const SmartView =
|
|
31
|
-
id:
|
|
32
|
-
name:
|
|
33
|
-
|
|
35
|
+
export const SmartView = z.object({
|
|
36
|
+
id: z.string(),
|
|
37
|
+
name: z.string(),
|
|
38
|
+
description: z.string().optional(),
|
|
34
39
|
filter: SmartViewFilter,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
createdAt:
|
|
38
|
-
updatedAt:
|
|
40
|
+
sortBy: SortField.optional(),
|
|
41
|
+
sortOrder: SortOrder.optional(),
|
|
42
|
+
createdAt: z.string(),
|
|
43
|
+
updatedAt: z.string(),
|
|
39
44
|
});
|
|
40
|
-
export type SmartView = typeof SmartView
|
|
45
|
+
export type SmartView = z.infer<typeof SmartView>;
|
|
41
46
|
|
|
42
47
|
// Built-in view names
|
|
43
|
-
export const BuiltInView =
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
export const BuiltInView = z.enum([
|
|
49
|
+
"today",
|
|
50
|
+
"this_week",
|
|
51
|
+
"blocked",
|
|
52
|
+
"critical_path",
|
|
53
|
+
"quick_wins",
|
|
54
|
+
"all",
|
|
55
|
+
]);
|
|
56
|
+
export type BuiltInView = z.infer<typeof BuiltInView>;
|
package/src/utils/date.ts
CHANGED
|
@@ -67,10 +67,26 @@ export function parseRelativeDate(input: string): Date | null {
|
|
|
67
67
|
return d;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
// Try parsing as
|
|
70
|
+
// Try parsing as YYYY-MM-DD format (local timezone, no UTC shift)
|
|
71
|
+
const isoDateMatch = input.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
72
|
+
if (isoDateMatch) {
|
|
73
|
+
const [, yearStr, monthStr, dayStr] = isoDateMatch;
|
|
74
|
+
const year = parseInt(yearStr!, 10);
|
|
75
|
+
const month = parseInt(monthStr!, 10) - 1; // 0-indexed
|
|
76
|
+
const day = parseInt(dayStr!, 10);
|
|
77
|
+
const d = new Date(year, month, day);
|
|
78
|
+
// Validate the date is valid (e.g., not Feb 30)
|
|
79
|
+
if (d.getFullYear() === year && d.getMonth() === month && d.getDate() === day) {
|
|
80
|
+
return d;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Try parsing other date formats (fallback)
|
|
71
85
|
const parsed = new Date(input);
|
|
72
86
|
if (!isNaN(parsed.getTime())) {
|
|
73
|
-
|
|
87
|
+
// For non-YYYY-MM-DD formats, normalize to local midnight
|
|
88
|
+
const d = new Date(parsed.getFullYear(), parsed.getMonth(), parsed.getDate());
|
|
89
|
+
return d;
|
|
74
90
|
}
|
|
75
91
|
|
|
76
92
|
return null;
|