@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.
Files changed (50) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +43 -26
  3. package/dist/engine/index.d.ts +19 -1
  4. package/dist/engine/index.d.ts.map +1 -1
  5. package/dist/engine/index.js +129 -6
  6. package/dist/engine/index.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +1 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.test.js +96 -1
  12. package/dist/index.test.js.map +1 -1
  13. package/dist/store/firebase.d.ts +113 -0
  14. package/dist/store/firebase.d.ts.map +1 -0
  15. package/dist/store/firebase.js +319 -0
  16. package/dist/store/firebase.js.map +1 -0
  17. package/dist/store/firebase.test.d.ts +2 -0
  18. package/dist/store/firebase.test.d.ts.map +1 -0
  19. package/dist/store/firebase.test.js +45 -0
  20. package/dist/store/firebase.test.js.map +1 -0
  21. package/dist/store/index.d.ts +36 -8
  22. package/dist/store/index.d.ts.map +1 -1
  23. package/dist/store/index.js +78 -12
  24. package/dist/store/index.js.map +1 -1
  25. package/dist/store/sqlite.d.ts +61 -0
  26. package/dist/store/sqlite.d.ts.map +1 -0
  27. package/dist/store/sqlite.js +492 -0
  28. package/dist/store/sqlite.js.map +1 -0
  29. package/dist/store/sqlite.test.d.ts +2 -0
  30. package/dist/store/sqlite.test.d.ts.map +1 -0
  31. package/dist/store/sqlite.test.js +63 -0
  32. package/dist/store/sqlite.test.js.map +1 -0
  33. package/dist/types/index.d.ts +68 -8
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/utils/status.d.ts +14 -0
  36. package/dist/utils/status.d.ts.map +1 -0
  37. package/dist/utils/status.js +58 -0
  38. package/dist/utils/status.js.map +1 -0
  39. package/package.json +9 -1
  40. package/src/engine/index.ts +161 -8
  41. package/src/index.test.ts +113 -1
  42. package/src/index.ts +1 -0
  43. package/src/store/firebase.test.ts +59 -0
  44. package/src/store/firebase.ts +381 -0
  45. package/src/store/index.ts +113 -19
  46. package/src/store/sqlite.test.ts +78 -0
  47. package/src/store/sqlite.ts +729 -0
  48. package/src/types/index.ts +74 -9
  49. package/src/utils/status.ts +85 -0
  50. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,19 @@
1
- export type Priority = 'urgent' | 'high' | 'medium' | 'low' | 'none';
1
+ export type DefaultPriority = 'urgent' | 'high' | 'medium' | 'low' | 'none';
2
+ export type Priority = DefaultPriority | (string & {});
2
3
 
3
- export type TaskStatus = 'backlog' | 'todo' | 'in_progress' | 'in_review' | 'done' | 'canceled';
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
- sprintId?: string;
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 Sprint {
124
+ export interface Iteration {
66
125
  id: string;
67
126
  projectId: string;
68
127
  name: string;
69
128
  goal?: string;
70
- startDate: string;
71
- endDate: string;
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
- | 'sprint.started'
123
- | 'sprint.completed';
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
- sprints?: Sprint[];
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
+ }
@@ -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"}