@critical-path/core 0.1.2 → 0.2.1
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/CHANGELOG.md +19 -0
- package/README.md +43 -26
- package/dist/engine/index.d.ts +19 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +129 -6
- package/dist/engine/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +96 -1
- package/dist/index.test.js.map +1 -1
- package/dist/store/firebase.d.ts +113 -0
- package/dist/store/firebase.d.ts.map +1 -0
- package/dist/store/firebase.js +319 -0
- package/dist/store/firebase.js.map +1 -0
- package/dist/store/firebase.test.d.ts +2 -0
- package/dist/store/firebase.test.d.ts.map +1 -0
- package/dist/store/firebase.test.js +45 -0
- package/dist/store/firebase.test.js.map +1 -0
- package/dist/store/index.d.ts +36 -8
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +78 -12
- package/dist/store/index.js.map +1 -1
- package/dist/store/sqlite.d.ts +61 -0
- package/dist/store/sqlite.d.ts.map +1 -0
- package/dist/store/sqlite.js +492 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/sqlite.test.d.ts +2 -0
- package/dist/store/sqlite.test.d.ts.map +1 -0
- package/dist/store/sqlite.test.js +63 -0
- package/dist/store/sqlite.test.js.map +1 -0
- package/dist/types/index.d.ts +68 -8
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/status.d.ts +14 -0
- package/dist/utils/status.d.ts.map +1 -0
- package/dist/utils/status.js +58 -0
- package/dist/utils/status.js.map +1 -0
- package/package.json +9 -1
- package/src/engine/index.ts +161 -8
- package/src/index.test.ts +113 -1
- package/src/index.ts +1 -0
- package/src/store/firebase.test.ts +59 -0
- package/src/store/firebase.ts +381 -0
- package/src/store/index.ts +113 -19
- package/src/store/sqlite.test.ts +78 -0
- package/src/store/sqlite.ts +729 -0
- package/src/types/index.ts +74 -9
- package/src/utils/status.ts +85 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/types/index.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type DefaultPriority = 'urgent' | 'high' | 'medium' | 'low' | 'none';
|
|
2
|
+
export type Priority = DefaultPriority | (string & {});
|
|
2
3
|
|
|
3
|
-
export type
|
|
4
|
+
export type DefaultTaskStatus = 'backlog' | 'todo' | 'in_progress' | 'in_review' | 'done' | 'canceled';
|
|
5
|
+
export type TaskStatus = DefaultTaskStatus | (string & {});
|
|
6
|
+
|
|
7
|
+
export type CompletionState = 'done' | 'not_done';
|
|
8
|
+
export type ExecutionState = 'active' | 'inactive';
|
|
9
|
+
|
|
10
|
+
export interface StatusDefinition {
|
|
11
|
+
key: string;
|
|
12
|
+
label: string;
|
|
13
|
+
completionState: CompletionState;
|
|
14
|
+
executionState: ExecutionState;
|
|
15
|
+
isCancelled?: boolean;
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
export type Role = 'admin' | 'project_manager' | 'contributor' | 'viewer';
|
|
6
19
|
|
|
@@ -13,6 +26,16 @@ export interface User {
|
|
|
13
26
|
createdAt: string;
|
|
14
27
|
}
|
|
15
28
|
|
|
29
|
+
export interface Team {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
leaderId?: string;
|
|
34
|
+
memberIds: string[];
|
|
35
|
+
createdAt: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
export interface CustomFieldDefinition {
|
|
17
40
|
id: string;
|
|
18
41
|
key: string;
|
|
@@ -30,11 +53,26 @@ export interface Project {
|
|
|
30
53
|
description?: string;
|
|
31
54
|
ownerId?: string;
|
|
32
55
|
members?: string[]; // user IDs
|
|
56
|
+
teamIds?: string[]; // team IDs
|
|
57
|
+
statusDefinitions?: StatusDefinition[];
|
|
58
|
+
priorityDefinitions?: Array<{ key: string; label: string; level?: number }>;
|
|
33
59
|
customFieldDefinitions?: CustomFieldDefinition[];
|
|
34
60
|
createdAt: string;
|
|
35
61
|
updatedAt: string;
|
|
36
62
|
}
|
|
37
63
|
|
|
64
|
+
export interface TaskContainer {
|
|
65
|
+
id: string;
|
|
66
|
+
projectId: string;
|
|
67
|
+
name: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
parentId?: string; // nested container hierarchy (e.g., folder -> epic -> group)
|
|
70
|
+
type?: 'epic' | 'group' | 'section' | 'folder' | string;
|
|
71
|
+
color?: string;
|
|
72
|
+
createdAt: string;
|
|
73
|
+
updatedAt: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
38
76
|
export interface TaskDependency {
|
|
39
77
|
id: string;
|
|
40
78
|
taskId: string;
|
|
@@ -42,6 +80,13 @@ export interface TaskDependency {
|
|
|
42
80
|
type: 'blocking' | 'blocked_by' | 'relates_to';
|
|
43
81
|
}
|
|
44
82
|
|
|
83
|
+
export interface TaskDependencyGraph {
|
|
84
|
+
taskId: string;
|
|
85
|
+
upstreamTasks: Task[]; // tasks that this task depends on
|
|
86
|
+
downstreamTasks: Task[]; // tasks that depend on this task
|
|
87
|
+
dependencies: TaskDependency[];
|
|
88
|
+
}
|
|
89
|
+
|
|
45
90
|
export interface Task {
|
|
46
91
|
id: string;
|
|
47
92
|
projectId: string;
|
|
@@ -51,10 +96,24 @@ export interface Task {
|
|
|
51
96
|
priority: Priority;
|
|
52
97
|
assigneeId?: string;
|
|
53
98
|
reporterId?: string;
|
|
54
|
-
|
|
99
|
+
reviewerId?: string;
|
|
100
|
+
iterationId?: string;
|
|
101
|
+
teamId?: string;
|
|
102
|
+
containerId?: string;
|
|
103
|
+
plannedStartDate?: string;
|
|
104
|
+
actualStartDate?: string;
|
|
105
|
+
actualEndDate?: string;
|
|
55
106
|
dueDate?: string;
|
|
107
|
+
// Duration & Effort (in hours and/or minutes)
|
|
56
108
|
estimatedHours?: number;
|
|
57
109
|
loggedHours?: number;
|
|
110
|
+
actualHours?: number;
|
|
111
|
+
billableHours?: number;
|
|
112
|
+
estimatedDurationMinutes?: number;
|
|
113
|
+
actualDurationMinutes?: number;
|
|
114
|
+
billableDurationMinutes?: number;
|
|
115
|
+
// Progress (0 to 100 percentage)
|
|
116
|
+
progress?: number;
|
|
58
117
|
tags?: string[];
|
|
59
118
|
customFields?: Record<string, unknown>;
|
|
60
119
|
parentId?: string; // Subtask support
|
|
@@ -62,13 +121,14 @@ export interface Task {
|
|
|
62
121
|
updatedAt: string;
|
|
63
122
|
}
|
|
64
123
|
|
|
65
|
-
export interface
|
|
124
|
+
export interface Iteration {
|
|
66
125
|
id: string;
|
|
67
126
|
projectId: string;
|
|
68
127
|
name: string;
|
|
69
128
|
goal?: string;
|
|
70
|
-
|
|
71
|
-
|
|
129
|
+
type?: 'sprint' | 'cycle' | 'milestone' | string;
|
|
130
|
+
startDate?: string;
|
|
131
|
+
endDate?: string;
|
|
72
132
|
status: 'planning' | 'active' | 'completed';
|
|
73
133
|
createdAt: string;
|
|
74
134
|
}
|
|
@@ -87,6 +147,7 @@ export interface TimeEntry {
|
|
|
87
147
|
taskId: string;
|
|
88
148
|
userId: string;
|
|
89
149
|
hours: number;
|
|
150
|
+
isBillable?: boolean;
|
|
90
151
|
description?: string;
|
|
91
152
|
loggedAt: string;
|
|
92
153
|
}
|
|
@@ -119,8 +180,10 @@ export type WebhookEvent =
|
|
|
119
180
|
| 'task.deleted'
|
|
120
181
|
| 'task.status_changed'
|
|
121
182
|
| 'comment.created'
|
|
122
|
-
| '
|
|
123
|
-
| '
|
|
183
|
+
| 'iteration.started'
|
|
184
|
+
| 'iteration.completed'
|
|
185
|
+
| 'team.created'
|
|
186
|
+
| 'container.created';
|
|
124
187
|
|
|
125
188
|
export interface PluginHooks {
|
|
126
189
|
beforeTaskCreate?: (task: Partial<Task>) => Promise<Partial<Task>> | Partial<Task>;
|
|
@@ -149,6 +212,8 @@ export interface CriticalPathConfig {
|
|
|
149
212
|
projects?: Project[];
|
|
150
213
|
tasks?: Task[];
|
|
151
214
|
users?: User[];
|
|
152
|
-
|
|
215
|
+
iterations?: Iteration[];
|
|
216
|
+
teams?: Team[];
|
|
217
|
+
containers?: TaskContainer[];
|
|
153
218
|
};
|
|
154
219
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Task,
|
|
3
|
+
StatusDefinition,
|
|
4
|
+
CompletionState,
|
|
5
|
+
ExecutionState
|
|
6
|
+
} from '../types/index.js';
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_STATUS_DEFINITIONS: Record<string, StatusDefinition> = {
|
|
9
|
+
backlog: { key: 'backlog', label: 'Backlog', completionState: 'not_done', executionState: 'inactive' },
|
|
10
|
+
todo: { key: 'todo', label: 'To Do', completionState: 'not_done', executionState: 'inactive' },
|
|
11
|
+
in_progress: { key: 'in_progress', label: 'In Progress', completionState: 'not_done', executionState: 'active' },
|
|
12
|
+
in_review: { key: 'in_review', label: 'In Review', completionState: 'not_done', executionState: 'active' },
|
|
13
|
+
done: { key: 'done', label: 'Done', completionState: 'done', executionState: 'inactive' },
|
|
14
|
+
canceled: { key: 'canceled', label: 'Canceled', completionState: 'done', executionState: 'inactive', isCancelled: true }
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export interface TaskLifecycleState {
|
|
18
|
+
completionState: CompletionState;
|
|
19
|
+
executionState: ExecutionState;
|
|
20
|
+
isDone: boolean;
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
isCancelled: boolean;
|
|
23
|
+
isOverdue: boolean;
|
|
24
|
+
isUpcoming: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function resolveStatusDefinition(
|
|
28
|
+
statusKey: string,
|
|
29
|
+
customDefinitions?: StatusDefinition[]
|
|
30
|
+
): StatusDefinition {
|
|
31
|
+
if (customDefinitions) {
|
|
32
|
+
const found = customDefinitions.find((def) => def.key === statusKey);
|
|
33
|
+
if (found) return found;
|
|
34
|
+
}
|
|
35
|
+
if (DEFAULT_STATUS_DEFINITIONS[statusKey]) {
|
|
36
|
+
return DEFAULT_STATUS_DEFINITIONS[statusKey];
|
|
37
|
+
}
|
|
38
|
+
// Fallback heuristic for unknown custom statuses:
|
|
39
|
+
const isDoneKey = ['done', 'completed', 'finished', 'closed', 'canceled', 'cancelled'].includes(statusKey.toLowerCase());
|
|
40
|
+
const isActiveKey = ['in_progress', 'active', 'working', 'in_review', 'review'].includes(statusKey.toLowerCase());
|
|
41
|
+
return {
|
|
42
|
+
key: statusKey,
|
|
43
|
+
label: statusKey,
|
|
44
|
+
completionState: isDoneKey ? 'done' : 'not_done',
|
|
45
|
+
executionState: isActiveKey ? 'active' : 'inactive',
|
|
46
|
+
isCancelled: statusKey.toLowerCase().includes('cancel')
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function deriveTaskLifecycleState(
|
|
51
|
+
task: Task,
|
|
52
|
+
customDefinitions?: StatusDefinition[],
|
|
53
|
+
referenceDate: Date = new Date()
|
|
54
|
+
): TaskLifecycleState {
|
|
55
|
+
const def = resolveStatusDefinition(task.status, customDefinitions);
|
|
56
|
+
const isDone = def.completionState === 'done';
|
|
57
|
+
const isActive = def.executionState === 'active';
|
|
58
|
+
const isCancelled = Boolean(def.isCancelled);
|
|
59
|
+
|
|
60
|
+
let isOverdue = false;
|
|
61
|
+
if (!isDone && task.dueDate) {
|
|
62
|
+
const due = new Date(task.dueDate);
|
|
63
|
+
if (!isNaN(due.getTime()) && due < referenceDate) {
|
|
64
|
+
isOverdue = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let isUpcoming = false;
|
|
69
|
+
if (!isDone && !isActive && task.plannedStartDate) {
|
|
70
|
+
const plannedStart = new Date(task.plannedStartDate);
|
|
71
|
+
if (!isNaN(plannedStart.getTime()) && plannedStart > referenceDate) {
|
|
72
|
+
isUpcoming = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
completionState: def.completionState,
|
|
78
|
+
executionState: def.executionState,
|
|
79
|
+
isDone,
|
|
80
|
+
isActive,
|
|
81
|
+
isCancelled,
|
|
82
|
+
isOverdue,
|
|
83
|
+
isUpcoming
|
|
84
|
+
};
|
|
85
|
+
}
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/index.test.ts","./src/index.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/store/index.ts","./src/types/index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/index.test.ts","./src/index.ts","./src/engine/index.ts","./src/plugins/index.ts","./src/store/firebase.test.ts","./src/store/firebase.ts","./src/store/index.ts","./src/store/sqlite.test.ts","./src/store/sqlite.ts","./src/types/index.ts","./src/utils/status.ts"],"version":"5.9.3"}
|